Skip to content

Commit 45c72cd

Browse files
piastryMiklos Szeredi
authored andcommitted
fuse: fix stat call on 32 bit platforms
Now we store attr->ino at inode->i_ino, return attr->ino at the first time and then return inode->i_ino if the attribute timeout isn't expired. That's wrong on 32 bit platforms because attr->ino is 64 bit and inode->i_ino is 32 bit in this case. Fix this by saving 64 bit ino in fuse_inode structure and returning it every time we call getattr. Also squash attr->ino into inode->i_ino explicitly. Signed-off-by: Pavel Shilovsky <[email protected]> Signed-off-by: Miklos Szeredi <[email protected]>
1 parent 519c604 commit 45c72cd

File tree

3 files changed

+20
-1
lines changed

3 files changed

+20
-1
lines changed

fs/fuse/dir.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -863,6 +863,7 @@ int fuse_update_attributes(struct inode *inode, struct kstat *stat,
863863
if (stat) {
864864
generic_fillattr(inode, stat);
865865
stat->mode = fi->orig_i_mode;
866+
stat->ino = fi->orig_ino;
866867
}
867868
}
868869

fs/fuse/fuse_i.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@ struct fuse_inode {
8282
preserve the original mode */
8383
umode_t orig_i_mode;
8484

85+
/** 64 bit inode number */
86+
u64 orig_ino;
87+
8588
/** Version of last attribute change */
8689
u64 attr_version;
8790

fs/fuse/inode.c

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ static struct inode *fuse_alloc_inode(struct super_block *sb)
9191
fi->nlookup = 0;
9292
fi->attr_version = 0;
9393
fi->writectr = 0;
94+
fi->orig_ino = 0;
9495
INIT_LIST_HEAD(&fi->write_files);
9596
INIT_LIST_HEAD(&fi->queued_writes);
9697
INIT_LIST_HEAD(&fi->writepages);
@@ -139,6 +140,18 @@ static int fuse_remount_fs(struct super_block *sb, int *flags, char *data)
139140
return 0;
140141
}
141142

143+
/*
144+
* ino_t is 32-bits on 32-bit arch. We have to squash the 64-bit value down
145+
* so that it will fit.
146+
*/
147+
static ino_t fuse_squash_ino(u64 ino64)
148+
{
149+
ino_t ino = (ino_t) ino64;
150+
if (sizeof(ino_t) < sizeof(u64))
151+
ino ^= ino64 >> (sizeof(u64) - sizeof(ino_t)) * 8;
152+
return ino;
153+
}
154+
142155
void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr,
143156
u64 attr_valid)
144157
{
@@ -148,7 +161,7 @@ void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr,
148161
fi->attr_version = ++fc->attr_version;
149162
fi->i_time = attr_valid;
150163

151-
inode->i_ino = attr->ino;
164+
inode->i_ino = fuse_squash_ino(attr->ino);
152165
inode->i_mode = (inode->i_mode & S_IFMT) | (attr->mode & 07777);
153166
set_nlink(inode, attr->nlink);
154167
inode->i_uid = attr->uid;
@@ -174,6 +187,8 @@ void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr,
174187
fi->orig_i_mode = inode->i_mode;
175188
if (!(fc->flags & FUSE_DEFAULT_PERMISSIONS))
176189
inode->i_mode &= ~S_ISVTX;
190+
191+
fi->orig_ino = attr->ino;
177192
}
178193

179194
void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr,

0 commit comments

Comments
 (0)