[PATCH] fstatat64 support

The *at patches introduced fstatat and, due to inusfficient research, I
used the newfstat functions generally as the guideline. The result is that
on 32-bit platforms we don't have all the information needed to implement
fstatat64.

This patch modifies the code to pass up 64-bit information if
__ARCH_WANT_STAT64 is defined. I renamed the syscall entry point to make
this clear. Other archs will continue to use the existing code. On x86-64
the compat code is implemented using a new sys32_ function. this is what
is done for the other stat syscalls as well.

This patch might break some other archs (those which define
__ARCH_WANT_STAT64 and which already wired up the syscall). Yet others
might need changes to accomodate the compatibility mode. I really don't
want to do that work because all this stat handling is a mess (more so in
glibc, but the kernel is also affected). It should be done by the arch
maintainers. I'll provide some stand-alone test shortly. Those who are
eager could compile glibc and run 'make check' (no installation needed).

The patch below has been tested on x86 and x86-64.

Signed-off-by: Ulrich Drepper <drepper@redhat.com>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Andi Kleen <ak@muc.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

authored by Ulrich Drepper and committed by Linus Torvalds cff2b760 25bf368b

+50 -4
+1 -1
arch/i386/kernel/syscall_table.S
··· 299 299 .long sys_mknodat 300 300 .long sys_fchownat 301 301 .long sys_futimesat 302 - .long sys_newfstatat /* 300 */ 302 + .long sys_fstatat64 /* 300 */ 303 303 .long sys_unlinkat 304 304 .long sys_renameat 305 305 .long sys_linkat
+1 -1
arch/x86_64/ia32/ia32entry.S
··· 677 677 .quad sys_mknodat 678 678 .quad sys_fchownat 679 679 .quad compat_sys_futimesat 680 - .quad compat_sys_newfstatat /* 300 */ 680 + .quad sys32_fstatat /* 300 */ 681 681 .quad sys_unlinkat 682 682 .quad sys_renameat 683 683 .quad sys_linkat
+22
arch/x86_64/ia32/sys_ia32.c
··· 180 180 return ret; 181 181 } 182 182 183 + asmlinkage long 184 + sys32_fstatat(unsigned int dfd, char __user *filename, 185 + struct stat64 __user* statbuf, int flag) 186 + { 187 + struct kstat stat; 188 + int error = -EINVAL; 189 + 190 + if ((flag & ~AT_SYMLINK_NOFOLLOW) != 0) 191 + goto out; 192 + 193 + if (flag & AT_SYMLINK_NOFOLLOW) 194 + error = vfs_lstat_fd(dfd, filename, &stat); 195 + else 196 + error = vfs_stat_fd(dfd, filename, &stat); 197 + 198 + if (!error) 199 + error = cp_stat64(statbuf, &stat); 200 + 201 + out: 202 + return error; 203 + } 204 + 183 205 /* 184 206 * Linux/i386 didn't use to be able to handle more than 185 207 * 4 system call parameters, so these system calls used a memory
+22
fs/stat.c
··· 261 261 return error; 262 262 } 263 263 264 + #ifndef __ARCH_WANT_STAT64 264 265 asmlinkage long sys_newfstatat(int dfd, char __user *filename, 265 266 struct stat __user *statbuf, int flag) 266 267 { ··· 282 281 out: 283 282 return error; 284 283 } 284 + #endif 285 285 286 286 asmlinkage long sys_newfstat(unsigned int fd, struct stat __user *statbuf) 287 287 { ··· 397 395 return error; 398 396 } 399 397 398 + asmlinkage long sys_fstatat64(int dfd, char __user *filename, 399 + struct stat64 __user *statbuf, int flag) 400 + { 401 + struct kstat stat; 402 + int error = -EINVAL; 403 + 404 + if ((flag & ~AT_SYMLINK_NOFOLLOW) != 0) 405 + goto out; 406 + 407 + if (flag & AT_SYMLINK_NOFOLLOW) 408 + error = vfs_lstat_fd(dfd, filename, &stat); 409 + else 410 + error = vfs_stat_fd(dfd, filename, &stat); 411 + 412 + if (!error) 413 + error = cp_new_stat64(&stat, statbuf); 414 + 415 + out: 416 + return error; 417 + } 400 418 #endif /* __ARCH_WANT_STAT64 */ 401 419 402 420 void inode_add_bytes(struct inode *inode, loff_t bytes)
+1 -1
include/asm-i386/unistd.h
··· 305 305 #define __NR_mknodat 297 306 306 #define __NR_fchownat 298 307 307 #define __NR_futimesat 299 308 - #define __NR_newfstatat 300 308 + #define __NR_fstatat64 300 309 309 #define __NR_unlinkat 301 310 310 #define __NR_renameat 302 311 311 #define __NR_linkat 303
+1 -1
include/asm-x86_64/ia32_unistd.h
··· 305 305 #define __NR_ia32_mknodat 297 306 306 #define __NR_ia32_fchownat 298 307 307 #define __NR_ia32_futimesat 299 308 - #define __NR_ia32_newfstatat 300 308 + #define __NR_ia32_fstatat64 300 309 309 #define __NR_ia32_unlinkat 301 310 310 #define __NR_ia32_renameat 302 311 311 #define __NR_ia32_linkat 303
+2
include/linux/syscalls.h
··· 557 557 int mode); 558 558 asmlinkage long sys_newfstatat(int dfd, char __user *filename, 559 559 struct stat __user *statbuf, int flag); 560 + asmlinkage long sys_fstatat64(int dfd, char __user *filename, 561 + struct stat64 __user *statbuf, int flag); 560 562 asmlinkage long sys_readlinkat(int dfd, const char __user *path, char __user *buf, 561 563 int bufsiz); 562 564 asmlinkage long compat_sys_futimesat(unsigned int dfd, char __user *filename,