aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPavel Shilovsky <piastry@etersoft.ru>2012-05-10 11:49:38 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-06-17 14:23:12 -0400
commit6140710c5dba509a20b26dfe38b58f40baf2a2c8 (patch)
tree36b64faaa0e80279bdd5bdc6c0b6f89e7a2db2ae
parent33b3689af55ddec6efd608bd82f09a83e4e4042c (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.c1
-rw-r--r--fs/fuse/fuse_i.h3
-rw-r--r--fs/fuse/inode.c17
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 */
148static 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
143void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr, 156void 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
180void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr, 195void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr,