aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2006-10-03 04:13:46 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-10-03 11:03:40 -0400
commitafefdbb28a0a2af689926c30b94a14aea6036719 (patch)
tree6ee500575cac928cd90045bcf5b691cf2b8daa09
parent1d32849b14bc8792e6f35ab27dd990d74b16126c (diff)
[PATCH] VFS: Make filldir_t and struct kstat deal in 64-bit inode numbers
These patches make the kernel pass 64-bit inode numbers internally when communicating to userspace, even on a 32-bit system. They are required because some filesystems have intrinsic 64-bit inode numbers: NFS3+ and XFS for example. The 64-bit inode numbers are then propagated to userspace automatically where the arch supports it. Problems have been seen with userspace (eg: ld.so) using the 64-bit inode number returned by stat64() or getdents64() to differentiate files, and failing because the 64-bit inode number space was compressed to 32-bits, and so overlaps occur. This patch: Make filldir_t take a 64-bit inode number and struct kstat carry a 64-bit inode number so that 64-bit inode numbers can be passed back to userspace. The stat functions then returns the full 64-bit inode number where available and where possible. If it is not possible to represent the inode number supplied by the filesystem in the field provided by userspace, then error EOVERFLOW will be issued. Similarly, the getdents/readdir functions now pass the full 64-bit inode number to userspace where possible, returning EOVERFLOW instead when a directory entry is encountered that can't be properly represented. Note that this means that some inodes will not be stat'able on a 32-bit system with old libraries where they were before - but it does mean that there will be no ambiguity over what a 32-bit inode number refers to. Note similarly that directory scans may be cut short with an error on a 32-bit system with old libraries where the scan would work before for the same reasons. It is judged unlikely that this situation will occur because modern glibc uses 64-bit capable versions of stat and getdents class functions exclusively, and that older systems are unlikely to encounter unrepresentable inode numbers anyway. [akpm: alpha build fix] Signed-off-by: David Howells <dhowells@redhat.com> Cc: Trond Myklebust <trond.myklebust@fys.uio.no> Cc: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--arch/alpha/kernel/osf_sys.c8
-rw-r--r--arch/ia64/ia32/sys_ia32.c23
-rw-r--r--arch/mips/kernel/linux32.c2
-rw-r--r--arch/mips/kernel/sysirix.c10
-rw-r--r--arch/parisc/hpux/fs.c6
-rw-r--r--arch/parisc/kernel/sys_parisc32.c19
-rw-r--r--arch/powerpc/kernel/sys_ppc32.c15
-rw-r--r--arch/s390/kernel/compat_linux.c5
-rw-r--r--arch/sparc/kernel/sys_sunos.c16
-rw-r--r--arch/sparc64/kernel/sys_sparc32.c5
-rw-r--r--arch/sparc64/kernel/sys_sunos32.c12
-rw-r--r--arch/sparc64/solaris/fs.c7
-rw-r--r--arch/x86_64/ia32/sys_ia32.c7
-rw-r--r--fs/afs/dir.c4
-rw-r--r--fs/compat.c18
-rw-r--r--fs/exportfs/expfs.c2
-rw-r--r--fs/fat/dir.c2
-rw-r--r--fs/nfsd/nfs4recover.c2
-rw-r--r--fs/readdir.c18
-rw-r--r--fs/reiserfs/xattr.c6
-rw-r--r--fs/stat.c6
-rw-r--r--include/linux/fs.h2
-rw-r--r--include/linux/stat.h2
23 files changed, 152 insertions, 45 deletions
diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c
index 8a31fc1bfb15..ad6173651995 100644
--- a/arch/alpha/kernel/osf_sys.c
+++ b/arch/alpha/kernel/osf_sys.c
@@ -111,22 +111,26 @@ struct osf_dirent_callback {
111 111
112static int 112static int
113osf_filldir(void *__buf, const char *name, int namlen, loff_t offset, 113osf_filldir(void *__buf, const char *name, int namlen, loff_t offset,
114 ino_t ino, unsigned int d_type) 114 u64 ino, unsigned int d_type)
115{ 115{
116 struct osf_dirent __user *dirent; 116 struct osf_dirent __user *dirent;
117 struct osf_dirent_callback *buf = (struct osf_dirent_callback *) __buf; 117 struct osf_dirent_callback *buf = (struct osf_dirent_callback *) __buf;
118 unsigned int reclen = ROUND_UP(NAME_OFFSET + namlen + 1); 118 unsigned int reclen = ROUND_UP(NAME_OFFSET + namlen + 1);
119 unsigned int d_ino;
119 120
120 buf->error = -EINVAL; /* only used if we fail */ 121 buf->error = -EINVAL; /* only used if we fail */
121 if (reclen > buf->count) 122 if (reclen > buf->count)
122 return -EINVAL; 123 return -EINVAL;
124 d_ino = ino;
125 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
126 return -EOVERFLOW;
123 if (buf->basep) { 127 if (buf->basep) {
124 if (put_user(offset, buf->basep)) 128 if (put_user(offset, buf->basep))
125 return -EFAULT; 129 return -EFAULT;
126 buf->basep = NULL; 130 buf->basep = NULL;
127 } 131 }
128 dirent = buf->dirent; 132 dirent = buf->dirent;
129 put_user(ino, &dirent->d_ino); 133 put_user(d_ino, &dirent->d_ino);
130 put_user(namlen, &dirent->d_namlen); 134 put_user(namlen, &dirent->d_namlen);
131 put_user(reclen, &dirent->d_reclen); 135 put_user(reclen, &dirent->d_reclen);
132 if (copy_to_user(dirent->d_name, name, namlen) || 136 if (copy_to_user(dirent->d_name, name, namlen) ||
diff --git a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c
index bddbd22706ed..9d6a3f210148 100644
--- a/arch/ia64/ia32/sys_ia32.c
+++ b/arch/ia64/ia32/sys_ia32.c
@@ -125,6 +125,7 @@ sys32_execve (char __user *name, compat_uptr_t __user *argv, compat_uptr_t __use
125 125
126int cp_compat_stat(struct kstat *stat, struct compat_stat __user *ubuf) 126int cp_compat_stat(struct kstat *stat, struct compat_stat __user *ubuf)
127{ 127{
128 compat_ino_t ino;
128 int err; 129 int err;
129 130
130 if ((u64) stat->size > MAX_NON_LFS || 131 if ((u64) stat->size > MAX_NON_LFS ||
@@ -132,11 +133,15 @@ int cp_compat_stat(struct kstat *stat, struct compat_stat __user *ubuf)
132 !old_valid_dev(stat->rdev)) 133 !old_valid_dev(stat->rdev))
133 return -EOVERFLOW; 134 return -EOVERFLOW;
134 135
136 ino = stat->ino;
137 if (sizeof(ino) < sizeof(stat->ino) && ino != stat->ino)
138 return -EOVERFLOW;
139
135 if (clear_user(ubuf, sizeof(*ubuf))) 140 if (clear_user(ubuf, sizeof(*ubuf)))
136 return -EFAULT; 141 return -EFAULT;
137 142
138 err = __put_user(old_encode_dev(stat->dev), &ubuf->st_dev); 143 err = __put_user(old_encode_dev(stat->dev), &ubuf->st_dev);
139 err |= __put_user(stat->ino, &ubuf->st_ino); 144 err |= __put_user(ino, &ubuf->st_ino);
140 err |= __put_user(stat->mode, &ubuf->st_mode); 145 err |= __put_user(stat->mode, &ubuf->st_mode);
141 err |= __put_user(stat->nlink, &ubuf->st_nlink); 146 err |= __put_user(stat->nlink, &ubuf->st_nlink);
142 err |= __put_user(high2lowuid(stat->uid), &ubuf->st_uid); 147 err |= __put_user(high2lowuid(stat->uid), &ubuf->st_uid);
@@ -1222,16 +1227,20 @@ struct readdir32_callback {
1222}; 1227};
1223 1228
1224static int 1229static int
1225filldir32 (void *__buf, const char *name, int namlen, loff_t offset, ino_t ino, 1230filldir32 (void *__buf, const char *name, int namlen, loff_t offset, u64 ino,
1226 unsigned int d_type) 1231 unsigned int d_type)
1227{ 1232{
1228 struct compat_dirent __user * dirent; 1233 struct compat_dirent __user * dirent;
1229 struct getdents32_callback * buf = (struct getdents32_callback *) __buf; 1234 struct getdents32_callback * buf = (struct getdents32_callback *) __buf;
1230 int reclen = ROUND_UP(offsetof(struct compat_dirent, d_name) + namlen + 1, 4); 1235 int reclen = ROUND_UP(offsetof(struct compat_dirent, d_name) + namlen + 1, 4);
1236 u32 d_ino;
1231 1237
1232 buf->error = -EINVAL; /* only used if we fail.. */ 1238 buf->error = -EINVAL; /* only used if we fail.. */
1233 if (reclen > buf->count) 1239 if (reclen > buf->count)
1234 return -EINVAL; 1240 return -EINVAL;
1241 d_ino = ino;
1242 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
1243 return -EOVERFLOW;
1235 buf->error = -EFAULT; /* only used if we fail.. */ 1244 buf->error = -EFAULT; /* only used if we fail.. */
1236 dirent = buf->previous; 1245 dirent = buf->previous;
1237 if (dirent) 1246 if (dirent)
@@ -1239,7 +1248,7 @@ filldir32 (void *__buf, const char *name, int namlen, loff_t offset, ino_t ino,
1239 return -EFAULT; 1248 return -EFAULT;
1240 dirent = buf->current_dir; 1249 dirent = buf->current_dir;
1241 buf->previous = dirent; 1250 buf->previous = dirent;
1242 if (put_user(ino, &dirent->d_ino) 1251 if (put_user(d_ino, &dirent->d_ino)
1243 || put_user(reclen, &dirent->d_reclen) 1252 || put_user(reclen, &dirent->d_reclen)
1244 || copy_to_user(dirent->d_name, name, namlen) 1253 || copy_to_user(dirent->d_name, name, namlen)
1245 || put_user(0, dirent->d_name + namlen)) 1254 || put_user(0, dirent->d_name + namlen))
@@ -1287,17 +1296,21 @@ out:
1287} 1296}
1288 1297
1289static int 1298static int
1290fillonedir32 (void * __buf, const char * name, int namlen, loff_t offset, ino_t ino, 1299fillonedir32 (void * __buf, const char * name, int namlen, loff_t offset, u64 ino,
1291 unsigned int d_type) 1300 unsigned int d_type)
1292{ 1301{
1293 struct readdir32_callback * buf = (struct readdir32_callback *) __buf; 1302 struct readdir32_callback * buf = (struct readdir32_callback *) __buf;
1294 struct old_linux32_dirent __user * dirent; 1303 struct old_linux32_dirent __user * dirent;
1304 u32 d_ino;
1295 1305
1296 if (buf->count) 1306 if (buf->count)
1297 return -EINVAL; 1307 return -EINVAL;
1308 d_ino = ino;
1309 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
1310 return -EOVERFLOW;
1298 buf->count++; 1311 buf->count++;
1299 dirent = buf->dirent; 1312 dirent = buf->dirent;
1300 if (put_user(ino, &dirent->d_ino) 1313 if (put_user(d_ino, &dirent->d_ino)
1301 || put_user(offset, &dirent->d_offset) 1314 || put_user(offset, &dirent->d_offset)
1302 || put_user(namlen, &dirent->d_namlen) 1315 || put_user(namlen, &dirent->d_namlen)
1303 || copy_to_user(dirent->d_name, name, namlen) 1316 || copy_to_user(dirent->d_name, name, namlen)
diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c
index 52cada45b353..53f4171fc188 100644
--- a/arch/mips/kernel/linux32.c
+++ b/arch/mips/kernel/linux32.c
@@ -77,6 +77,8 @@ int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf)
77 memset(&tmp, 0, sizeof(tmp)); 77 memset(&tmp, 0, sizeof(tmp));
78 tmp.st_dev = new_encode_dev(stat->dev); 78 tmp.st_dev = new_encode_dev(stat->dev);
79 tmp.st_ino = stat->ino; 79 tmp.st_ino = stat->ino;
80 if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino)
81 return -EOVERFLOW;
80 tmp.st_mode = stat->mode; 82 tmp.st_mode = stat->mode;
81 tmp.st_nlink = stat->nlink; 83 tmp.st_nlink = stat->nlink;
82 SET_UID(tmp.st_uid, stat->uid); 84 SET_UID(tmp.st_uid, stat->uid);
diff --git a/arch/mips/kernel/sysirix.c b/arch/mips/kernel/sysirix.c
index 11bb97174972..93c74fefff76 100644
--- a/arch/mips/kernel/sysirix.c
+++ b/arch/mips/kernel/sysirix.c
@@ -1739,12 +1739,13 @@ struct irix_dirent32_callback {
1739#define ROUND_UP32(x) (((x)+sizeof(u32)-1) & ~(sizeof(u32)-1)) 1739#define ROUND_UP32(x) (((x)+sizeof(u32)-1) & ~(sizeof(u32)-1))
1740 1740
1741static int irix_filldir32(void *__buf, const char *name, 1741static int irix_filldir32(void *__buf, const char *name,
1742 int namlen, loff_t offset, ino_t ino, unsigned int d_type) 1742 int namlen, loff_t offset, u64 ino, unsigned int d_type)
1743{ 1743{
1744 struct irix_dirent32 __user *dirent; 1744 struct irix_dirent32 __user *dirent;
1745 struct irix_dirent32_callback *buf = __buf; 1745 struct irix_dirent32_callback *buf = __buf;
1746 unsigned short reclen = ROUND_UP32(NAME_OFFSET32(dirent) + namlen + 1); 1746 unsigned short reclen = ROUND_UP32(NAME_OFFSET32(dirent) + namlen + 1);
1747 int err = 0; 1747 int err = 0;
1748 u32 d_ino;
1748 1749
1749#ifdef DEBUG_GETDENTS 1750#ifdef DEBUG_GETDENTS
1750 printk("\nirix_filldir32[reclen<%d>namlen<%d>count<%d>]", 1751 printk("\nirix_filldir32[reclen<%d>namlen<%d>count<%d>]",
@@ -1753,12 +1754,15 @@ static int irix_filldir32(void *__buf, const char *name,
1753 buf->error = -EINVAL; /* only used if we fail.. */ 1754 buf->error = -EINVAL; /* only used if we fail.. */
1754 if (reclen > buf->count) 1755 if (reclen > buf->count)
1755 return -EINVAL; 1756 return -EINVAL;
1757 d_ino = ino;
1758 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
1759 return -EOVERFLOW;
1756 dirent = buf->previous; 1760 dirent = buf->previous;
1757 if (dirent) 1761 if (dirent)
1758 err = __put_user(offset, &dirent->d_off); 1762 err = __put_user(offset, &dirent->d_off);
1759 dirent = buf->current_dir; 1763 dirent = buf->current_dir;
1760 err |= __put_user(dirent, &buf->previous); 1764 err |= __put_user(dirent, &buf->previous);
1761 err |= __put_user(ino, &dirent->d_ino); 1765 err |= __put_user(d_ino, &dirent->d_ino);
1762 err |= __put_user(reclen, &dirent->d_reclen); 1766 err |= __put_user(reclen, &dirent->d_reclen);
1763 err |= copy_to_user((char __user *)dirent->d_name, name, namlen) ? -EFAULT : 0; 1767 err |= copy_to_user((char __user *)dirent->d_name, name, namlen) ? -EFAULT : 0;
1764 err |= __put_user(0, &dirent->d_name[namlen]); 1768 err |= __put_user(0, &dirent->d_name[namlen]);
@@ -1837,7 +1841,7 @@ struct irix_dirent64_callback {
1837#define ROUND_UP64(x) (((x)+sizeof(u64)-1) & ~(sizeof(u64)-1)) 1841#define ROUND_UP64(x) (((x)+sizeof(u64)-1) & ~(sizeof(u64)-1))
1838 1842
1839static int irix_filldir64(void *__buf, const char *name, 1843static int irix_filldir64(void *__buf, const char *name,
1840 int namlen, loff_t offset, ino_t ino, unsigned int d_type) 1844 int namlen, loff_t offset, u64 ino, unsigned int d_type)
1841{ 1845{
1842 struct irix_dirent64 __user *dirent; 1846 struct irix_dirent64 __user *dirent;
1843 struct irix_dirent64_callback * buf = __buf; 1847 struct irix_dirent64_callback * buf = __buf;
diff --git a/arch/parisc/hpux/fs.c b/arch/parisc/hpux/fs.c
index d7c80edf4489..6e79dbf3f6bd 100644
--- a/arch/parisc/hpux/fs.c
+++ b/arch/parisc/hpux/fs.c
@@ -77,17 +77,21 @@ static int filldir(void * __buf, const char * name, int namlen, loff_t offset,
77{ 77{
78 struct hpux_dirent * dirent; 78 struct hpux_dirent * dirent;
79 struct getdents_callback * buf = (struct getdents_callback *) __buf; 79 struct getdents_callback * buf = (struct getdents_callback *) __buf;
80 ino_t d_ino;
80 int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1); 81 int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1);
81 82
82 buf->error = -EINVAL; /* only used if we fail.. */ 83 buf->error = -EINVAL; /* only used if we fail.. */
83 if (reclen > buf->count) 84 if (reclen > buf->count)
84 return -EINVAL; 85 return -EINVAL;
86 d_ino = ino;
87 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
88 return -EOVERFLOW;
85 dirent = buf->previous; 89 dirent = buf->previous;
86 if (dirent) 90 if (dirent)
87 put_user(offset, &dirent->d_off); 91 put_user(offset, &dirent->d_off);
88 dirent = buf->current_dir; 92 dirent = buf->current_dir;
89 buf->previous = dirent; 93 buf->previous = dirent;
90 put_user(ino, &dirent->d_ino); 94 put_user(d_ino, &dirent->d_ino);
91 put_user(reclen, &dirent->d_reclen); 95 put_user(reclen, &dirent->d_reclen);
92 put_user(namlen, &dirent->d_namlen); 96 put_user(namlen, &dirent->d_namlen);
93 copy_to_user(dirent->d_name, name, namlen); 97 copy_to_user(dirent->d_name, name, namlen);
diff --git a/arch/parisc/kernel/sys_parisc32.c b/arch/parisc/kernel/sys_parisc32.c
index b74869803081..e3b30bc36453 100644
--- a/arch/parisc/kernel/sys_parisc32.c
+++ b/arch/parisc/kernel/sys_parisc32.c
@@ -237,14 +237,19 @@ int sys32_settimeofday(struct compat_timeval __user *tv, struct timezone __user
237 237
238int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf) 238int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf)
239{ 239{
240 compat_ino_t ino;
240 int err; 241 int err;
241 242
242 if (stat->size > MAX_NON_LFS || !new_valid_dev(stat->dev) || 243 if (stat->size > MAX_NON_LFS || !new_valid_dev(stat->dev) ||
243 !new_valid_dev(stat->rdev)) 244 !new_valid_dev(stat->rdev))
244 return -EOVERFLOW; 245 return -EOVERFLOW;
245 246
247 ino = stat->ino;
248 if (sizeof(ino) < sizeof(stat->ino) && ino != stat->ino)
249 return -EOVERFLOW;
250
246 err = put_user(new_encode_dev(stat->dev), &statbuf->st_dev); 251 err = put_user(new_encode_dev(stat->dev), &statbuf->st_dev);
247 err |= put_user(stat->ino, &statbuf->st_ino); 252 err |= put_user(ino, &statbuf->st_ino);
248 err |= put_user(stat->mode, &statbuf->st_mode); 253 err |= put_user(stat->mode, &statbuf->st_mode);
249 err |= put_user(stat->nlink, &statbuf->st_nlink); 254 err |= put_user(stat->nlink, &statbuf->st_nlink);
250 err |= put_user(0, &statbuf->st_reserved1); 255 err |= put_user(0, &statbuf->st_reserved1);
@@ -312,16 +317,20 @@ filldir32 (void *__buf, const char *name, int namlen, loff_t offset, ino_t ino,
312 struct linux32_dirent __user * dirent; 317 struct linux32_dirent __user * dirent;
313 struct getdents32_callback * buf = (struct getdents32_callback *) __buf; 318 struct getdents32_callback * buf = (struct getdents32_callback *) __buf;
314 int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1, 4); 319 int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1, 4);
320 u32 d_ino;
315 321
316 buf->error = -EINVAL; /* only used if we fail.. */ 322 buf->error = -EINVAL; /* only used if we fail.. */
317 if (reclen > buf->count) 323 if (reclen > buf->count)
318 return -EINVAL; 324 return -EINVAL;
325 d_ino = ino;
326 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
327 return -EOVERFLOW;
319 dirent = buf->previous; 328 dirent = buf->previous;
320 if (dirent) 329 if (dirent)
321 put_user(offset, &dirent->d_off); 330 put_user(offset, &dirent->d_off);
322 dirent = buf->current_dir; 331 dirent = buf->current_dir;
323 buf->previous = dirent; 332 buf->previous = dirent;
324 put_user(ino, &dirent->d_ino); 333 put_user(d_ino, &dirent->d_ino);
325 put_user(reclen, &dirent->d_reclen); 334 put_user(reclen, &dirent->d_reclen);
326 copy_to_user(dirent->d_name, name, namlen); 335 copy_to_user(dirent->d_name, name, namlen);
327 put_user(0, dirent->d_name + namlen); 336 put_user(0, dirent->d_name + namlen);
@@ -371,12 +380,16 @@ fillonedir32 (void * __buf, const char * name, int namlen, loff_t offset, ino_t
371{ 380{
372 struct readdir32_callback * buf = (struct readdir32_callback *) __buf; 381 struct readdir32_callback * buf = (struct readdir32_callback *) __buf;
373 struct old_linux32_dirent __user * dirent; 382 struct old_linux32_dirent __user * dirent;
383 u32 d_ino;
374 384
375 if (buf->count) 385 if (buf->count)
376 return -EINVAL; 386 return -EINVAL;
387 d_ino = ino;
388 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
389 return -EOVERFLOW;
377 buf->count++; 390 buf->count++;
378 dirent = buf->dirent; 391 dirent = buf->dirent;
379 put_user(ino, &dirent->d_ino); 392 put_user(d_ino, &dirent->d_ino);
380 put_user(offset, &dirent->d_offset); 393 put_user(offset, &dirent->d_offset);
381 put_user(namlen, &dirent->d_namlen); 394 put_user(namlen, &dirent->d_namlen);
382 copy_to_user(dirent->d_name, name, namlen); 395 copy_to_user(dirent->d_name, name, namlen);
diff --git a/arch/powerpc/kernel/sys_ppc32.c b/arch/powerpc/kernel/sys_ppc32.c
index 5e391fc25340..d15c33e95959 100644
--- a/arch/powerpc/kernel/sys_ppc32.c
+++ b/arch/powerpc/kernel/sys_ppc32.c
@@ -69,16 +69,20 @@ struct readdir_callback32 {
69}; 69};
70 70
71static int fillonedir(void * __buf, const char * name, int namlen, 71static int fillonedir(void * __buf, const char * name, int namlen,
72 off_t offset, ino_t ino, unsigned int d_type) 72 off_t offset, u64 ino, unsigned int d_type)
73{ 73{
74 struct readdir_callback32 * buf = (struct readdir_callback32 *) __buf; 74 struct readdir_callback32 * buf = (struct readdir_callback32 *) __buf;
75 struct old_linux_dirent32 __user * dirent; 75 struct old_linux_dirent32 __user * dirent;
76 ino_t d_ino;
76 77
77 if (buf->count) 78 if (buf->count)
78 return -EINVAL; 79 return -EINVAL;
80 d_ino = ino;
81 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
82 return -EOVERFLOW;
79 buf->count++; 83 buf->count++;
80 dirent = buf->dirent; 84 dirent = buf->dirent;
81 put_user(ino, &dirent->d_ino); 85 put_user(d_ino, &dirent->d_ino);
82 put_user(offset, &dirent->d_offset); 86 put_user(offset, &dirent->d_offset);
83 put_user(namlen, &dirent->d_namlen); 87 put_user(namlen, &dirent->d_namlen);
84 copy_to_user(dirent->d_name, name, namlen); 88 copy_to_user(dirent->d_name, name, namlen);
@@ -120,15 +124,20 @@ asmlinkage long ppc32_select(u32 n, compat_ulong_t __user *inp,
120 124
121int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf) 125int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf)
122{ 126{
127 compat_ino_t ino;
123 long err; 128 long err;
124 129
125 if (stat->size > MAX_NON_LFS || !new_valid_dev(stat->dev) || 130 if (stat->size > MAX_NON_LFS || !new_valid_dev(stat->dev) ||
126 !new_valid_dev(stat->rdev)) 131 !new_valid_dev(stat->rdev))
127 return -EOVERFLOW; 132 return -EOVERFLOW;
128 133
134 ino = stat->ino;
135 if (sizeof(ino) < sizeof(stat->ino) && ino != stat->ino)
136 return -EOVERFLOW;
137
129 err = access_ok(VERIFY_WRITE, statbuf, sizeof(*statbuf)) ? 0 : -EFAULT; 138 err = access_ok(VERIFY_WRITE, statbuf, sizeof(*statbuf)) ? 0 : -EFAULT;
130 err |= __put_user(new_encode_dev(stat->dev), &statbuf->st_dev); 139 err |= __put_user(new_encode_dev(stat->dev), &statbuf->st_dev);
131 err |= __put_user(stat->ino, &statbuf->st_ino); 140 err |= __put_user(ino, &statbuf->st_ino);
132 err |= __put_user(stat->mode, &statbuf->st_mode); 141 err |= __put_user(stat->mode, &statbuf->st_mode);
133 err |= __put_user(stat->nlink, &statbuf->st_nlink); 142 err |= __put_user(stat->nlink, &statbuf->st_nlink);
134 err |= __put_user(stat->uid, &statbuf->st_uid); 143 err |= __put_user(stat->uid, &statbuf->st_uid);
diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c
index c46e3d48e410..e15e1489aef5 100644
--- a/arch/s390/kernel/compat_linux.c
+++ b/arch/s390/kernel/compat_linux.c
@@ -357,11 +357,16 @@ asmlinkage long sys32_ftruncate64(unsigned int fd, unsigned long high, unsigned
357 357
358int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf) 358int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf)
359{ 359{
360 compat_ino_t ino;
360 int err; 361 int err;
361 362
362 if (!old_valid_dev(stat->dev) || !old_valid_dev(stat->rdev)) 363 if (!old_valid_dev(stat->dev) || !old_valid_dev(stat->rdev))
363 return -EOVERFLOW; 364 return -EOVERFLOW;
364 365
366 ino = stat->ino;
367 if (sizeof(ino) < sizeof(stat->ino) && ino != stat->ino)
368 return -EOVERFLOW;
369
365 err = put_user(old_encode_dev(stat->dev), &statbuf->st_dev); 370 err = put_user(old_encode_dev(stat->dev), &statbuf->st_dev);
366 err |= put_user(stat->ino, &statbuf->st_ino); 371 err |= put_user(stat->ino, &statbuf->st_ino);
367 err |= put_user(stat->mode, &statbuf->st_mode); 372 err |= put_user(stat->mode, &statbuf->st_mode);
diff --git a/arch/sparc/kernel/sys_sunos.c b/arch/sparc/kernel/sys_sunos.c
index 9d2cd97d1c3a..6f3ac548ee66 100644
--- a/arch/sparc/kernel/sys_sunos.c
+++ b/arch/sparc/kernel/sys_sunos.c
@@ -325,21 +325,25 @@ struct sunos_dirent_callback {
325#define ROUND_UP(x) (((x)+sizeof(long)-1) & ~(sizeof(long)-1)) 325#define ROUND_UP(x) (((x)+sizeof(long)-1) & ~(sizeof(long)-1))
326 326
327static int sunos_filldir(void * __buf, const char * name, int namlen, 327static int sunos_filldir(void * __buf, const char * name, int namlen,
328 loff_t offset, ino_t ino, unsigned int d_type) 328 loff_t offset, u64 ino, unsigned int d_type)
329{ 329{
330 struct sunos_dirent __user *dirent; 330 struct sunos_dirent __user *dirent;
331 struct sunos_dirent_callback * buf = __buf; 331 struct sunos_dirent_callback * buf = __buf;
332 unsigned long d_ino;
332 int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1); 333 int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1);
333 334
334 buf->error = -EINVAL; /* only used if we fail.. */ 335 buf->error = -EINVAL; /* only used if we fail.. */
335 if (reclen > buf->count) 336 if (reclen > buf->count)
336 return -EINVAL; 337 return -EINVAL;
338 d_ino = ino;
339 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
340 return -EOVERFLOW;
337 dirent = buf->previous; 341 dirent = buf->previous;
338 if (dirent) 342 if (dirent)
339 put_user(offset, &dirent->d_off); 343 put_user(offset, &dirent->d_off);
340 dirent = buf->curr; 344 dirent = buf->curr;
341 buf->previous = dirent; 345 buf->previous = dirent;
342 put_user(ino, &dirent->d_ino); 346 put_user(d_ino, &dirent->d_ino);
343 put_user(namlen, &dirent->d_namlen); 347 put_user(namlen, &dirent->d_namlen);
344 put_user(reclen, &dirent->d_reclen); 348 put_user(reclen, &dirent->d_reclen);
345 copy_to_user(dirent->d_name, name, namlen); 349 copy_to_user(dirent->d_name, name, namlen);
@@ -406,19 +410,23 @@ struct sunos_direntry_callback {
406}; 410};
407 411
408static int sunos_filldirentry(void * __buf, const char * name, int namlen, 412static int sunos_filldirentry(void * __buf, const char * name, int namlen,
409 loff_t offset, ino_t ino, unsigned int d_type) 413 loff_t offset, u64 ino, unsigned int d_type)
410{ 414{
411 struct sunos_direntry __user *dirent; 415 struct sunos_direntry __user *dirent;
412 struct sunos_direntry_callback *buf = __buf; 416 struct sunos_direntry_callback *buf = __buf;
417 unsigned long d_ino;
413 int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1); 418 int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1);
414 419
415 buf->error = -EINVAL; /* only used if we fail.. */ 420 buf->error = -EINVAL; /* only used if we fail.. */
416 if (reclen > buf->count) 421 if (reclen > buf->count)
417 return -EINVAL; 422 return -EINVAL;
423 d_ino = ino;
424 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
425 return -EOVERFLOW;
418 dirent = buf->previous; 426 dirent = buf->previous;
419 dirent = buf->curr; 427 dirent = buf->curr;
420 buf->previous = dirent; 428 buf->previous = dirent;
421 put_user(ino, &dirent->d_ino); 429 put_user(d_ino, &dirent->d_ino);
422 put_user(namlen, &dirent->d_namlen); 430 put_user(namlen, &dirent->d_namlen);
423 put_user(reclen, &dirent->d_reclen); 431 put_user(reclen, &dirent->d_reclen);
424 copy_to_user(dirent->d_name, name, namlen); 432 copy_to_user(dirent->d_name, name, namlen);
diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
index 69444f266e2d..dbc6d1a3be1f 100644
--- a/arch/sparc64/kernel/sys_sparc32.c
+++ b/arch/sparc64/kernel/sys_sparc32.c
@@ -337,12 +337,17 @@ asmlinkage long sys32_ftruncate64(unsigned int fd, unsigned long high, unsigned
337 337
338int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf) 338int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf)
339{ 339{
340 compat_ino_t ino;
340 int err; 341 int err;
341 342
342 if (stat->size > MAX_NON_LFS || !old_valid_dev(stat->dev) || 343 if (stat->size > MAX_NON_LFS || !old_valid_dev(stat->dev) ||
343 !old_valid_dev(stat->rdev)) 344 !old_valid_dev(stat->rdev))
344 return -EOVERFLOW; 345 return -EOVERFLOW;
345 346
347 ino = stat->ino;
348 if (sizeof(ino) < sizeof(stat->ino) && ino != stat->ino)
349 return -EOVERFLOW;
350
346 err = put_user(old_encode_dev(stat->dev), &statbuf->st_dev); 351 err = put_user(old_encode_dev(stat->dev), &statbuf->st_dev);
347 err |= put_user(stat->ino, &statbuf->st_ino); 352 err |= put_user(stat->ino, &statbuf->st_ino);
348 err |= put_user(stat->mode, &statbuf->st_mode); 353 err |= put_user(stat->mode, &statbuf->st_mode);
diff --git a/arch/sparc64/kernel/sys_sunos32.c b/arch/sparc64/kernel/sys_sunos32.c
index 953296b73f3f..e414c8ef0225 100644
--- a/arch/sparc64/kernel/sys_sunos32.c
+++ b/arch/sparc64/kernel/sys_sunos32.c
@@ -280,16 +280,20 @@ static int sunos_filldir(void * __buf, const char * name, int namlen,
280 struct sunos_dirent __user *dirent; 280 struct sunos_dirent __user *dirent;
281 struct sunos_dirent_callback * buf = (struct sunos_dirent_callback *) __buf; 281 struct sunos_dirent_callback * buf = (struct sunos_dirent_callback *) __buf;
282 int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1); 282 int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1);
283 u32 d_ino;
283 284
284 buf->error = -EINVAL; /* only used if we fail.. */ 285 buf->error = -EINVAL; /* only used if we fail.. */
285 if (reclen > buf->count) 286 if (reclen > buf->count)
286 return -EINVAL; 287 return -EINVAL;
288 d_ino = ino;
289 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
290 return -EOVERFLOW;
287 dirent = buf->previous; 291 dirent = buf->previous;
288 if (dirent) 292 if (dirent)
289 put_user(offset, &dirent->d_off); 293 put_user(offset, &dirent->d_off);
290 dirent = buf->curr; 294 dirent = buf->curr;
291 buf->previous = dirent; 295 buf->previous = dirent;
292 put_user(ino, &dirent->d_ino); 296 put_user(d_ino, &dirent->d_ino);
293 put_user(namlen, &dirent->d_namlen); 297 put_user(namlen, &dirent->d_namlen);
294 put_user(reclen, &dirent->d_reclen); 298 put_user(reclen, &dirent->d_reclen);
295 if (copy_to_user(dirent->d_name, name, namlen)) 299 if (copy_to_user(dirent->d_name, name, namlen))
@@ -363,14 +367,18 @@ static int sunos_filldirentry(void * __buf, const char * name, int namlen,
363 struct sunos_direntry_callback * buf = 367 struct sunos_direntry_callback * buf =
364 (struct sunos_direntry_callback *) __buf; 368 (struct sunos_direntry_callback *) __buf;
365 int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1); 369 int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1);
370 u32 d_ino;
366 371
367 buf->error = -EINVAL; /* only used if we fail.. */ 372 buf->error = -EINVAL; /* only used if we fail.. */
368 if (reclen > buf->count) 373 if (reclen > buf->count)
369 return -EINVAL; 374 return -EINVAL;
375 d_ino = ino;
376 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
377 return -EOVERFLOW;
370 dirent = buf->previous; 378 dirent = buf->previous;
371 dirent = buf->curr; 379 dirent = buf->curr;
372 buf->previous = dirent; 380 buf->previous = dirent;
373 put_user(ino, &dirent->d_ino); 381 put_user(d_ino, &dirent->d_ino);
374 put_user(namlen, &dirent->d_namlen); 382 put_user(namlen, &dirent->d_namlen);
375 put_user(reclen, &dirent->d_reclen); 383 put_user(reclen, &dirent->d_reclen);
376 if (copy_to_user(dirent->d_name, name, namlen)) 384 if (copy_to_user(dirent->d_name, name, namlen))
diff --git a/arch/sparc64/solaris/fs.c b/arch/sparc64/solaris/fs.c
index 0f0eb6aa1c40..12a940cc791f 100644
--- a/arch/sparc64/solaris/fs.c
+++ b/arch/sparc64/solaris/fs.c
@@ -82,12 +82,17 @@ struct sol_stat64 {
82 82
83static inline int putstat(struct sol_stat __user *ubuf, struct kstat *kbuf) 83static inline int putstat(struct sol_stat __user *ubuf, struct kstat *kbuf)
84{ 84{
85 u32 ino;
86
85 if (kbuf->size > MAX_NON_LFS || 87 if (kbuf->size > MAX_NON_LFS ||
86 !sysv_valid_dev(kbuf->dev) || 88 !sysv_valid_dev(kbuf->dev) ||
87 !sysv_valid_dev(kbuf->rdev)) 89 !sysv_valid_dev(kbuf->rdev))
88 return -EOVERFLOW; 90 return -EOVERFLOW;
91 ino = kbuf->ino;
92 if (sizeof(ino) < sizeof(kbuf->ino) && ino != kbuf->ino)
93 return -EOVERFLOW;
89 if (put_user (sysv_encode_dev(kbuf->dev), &ubuf->st_dev) || 94 if (put_user (sysv_encode_dev(kbuf->dev), &ubuf->st_dev) ||
90 __put_user (kbuf->ino, &ubuf->st_ino) || 95 __put_user (ino, &ubuf->st_ino) ||
91 __put_user (kbuf->mode, &ubuf->st_mode) || 96 __put_user (kbuf->mode, &ubuf->st_mode) ||
92 __put_user (kbuf->nlink, &ubuf->st_nlink) || 97 __put_user (kbuf->nlink, &ubuf->st_nlink) ||
93 __put_user (kbuf->uid, &ubuf->st_uid) || 98 __put_user (kbuf->uid, &ubuf->st_uid) ||
diff --git a/arch/x86_64/ia32/sys_ia32.c b/arch/x86_64/ia32/sys_ia32.c
index 26a01717cc1a..c9bac3af29d6 100644
--- a/arch/x86_64/ia32/sys_ia32.c
+++ b/arch/x86_64/ia32/sys_ia32.c
@@ -76,6 +76,8 @@
76 76
77int cp_compat_stat(struct kstat *kbuf, struct compat_stat __user *ubuf) 77int cp_compat_stat(struct kstat *kbuf, struct compat_stat __user *ubuf)
78{ 78{
79 compat_ino_t ino;
80
79 typeof(ubuf->st_uid) uid = 0; 81 typeof(ubuf->st_uid) uid = 0;
80 typeof(ubuf->st_gid) gid = 0; 82 typeof(ubuf->st_gid) gid = 0;
81 SET_UID(uid, kbuf->uid); 83 SET_UID(uid, kbuf->uid);
@@ -84,9 +86,12 @@ int cp_compat_stat(struct kstat *kbuf, struct compat_stat __user *ubuf)
84 return -EOVERFLOW; 86 return -EOVERFLOW;
85 if (kbuf->size >= 0x7fffffff) 87 if (kbuf->size >= 0x7fffffff)
86 return -EOVERFLOW; 88 return -EOVERFLOW;
89 ino = kbuf->ino;
90 if (sizeof(ino) < sizeof(kbuf->ino) && ino != kbuf->ino)
91 return -EOVERFLOW;
87 if (!access_ok(VERIFY_WRITE, ubuf, sizeof(struct compat_stat)) || 92 if (!access_ok(VERIFY_WRITE, ubuf, sizeof(struct compat_stat)) ||
88 __put_user (old_encode_dev(kbuf->dev), &ubuf->st_dev) || 93 __put_user (old_encode_dev(kbuf->dev), &ubuf->st_dev) ||
89 __put_user (kbuf->ino, &ubuf->st_ino) || 94 __put_user (ino, &ubuf->st_ino) ||
90 __put_user (kbuf->mode, &ubuf->st_mode) || 95 __put_user (kbuf->mode, &ubuf->st_mode) ||
91 __put_user (kbuf->nlink, &ubuf->st_nlink) || 96 __put_user (kbuf->nlink, &ubuf->st_nlink) ||
92 __put_user (uid, &ubuf->st_uid) || 97 __put_user (uid, &ubuf->st_uid) ||
diff --git a/fs/afs/dir.c b/fs/afs/dir.c
index 2fc99877cb0d..cf8a2cb28505 100644
--- a/fs/afs/dir.c
+++ b/fs/afs/dir.c
@@ -30,7 +30,7 @@ static int afs_dir_readdir(struct file *file, void *dirent, filldir_t filldir);
30static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd); 30static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd);
31static int afs_d_delete(struct dentry *dentry); 31static int afs_d_delete(struct dentry *dentry);
32static int afs_dir_lookup_filldir(void *_cookie, const char *name, int nlen, 32static int afs_dir_lookup_filldir(void *_cookie, const char *name, int nlen,
33 loff_t fpos, ino_t ino, unsigned dtype); 33 loff_t fpos, u64 ino, unsigned dtype);
34 34
35const struct file_operations afs_dir_file_operations = { 35const struct file_operations afs_dir_file_operations = {
36 .open = afs_dir_open, 36 .open = afs_dir_open,
@@ -409,7 +409,7 @@ static int afs_dir_readdir(struct file *file, void *cookie, filldir_t filldir)
409 * uniquifier through dtype 409 * uniquifier through dtype
410 */ 410 */
411static int afs_dir_lookup_filldir(void *_cookie, const char *name, int nlen, 411static int afs_dir_lookup_filldir(void *_cookie, const char *name, int nlen,
412 loff_t fpos, ino_t ino, unsigned dtype) 412 loff_t fpos, u64 ino, unsigned dtype)
413{ 413{
414 struct afs_dir_lookup_cookie *cookie = _cookie; 414 struct afs_dir_lookup_cookie *cookie = _cookie;
415 415
diff --git a/fs/compat.c b/fs/compat.c
index d98c96f4a44d..4d3fbcb2ddb1 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -914,20 +914,24 @@ struct compat_readdir_callback {
914}; 914};
915 915
916static int compat_fillonedir(void *__buf, const char *name, int namlen, 916static int compat_fillonedir(void *__buf, const char *name, int namlen,
917 loff_t offset, ino_t ino, unsigned int d_type) 917 loff_t offset, u64 ino, unsigned int d_type)
918{ 918{
919 struct compat_readdir_callback *buf = __buf; 919 struct compat_readdir_callback *buf = __buf;
920 struct compat_old_linux_dirent __user *dirent; 920 struct compat_old_linux_dirent __user *dirent;
921 compat_ulong_t d_ino;
921 922
922 if (buf->result) 923 if (buf->result)
923 return -EINVAL; 924 return -EINVAL;
925 d_ino = ino;
926 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
927 return -EOVERFLOW;
924 buf->result++; 928 buf->result++;
925 dirent = buf->dirent; 929 dirent = buf->dirent;
926 if (!access_ok(VERIFY_WRITE, dirent, 930 if (!access_ok(VERIFY_WRITE, dirent,
927 (unsigned long)(dirent->d_name + namlen + 1) - 931 (unsigned long)(dirent->d_name + namlen + 1) -
928 (unsigned long)dirent)) 932 (unsigned long)dirent))
929 goto efault; 933 goto efault;
930 if ( __put_user(ino, &dirent->d_ino) || 934 if ( __put_user(d_ino, &dirent->d_ino) ||
931 __put_user(offset, &dirent->d_offset) || 935 __put_user(offset, &dirent->d_offset) ||
932 __put_user(namlen, &dirent->d_namlen) || 936 __put_user(namlen, &dirent->d_namlen) ||
933 __copy_to_user(dirent->d_name, name, namlen) || 937 __copy_to_user(dirent->d_name, name, namlen) ||
@@ -978,22 +982,26 @@ struct compat_getdents_callback {
978}; 982};
979 983
980static int compat_filldir(void *__buf, const char *name, int namlen, 984static int compat_filldir(void *__buf, const char *name, int namlen,
981 loff_t offset, ino_t ino, unsigned int d_type) 985 loff_t offset, u64 ino, unsigned int d_type)
982{ 986{
983 struct compat_linux_dirent __user * dirent; 987 struct compat_linux_dirent __user * dirent;
984 struct compat_getdents_callback *buf = __buf; 988 struct compat_getdents_callback *buf = __buf;
989 compat_ulong_t d_ino;
985 int reclen = COMPAT_ROUND_UP(NAME_OFFSET(dirent) + namlen + 2); 990 int reclen = COMPAT_ROUND_UP(NAME_OFFSET(dirent) + namlen + 2);
986 991
987 buf->error = -EINVAL; /* only used if we fail.. */ 992 buf->error = -EINVAL; /* only used if we fail.. */
988 if (reclen > buf->count) 993 if (reclen > buf->count)
989 return -EINVAL; 994 return -EINVAL;
995 d_ino = ino;
996 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
997 return -EOVERFLOW;
990 dirent = buf->previous; 998 dirent = buf->previous;
991 if (dirent) { 999 if (dirent) {
992 if (__put_user(offset, &dirent->d_off)) 1000 if (__put_user(offset, &dirent->d_off))
993 goto efault; 1001 goto efault;
994 } 1002 }
995 dirent = buf->current_dir; 1003 dirent = buf->current_dir;
996 if (__put_user(ino, &dirent->d_ino)) 1004 if (__put_user(d_ino, &dirent->d_ino))
997 goto efault; 1005 goto efault;
998 if (__put_user(reclen, &dirent->d_reclen)) 1006 if (__put_user(reclen, &dirent->d_reclen))
999 goto efault; 1007 goto efault;
@@ -1064,7 +1072,7 @@ struct compat_getdents_callback64 {
1064}; 1072};
1065 1073
1066static int compat_filldir64(void * __buf, const char * name, int namlen, loff_t offset, 1074static int compat_filldir64(void * __buf, const char * name, int namlen, loff_t offset,
1067 ino_t ino, unsigned int d_type) 1075 u64 ino, unsigned int d_type)
1068{ 1076{
1069 struct linux_dirent64 __user *dirent; 1077 struct linux_dirent64 __user *dirent;
1070 struct compat_getdents_callback64 *buf = __buf; 1078 struct compat_getdents_callback64 *buf = __buf;
diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c
index 4c39009350f3..93e77c3d2490 100644
--- a/fs/exportfs/expfs.c
+++ b/fs/exportfs/expfs.c
@@ -315,7 +315,7 @@ struct getdents_callback {
315 * the name matching the specified inode number. 315 * the name matching the specified inode number.
316 */ 316 */
317static int filldir_one(void * __buf, const char * name, int len, 317static int filldir_one(void * __buf, const char * name, int len,
318 loff_t pos, ino_t ino, unsigned int d_type) 318 loff_t pos, u64 ino, unsigned int d_type)
319{ 319{
320 struct getdents_callback *buf = __buf; 320 struct getdents_callback *buf = __buf;
321 int result = 0; 321 int result = 0;
diff --git a/fs/fat/dir.c b/fs/fat/dir.c
index 3e50a4166283..69c439f44387 100644
--- a/fs/fat/dir.c
+++ b/fs/fat/dir.c
@@ -648,7 +648,7 @@ static int fat_readdir(struct file *filp, void *dirent, filldir_t filldir)
648} 648}
649 649
650static int fat_ioctl_filldir(void *__buf, const char *name, int name_len, 650static int fat_ioctl_filldir(void *__buf, const char *name, int name_len,
651 loff_t offset, ino_t ino, unsigned int d_type) 651 loff_t offset, u64 ino, unsigned int d_type)
652{ 652{
653 struct fat_ioctl_filldir_callback *buf = __buf; 653 struct fat_ioctl_filldir_callback *buf = __buf;
654 struct dirent __user *d1 = buf->dirent; 654 struct dirent __user *d1 = buf->dirent;
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c
index e35d7e52fdeb..1cbd2e4ee122 100644
--- a/fs/nfsd/nfs4recover.c
+++ b/fs/nfsd/nfs4recover.c
@@ -184,7 +184,7 @@ struct dentry_list_arg {
184 184
185static int 185static int
186nfsd4_build_dentrylist(void *arg, const char *name, int namlen, 186nfsd4_build_dentrylist(void *arg, const char *name, int namlen,
187 loff_t offset, ino_t ino, unsigned int d_type) 187 loff_t offset, u64 ino, unsigned int d_type)
188{ 188{
189 struct dentry_list_arg *dla = arg; 189 struct dentry_list_arg *dla = arg;
190 struct list_head *dentries = &dla->dentries; 190 struct list_head *dentries = &dla->dentries;
diff --git a/fs/readdir.c b/fs/readdir.c
index b6109329b607..bff3ee58e2f8 100644
--- a/fs/readdir.c
+++ b/fs/readdir.c
@@ -69,20 +69,24 @@ struct readdir_callback {
69}; 69};
70 70
71static int fillonedir(void * __buf, const char * name, int namlen, loff_t offset, 71static int fillonedir(void * __buf, const char * name, int namlen, loff_t offset,
72 ino_t ino, unsigned int d_type) 72 u64 ino, unsigned int d_type)
73{ 73{
74 struct readdir_callback * buf = (struct readdir_callback *) __buf; 74 struct readdir_callback * buf = (struct readdir_callback *) __buf;
75 struct old_linux_dirent __user * dirent; 75 struct old_linux_dirent __user * dirent;
76 unsigned long d_ino;
76 77
77 if (buf->result) 78 if (buf->result)
78 return -EINVAL; 79 return -EINVAL;
80 d_ino = ino;
81 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
82 return -EOVERFLOW;
79 buf->result++; 83 buf->result++;
80 dirent = buf->dirent; 84 dirent = buf->dirent;
81 if (!access_ok(VERIFY_WRITE, dirent, 85 if (!access_ok(VERIFY_WRITE, dirent,
82 (unsigned long)(dirent->d_name + namlen + 1) - 86 (unsigned long)(dirent->d_name + namlen + 1) -
83 (unsigned long)dirent)) 87 (unsigned long)dirent))
84 goto efault; 88 goto efault;
85 if ( __put_user(ino, &dirent->d_ino) || 89 if ( __put_user(d_ino, &dirent->d_ino) ||
86 __put_user(offset, &dirent->d_offset) || 90 __put_user(offset, &dirent->d_offset) ||
87 __put_user(namlen, &dirent->d_namlen) || 91 __put_user(namlen, &dirent->d_namlen) ||
88 __copy_to_user(dirent->d_name, name, namlen) || 92 __copy_to_user(dirent->d_name, name, namlen) ||
@@ -138,22 +142,26 @@ struct getdents_callback {
138}; 142};
139 143
140static int filldir(void * __buf, const char * name, int namlen, loff_t offset, 144static int filldir(void * __buf, const char * name, int namlen, loff_t offset,
141 ino_t ino, unsigned int d_type) 145 u64 ino, unsigned int d_type)
142{ 146{
143 struct linux_dirent __user * dirent; 147 struct linux_dirent __user * dirent;
144 struct getdents_callback * buf = (struct getdents_callback *) __buf; 148 struct getdents_callback * buf = (struct getdents_callback *) __buf;
149 unsigned long d_ino;
145 int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 2); 150 int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 2);
146 151
147 buf->error = -EINVAL; /* only used if we fail.. */ 152 buf->error = -EINVAL; /* only used if we fail.. */
148 if (reclen > buf->count) 153 if (reclen > buf->count)
149 return -EINVAL; 154 return -EINVAL;
155 d_ino = ino;
156 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
157 return -EOVERFLOW;
150 dirent = buf->previous; 158 dirent = buf->previous;
151 if (dirent) { 159 if (dirent) {
152 if (__put_user(offset, &dirent->d_off)) 160 if (__put_user(offset, &dirent->d_off))
153 goto efault; 161 goto efault;
154 } 162 }
155 dirent = buf->current_dir; 163 dirent = buf->current_dir;
156 if (__put_user(ino, &dirent->d_ino)) 164 if (__put_user(d_ino, &dirent->d_ino))
157 goto efault; 165 goto efault;
158 if (__put_user(reclen, &dirent->d_reclen)) 166 if (__put_user(reclen, &dirent->d_reclen))
159 goto efault; 167 goto efault;
@@ -222,7 +230,7 @@ struct getdents_callback64 {
222}; 230};
223 231
224static int filldir64(void * __buf, const char * name, int namlen, loff_t offset, 232static int filldir64(void * __buf, const char * name, int namlen, loff_t offset,
225 ino_t ino, unsigned int d_type) 233 u64 ino, unsigned int d_type)
226{ 234{
227 struct linux_dirent64 __user *dirent; 235 struct linux_dirent64 __user *dirent;
228 struct getdents_callback64 * buf = (struct getdents_callback64 *) __buf; 236 struct getdents_callback64 * buf = (struct getdents_callback64 *) __buf;
diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c
index d935fb9394e3..7bdb0ed443e1 100644
--- a/fs/reiserfs/xattr.c
+++ b/fs/reiserfs/xattr.c
@@ -773,7 +773,7 @@ int reiserfs_xattr_del(struct inode *inode, const char *name)
773 773
774static int 774static int
775reiserfs_delete_xattrs_filler(void *buf, const char *name, int namelen, 775reiserfs_delete_xattrs_filler(void *buf, const char *name, int namelen,
776 loff_t offset, ino_t ino, unsigned int d_type) 776 loff_t offset, u64 ino, unsigned int d_type)
777{ 777{
778 struct dentry *xadir = (struct dentry *)buf; 778 struct dentry *xadir = (struct dentry *)buf;
779 779
@@ -851,7 +851,7 @@ struct reiserfs_chown_buf {
851/* XXX: If there is a better way to do this, I'd love to hear about it */ 851/* XXX: If there is a better way to do this, I'd love to hear about it */
852static int 852static int
853reiserfs_chown_xattrs_filler(void *buf, const char *name, int namelen, 853reiserfs_chown_xattrs_filler(void *buf, const char *name, int namelen,
854 loff_t offset, ino_t ino, unsigned int d_type) 854 loff_t offset, u64 ino, unsigned int d_type)
855{ 855{
856 struct reiserfs_chown_buf *chown_buf = (struct reiserfs_chown_buf *)buf; 856 struct reiserfs_chown_buf *chown_buf = (struct reiserfs_chown_buf *)buf;
857 struct dentry *xafile, *xadir = chown_buf->xadir; 857 struct dentry *xafile, *xadir = chown_buf->xadir;
@@ -1036,7 +1036,7 @@ struct reiserfs_listxattr_buf {
1036 1036
1037static int 1037static int
1038reiserfs_listxattr_filler(void *buf, const char *name, int namelen, 1038reiserfs_listxattr_filler(void *buf, const char *name, int namelen,
1039 loff_t offset, ino_t ino, unsigned int d_type) 1039 loff_t offset, u64 ino, unsigned int d_type)
1040{ 1040{
1041 struct reiserfs_listxattr_buf *b = (struct reiserfs_listxattr_buf *)buf; 1041 struct reiserfs_listxattr_buf *b = (struct reiserfs_listxattr_buf *)buf;
1042 int len = 0; 1042 int len = 0;
diff --git a/fs/stat.c b/fs/stat.c
index 60a31d5e5966..bca07eb2003c 100644
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -140,6 +140,8 @@ static int cp_old_stat(struct kstat *stat, struct __old_kernel_stat __user * sta
140 memset(&tmp, 0, sizeof(struct __old_kernel_stat)); 140 memset(&tmp, 0, sizeof(struct __old_kernel_stat));
141 tmp.st_dev = old_encode_dev(stat->dev); 141 tmp.st_dev = old_encode_dev(stat->dev);
142 tmp.st_ino = stat->ino; 142 tmp.st_ino = stat->ino;
143 if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino)
144 return -EOVERFLOW;
143 tmp.st_mode = stat->mode; 145 tmp.st_mode = stat->mode;
144 tmp.st_nlink = stat->nlink; 146 tmp.st_nlink = stat->nlink;
145 if (tmp.st_nlink != stat->nlink) 147 if (tmp.st_nlink != stat->nlink)
@@ -210,6 +212,8 @@ static int cp_new_stat(struct kstat *stat, struct stat __user *statbuf)
210 tmp.st_dev = new_encode_dev(stat->dev); 212 tmp.st_dev = new_encode_dev(stat->dev);
211#endif 213#endif
212 tmp.st_ino = stat->ino; 214 tmp.st_ino = stat->ino;
215 if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino)
216 return -EOVERFLOW;
213 tmp.st_mode = stat->mode; 217 tmp.st_mode = stat->mode;
214 tmp.st_nlink = stat->nlink; 218 tmp.st_nlink = stat->nlink;
215 if (tmp.st_nlink != stat->nlink) 219 if (tmp.st_nlink != stat->nlink)
@@ -347,6 +351,8 @@ static long cp_new_stat64(struct kstat *stat, struct stat64 __user *statbuf)
347 tmp.st_rdev = huge_encode_dev(stat->rdev); 351 tmp.st_rdev = huge_encode_dev(stat->rdev);
348#endif 352#endif
349 tmp.st_ino = stat->ino; 353 tmp.st_ino = stat->ino;
354 if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino)
355 return -EOVERFLOW;
350#ifdef STAT64_HAS_BROKEN_ST_INO 356#ifdef STAT64_HAS_BROKEN_ST_INO
351 tmp.__st_ino = stat->ino; 357 tmp.__st_ino = stat->ino;
352#endif 358#endif
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 91c0b2a32a90..7b61e94bf8fc 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1049,7 +1049,7 @@ int generic_osync_inode(struct inode *, struct address_space *, int);
1049 * This allows the kernel to read directories into kernel space or 1049 * This allows the kernel to read directories into kernel space or
1050 * to have different dirent layouts depending on the binary type. 1050 * to have different dirent layouts depending on the binary type.
1051 */ 1051 */
1052typedef int (*filldir_t)(void *, const char *, int, loff_t, ino_t, unsigned); 1052typedef int (*filldir_t)(void *, const char *, int, loff_t, u64, unsigned);
1053 1053
1054struct block_device_operations { 1054struct block_device_operations {
1055 int (*open) (struct inode *, struct file *); 1055 int (*open) (struct inode *, struct file *);
diff --git a/include/linux/stat.h b/include/linux/stat.h
index 8669291352db..679ef0d70b6b 100644
--- a/include/linux/stat.h
+++ b/include/linux/stat.h
@@ -57,7 +57,7 @@
57#include <linux/time.h> 57#include <linux/time.h>
58 58
59struct kstat { 59struct kstat {
60 unsigned long ino; 60 u64 ino;
61 dev_t dev; 61 dev_t dev;
62 umode_t mode; 62 umode_t mode;
63 unsigned int nlink; 63 unsigned int nlink;