Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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 <piastry@etersoft.ru>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>

authored by

Pavel Shilovsky and committed by
Miklos Szeredi
45c72cd7 519c6040

+20 -1
+1
fs/fuse/dir.c
··· 863 863 if (stat) { 864 864 generic_fillattr(inode, stat); 865 865 stat->mode = fi->orig_i_mode; 866 + stat->ino = fi->orig_ino; 866 867 } 867 868 } 868 869
+3
fs/fuse/fuse_i.h
··· 82 82 preserve the original mode */ 83 83 umode_t orig_i_mode; 84 84 85 + /** 64 bit inode number */ 86 + u64 orig_ino; 87 + 85 88 /** Version of last attribute change */ 86 89 u64 attr_version; 87 90
+16 -1
fs/fuse/inode.c
··· 91 91 fi->nlookup = 0; 92 92 fi->attr_version = 0; 93 93 fi->writectr = 0; 94 + fi->orig_ino = 0; 94 95 INIT_LIST_HEAD(&fi->write_files); 95 96 INIT_LIST_HEAD(&fi->queued_writes); 96 97 INIT_LIST_HEAD(&fi->writepages); ··· 140 139 return 0; 141 140 } 142 141 142 + /* 143 + * ino_t is 32-bits on 32-bit arch. We have to squash the 64-bit value down 144 + * so that it will fit. 145 + */ 146 + static ino_t fuse_squash_ino(u64 ino64) 147 + { 148 + ino_t ino = (ino_t) ino64; 149 + if (sizeof(ino_t) < sizeof(u64)) 150 + ino ^= ino64 >> (sizeof(u64) - sizeof(ino_t)) * 8; 151 + return ino; 152 + } 153 + 143 154 void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr, 144 155 u64 attr_valid) 145 156 { ··· 161 148 fi->attr_version = ++fc->attr_version; 162 149 fi->i_time = attr_valid; 163 150 164 - inode->i_ino = attr->ino; 151 + inode->i_ino = fuse_squash_ino(attr->ino); 165 152 inode->i_mode = (inode->i_mode & S_IFMT) | (attr->mode & 07777); 166 153 set_nlink(inode, attr->nlink); 167 154 inode->i_uid = attr->uid; ··· 187 174 fi->orig_i_mode = inode->i_mode; 188 175 if (!(fc->flags & FUSE_DEFAULT_PERMISSIONS)) 189 176 inode->i_mode &= ~S_ISVTX; 177 + 178 + fi->orig_ino = attr->ino; 190 179 } 191 180 192 181 void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr,