diff options
author | Pavel Shilovsky <piastry@etersoft.ru> | 2012-05-10 11:49:38 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-06-17 14:23:12 -0400 |
commit | 6140710c5dba509a20b26dfe38b58f40baf2a2c8 (patch) | |
tree | 36b64faaa0e80279bdd5bdc6c0b6f89e7a2db2ae | |
parent | 33b3689af55ddec6efd608bd82f09a83e4e4042c (diff) |
fuse: fix stat call on 32 bit platforms
commit 45c72cd73c788dd18c8113d4a404d6b4a01decf1 upstream.
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 <piastry@etersoft.ru>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | fs/fuse/dir.c | 1 | ||||
-rw-r--r-- | fs/fuse/fuse_i.h | 3 | ||||
-rw-r--r-- | fs/fuse/inode.c | 17 |
3 files changed, 20 insertions, 1 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index d5016071459..c04a025c677 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c | |||
@@ -858,6 +858,7 @@ int fuse_update_attributes(struct inode *inode, struct kstat *stat, | |||
858 | if (stat) { | 858 | if (stat) { |
859 | generic_fillattr(inode, stat); | 859 | generic_fillattr(inode, stat); |
860 | stat->mode = fi->orig_i_mode; | 860 | stat->mode = fi->orig_i_mode; |
861 | stat->ino = fi->orig_ino; | ||
861 | } | 862 | } |
862 | } | 863 | } |
863 | 864 | ||
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index b788becada7..f6215501097 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h | |||
@@ -82,6 +82,9 @@ struct fuse_inode { | |||
82 | preserve the original mode */ | 82 | preserve the original mode */ |
83 | mode_t orig_i_mode; | 83 | mode_t orig_i_mode; |
84 | 84 | ||
85 | /** 64 bit inode number */ | ||
86 | u64 orig_ino; | ||
87 | |||
85 | /** Version of last attribute change */ | 88 | /** Version of last attribute change */ |
86 | u64 attr_version; | 89 | u64 attr_version; |
87 | 90 | ||
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 38f84cd48b6..69a1e0f04f4 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c | |||
@@ -91,6 +91,7 @@ static struct inode *fuse_alloc_inode(struct super_block *sb) | |||
91 | fi->nlookup = 0; | 91 | fi->nlookup = 0; |
92 | fi->attr_version = 0; | 92 | fi->attr_version = 0; |
93 | fi->writectr = 0; | 93 | fi->writectr = 0; |
94 | fi->orig_ino = 0; | ||
94 | INIT_LIST_HEAD(&fi->write_files); | 95 | INIT_LIST_HEAD(&fi->write_files); |
95 | INIT_LIST_HEAD(&fi->queued_writes); | 96 | INIT_LIST_HEAD(&fi->queued_writes); |
96 | INIT_LIST_HEAD(&fi->writepages); | 97 | INIT_LIST_HEAD(&fi->writepages); |
@@ -140,6 +141,18 @@ static int fuse_remount_fs(struct super_block *sb, int *flags, char *data) | |||
140 | return 0; | 141 | return 0; |
141 | } | 142 | } |
142 | 143 | ||
144 | /* | ||
145 | * ino_t is 32-bits on 32-bit arch. We have to squash the 64-bit value down | ||
146 | * so that it will fit. | ||
147 | */ | ||
148 | static ino_t fuse_squash_ino(u64 ino64) | ||
149 | { | ||
150 | ino_t ino = (ino_t) ino64; | ||
151 | if (sizeof(ino_t) < sizeof(u64)) | ||
152 | ino ^= ino64 >> (sizeof(u64) - sizeof(ino_t)) * 8; | ||
153 | return ino; | ||
154 | } | ||
155 | |||
143 | void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr, | 156 | void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr, |
144 | u64 attr_valid) | 157 | u64 attr_valid) |
145 | { | 158 | { |
@@ -149,7 +162,7 @@ void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr, | |||
149 | fi->attr_version = ++fc->attr_version; | 162 | fi->attr_version = ++fc->attr_version; |
150 | fi->i_time = attr_valid; | 163 | fi->i_time = attr_valid; |
151 | 164 | ||
152 | inode->i_ino = attr->ino; | 165 | inode->i_ino = fuse_squash_ino(attr->ino); |
153 | inode->i_mode = (inode->i_mode & S_IFMT) | (attr->mode & 07777); | 166 | inode->i_mode = (inode->i_mode & S_IFMT) | (attr->mode & 07777); |
154 | inode->i_nlink = attr->nlink; | 167 | inode->i_nlink = attr->nlink; |
155 | inode->i_uid = attr->uid; | 168 | inode->i_uid = attr->uid; |
@@ -175,6 +188,8 @@ void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr, | |||
175 | fi->orig_i_mode = inode->i_mode; | 188 | fi->orig_i_mode = inode->i_mode; |
176 | if (!(fc->flags & FUSE_DEFAULT_PERMISSIONS)) | 189 | if (!(fc->flags & FUSE_DEFAULT_PERMISSIONS)) |
177 | inode->i_mode &= ~S_ISVTX; | 190 | inode->i_mode &= ~S_ISVTX; |
191 | |||
192 | fi->orig_ino = attr->ino; | ||
178 | } | 193 | } |
179 | 194 | ||
180 | void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr, | 195 | void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr, |