diff -urN aa/arch/i386/kernel/entry.S lfs/arch/i386/kernel/entry.S --- aa/arch/i386/kernel/entry.S Mon Apr 3 03:21:55 2000 +++ lfs/arch/i386/kernel/entry.S Fri Apr 21 16:44:02 2000 @@ -634,6 +634,7 @@ .long SYMBOL_NAME(sys_pivot_root) .long SYMBOL_NAME(sys_mincore) .long SYMBOL_NAME(sys_madvise) + .long SYMBOL_NAME(sys_fcntl64) /* @@ -642,6 +643,6 @@ * entries. Don't panic if you notice that this hasn't * been shrunk every time we add a new system call. */ - .rept NR_syscalls-219 + .rept NR_syscalls-220 .long SYMBOL_NAME(sys_ni_syscall) .endr diff -urN aa/arch/sparc/kernel/systbls.S lfs/arch/sparc/kernel/systbls.S --- aa/arch/sparc/kernel/systbls.S Tue Apr 18 16:12:15 2000 +++ lfs/arch/sparc/kernel/systbls.S Fri Apr 21 16:38:41 2000 @@ -44,7 +44,7 @@ /*115*/ .long sys_getgroups, sys_gettimeofday, sys_getrusage, sys_nis_syscall, sys_getcwd /*120*/ .long sys_readv, sys_writev, sys_settimeofday, sys_fchown16, sys_fchmod /*125*/ .long sys_nis_syscall, sys_setreuid16, sys_setregid16, sys_rename, sys_truncate -/*130*/ .long sys_ftruncate, sys_flock, sys_lstat64, sys_nis_syscall, sys_nis_syscall +/*130*/ .long sys_ftruncate, sys_flock, sys_lstat64, sys_fcntl64, sys_nis_syscall /*135*/ .long sys_nis_syscall, sys_mkdir, sys_rmdir, sys_utimes, sys_stat64 /*140*/ .long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getrlimit /*145*/ .long sys_setrlimit, sys_pivot_root, sys_prctl, sys_pciconfig_read, sys_pciconfig_write diff -urN aa/arch/sparc64/kernel/sys_sparc32.c lfs/arch/sparc64/kernel/sys_sparc32.c --- aa/arch/sparc64/kernel/sys_sparc32.c Fri Apr 21 16:33:09 2000 +++ lfs/arch/sparc64/kernel/sys_sparc32.c Fri Apr 21 16:55:37 2000 @@ -889,6 +889,30 @@ return err; } +static inline int get_flock64(struct flock *kfl, struct flock32_64 *ufl) +{ + int err; + + err = get_user(kfl->l_type, &ufl->l_type); + err |= __get_user(kfl->l_whence, &ufl->l_whence); + err |= __get_user(kfl->l_start, &ufl->l_start); + err |= __get_user(kfl->l_len, &ufl->l_len); + err |= __get_user(kfl->l_pid, &ufl->l_pid); + return err; +} + +static inline int put_flock64(struct flock *kfl, struct flock32_64 *ufl) +{ + int err; + + err = __put_user(kfl->l_type, &ufl->l_type); + err |= __put_user(kfl->l_whence, &ufl->l_whence); + err |= __put_user(kfl->l_start, &ufl->l_start); + err |= __put_user(kfl->l_len, &ufl->l_len); + err |= __put_user(kfl->l_pid, &ufl->l_pid); + return err; +} + extern asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg); asmlinkage long sys32_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg) @@ -907,7 +931,61 @@ old_fs = get_fs(); set_fs (KERNEL_DS); ret = sys_fcntl(fd, cmd, (unsigned long)&f); set_fs (old_fs); + if (f.l_start >= 0x7fffffffUL || + f.l_len >= 0x7fffffffUL || + f.l_start + f.l_len >= 0x7fffffffUL) + return -EOVERFLOW; if(put_flock(&f, (struct flock32 *)arg)) + return -EFAULT; + return ret; + } + case F_GETLK64: + case F_SETLK64: + case F_SETLKW64: + return -EINVAL; + default: + return sys_fcntl(fd, cmd, (unsigned long)arg); + } +} + +asmlinkage long sys32_fcntl64(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + switch (cmd) { + case F_GETLK: + case F_SETLK: + case F_SETLKW: + { + struct flock f; + mm_segment_t old_fs; + long ret; + + if(get_flock(&f, (struct flock32 *)arg)) + return -EFAULT; + old_fs = get_fs(); set_fs (KERNEL_DS); + ret = sys_fcntl(fd, cmd, (unsigned long)&f); + set_fs (old_fs); + if (f.l_start >= 0x7fffffffUL || + f.l_len >= 0x7fffffffUL || + f.l_start + f.l_len >= 0x7fffffffUL) + return -EOVERFLOW; + if(put_flock(&f, (struct flock32 *)arg)) + return -EFAULT; + return ret; + } + case F_GETLK64: + case F_SETLK64: + case F_SETLKW64: + { + struct flock f; + mm_segment_t old_fs; + long ret; + + if(get_flock64(&f, (struct flock32_64 *)arg)) + return -EFAULT; + old_fs = get_fs(); set_fs (KERNEL_DS); + ret = sys_fcntl(fd, cmd + F_GETLK - F_GETLK64, (unsigned long)&f); + set_fs (old_fs); + if(put_flock64(&f, (struct flock32_64 *)arg)) return -EFAULT; return ret; } diff -urN aa/arch/sparc64/kernel/systbls.S lfs/arch/sparc64/kernel/systbls.S --- aa/arch/sparc64/kernel/systbls.S Tue Apr 18 16:12:15 2000 +++ lfs/arch/sparc64/kernel/systbls.S Fri Apr 21 16:52:57 2000 @@ -45,7 +45,7 @@ .word sys_getgroups, sys32_gettimeofday, sys32_getrusage, sys_nis_syscall, sys_getcwd /*120*/ .word sys32_readv, sys32_writev, sys32_settimeofday, sys32_fchown16, sys_fchmod .word sys_nis_syscall, sys32_setreuid16, sys32_setregid16, sys_rename, sys_truncate -/*130*/ .word sys_ftruncate, sys_flock, sys_lstat64, sys_nis_syscall, sys_nis_syscall +/*130*/ .word sys_ftruncate, sys_flock, sys_lstat64, sys32_fcntl64, sys_nis_syscall .word sys_nis_syscall, sys_mkdir, sys_rmdir, sys32_utimes, sys_stat64 /*140*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getrlimit .word sys32_setrlimit, sys_pivot_root, sys32_prctl, sys32_pciconfig_read, sys32_pciconfig_write diff -urN aa/fs/fcntl.c lfs/fs/fcntl.c --- aa/fs/fcntl.c Fri Apr 21 16:33:09 2000 +++ lfs/fs/fcntl.c Fri Apr 21 16:33:18 2000 @@ -173,16 +173,11 @@ return 0; } -asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - struct file * filp; - long err = -EBADF; +static long do_fcntl(unsigned int fd, unsigned int cmd, + unsigned long arg, struct file * filp) +{ + long err = 0; - filp = fget(fd); - if (!filp) - goto out; - err = 0; - lock_kernel(); switch (cmd) { case F_DUPFD: err = -EINVAL; @@ -215,6 +210,7 @@ case F_SETLKW: err = fcntl_setlk(fd, cmd, (struct flock *) arg); break; + case F_GETOWN: /* * XXX If f_owner is a process group, the @@ -251,11 +247,60 @@ err = sock_fcntl (filp, cmd, arg); break; } + + return err; +} + +asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct file * filp; + long err = -EBADF; + + filp = fget(fd); + if (!filp) + goto out; + + lock_kernel(); + err = do_fcntl(fd, cmd, arg, filp); + unlock_kernel(); + fput(filp); +out: + return err; +} + +#if BITS_PER_LONG == 32 +asmlinkage long sys_fcntl64(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct file * filp; + long err; + + err = -EBADF; + filp = fget(fd); + if (!filp) + goto out; + + lock_kernel(); + switch (cmd) { + case F_GETLK64: + err = fcntl_getlk64(fd, (struct flock64 *) arg); + break; + case F_SETLK64: + err = fcntl_setlk64(fd, cmd, (struct flock64 *) arg); + break; + case F_SETLKW64: + err = fcntl_setlk64(fd, cmd, (struct flock64 *) arg); + break; + default: + err = do_fcntl(fd, cmd, arg, filp); + break; + } unlock_kernel(); + fput(filp); out: return err; } +#endif /* Table to convert sigio signal codes into poll band bitmaps */ diff -urN aa/fs/locks.c lfs/fs/locks.c --- aa/fs/locks.c Fri Apr 21 16:33:09 2000 +++ lfs/fs/locks.c Fri Apr 21 16:33:18 2000 @@ -114,7 +114,7 @@ static int flock_make_lock(struct file *filp, struct file_lock *fl, unsigned int cmd); static int posix_make_lock(struct file *filp, struct file_lock *fl, - struct flock *l); + struct flock64 *l); static int flock_locks_conflict(struct file_lock *caller_fl, struct file_lock *sys_fl); static int posix_locks_conflict(struct file_lock *caller_fl, @@ -321,11 +321,16 @@ { struct file *filp; struct file_lock *fl,file_lock; - struct flock flock; + struct flock64 flock; int error; error = -EFAULT; - if (copy_from_user(&flock, l, sizeof(flock))) + if (verify_area(VERIFY_READ, l, sizeof(*l)) + || __get_user(flock.l_type, &l->l_type) + || __get_user(flock.l_whence, &l->l_whence) + || __get_user(flock.l_start, &l->l_start) + || __get_user(flock.l_len, &l->l_len) + || __get_user(flock.l_pid, &l->l_pid)) goto out; error = -EINVAL; if ((flock.l_type != F_RDLCK) && (flock.l_type != F_WRLCK)) @@ -336,6 +341,7 @@ if (!filp) goto out; + error = -EINVAL; if (!posix_make_lock(filp, &file_lock, &flock)) goto out_putf; @@ -361,9 +367,24 @@ flock.l_whence = 0; flock.l_type = fl->fl_type; } - error = -EFAULT; - if (!copy_to_user(l, &flock, sizeof(flock))) - error = 0; + + /* Convert to 32-bit offsets (at 32-bit systems) */ + + if (!off_t_presentable(flock.l_start) || + !off_t_presentable(flock.l_len) || + !off_t_presentable(flock.l_start + flock.l_len)) { + error = -EOVERFLOW; + goto out_putf; + } + + error = 0; + if (verify_area(VERIFY_WRITE, l, sizeof(*l)) + || __put_user(flock.l_type, &l->l_type) + || __put_user(flock.l_whence, &l->l_whence) + || __put_user(flock.l_start, &l->l_start) + || __put_user(flock.l_len, &l->l_len) + || __put_user(flock.l_pid, &l->l_pid)) + error = -EFAULT; out_putf: fput(filp); @@ -378,7 +399,7 @@ { struct file *filp; struct file_lock file_lock; - struct flock flock; + struct flock64 flock; struct inode *inode; int error; @@ -386,7 +407,12 @@ * This might block, so we do it before checking the inode. */ error = -EFAULT; - if (copy_from_user(&flock, l, sizeof(flock))) + if (verify_area(VERIFY_READ, l, sizeof(*l)) + || __get_user(flock.l_type, &l->l_type) + || __get_user(flock.l_whence, &l->l_whence) + || __get_user(flock.l_start, &l->l_start) + || __get_user(flock.l_len, &l->l_len) + || __get_user(flock.l_pid, &l->l_pid)) goto out; /* Get arguments and validate them ... @@ -469,6 +495,149 @@ return error; } +#if BITS_PER_LONG == 32 +/* Report the first existing lock that would conflict with l. + * This implements the F_GETLK command of fcntl(). + */ +int fcntl_getlk64(unsigned int fd, struct flock64 *l) +{ + struct file *filp; + struct file_lock *fl,file_lock; + struct flock64 flock; + int error; + + error = -EFAULT; + if (copy_from_user(&flock, l, sizeof(flock))) + goto out; + error = -EINVAL; + if ((flock.l_type != F_RDLCK) && (flock.l_type != F_WRLCK)) + goto out; + + error = -EBADF; + filp = fget(fd); + if (!filp) + goto out; + + error = -EINVAL; + if (!posix_make_lock(filp, &file_lock, &flock)) + goto out_putf; + + if (filp->f_op->lock) { + error = filp->f_op->lock(filp, F_GETLK, &file_lock); + if (error < 0) + goto out_putf; + else if (error == LOCK_USE_CLNT) + /* Bypass for NFS with no locking - 2.0.36 compat */ + fl = posix_test_lock(filp, &file_lock); + else + fl = (file_lock.fl_type == F_UNLCK ? NULL : &file_lock); + } else { + fl = posix_test_lock(filp, &file_lock); + } + + flock.l_type = F_UNLCK; + if (fl != NULL) { + flock.l_pid = fl->fl_pid; + flock.l_start = fl->fl_start; + flock.l_len = fl->fl_end == OFFSET_MAX ? 0 : + fl->fl_end - fl->fl_start + 1; + flock.l_whence = 0; + flock.l_type = fl->fl_type; + } + error = -EFAULT; + if (!copy_to_user(l, &flock, sizeof(flock))) + error = 0; + +out_putf: + fput(filp); +out: + return error; +} + +/* Apply the lock described by l to an open file descriptor. + * This implements both the F_SETLK and F_SETLKW commands of fcntl(). + */ +int fcntl_setlk64(unsigned int fd, unsigned int cmd, struct flock64 *l) +{ + struct file *filp; + struct file_lock file_lock; + struct flock64 flock; + struct inode *inode; + int error; + + /* + * This might block, so we do it before checking the inode. + */ + error = -EFAULT; + if (copy_from_user(&flock, l, sizeof(flock))) + goto out; + + /* Get arguments and validate them ... + */ + + error = -EBADF; + filp = fget(fd); + if (!filp) + goto out; + + error = -EINVAL; + inode = filp->f_dentry->d_inode; + + /* Don't allow mandatory locks on files that may be memory mapped + * and shared. + */ + if (IS_MANDLOCK(inode) && + (inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) { + struct vm_area_struct *vma; + struct address_space *mapping = inode->i_mapping; + spin_lock(&mapping->i_shared_lock); + for(vma = mapping->i_mmap;vma;vma = vma->vm_next_share) { + if (!(vma->vm_flags & VM_MAYSHARE)) + continue; + spin_unlock(&mapping->i_shared_lock); + error = -EAGAIN; + goto out_putf; + } + spin_unlock(&mapping->i_shared_lock); + } + + error = -EINVAL; + if (!posix_make_lock(filp, &file_lock, &flock)) + goto out_putf; + + error = -EBADF; + switch (flock.l_type) { + case F_RDLCK: + if (!(filp->f_mode & FMODE_READ)) + goto out_putf; + break; + case F_WRLCK: + if (!(filp->f_mode & FMODE_WRITE)) + goto out_putf; + break; + case F_UNLCK: + break; + case F_SHLCK: + case F_EXLCK: + default: + error = -EINVAL; + goto out_putf; + } + + if (filp->f_op->lock != NULL) { + error = filp->f_op->lock(filp, cmd, &file_lock); + if (error < 0) + goto out_putf; + } + error = posix_lock_file(filp, &file_lock, cmd == F_SETLKW); + +out_putf: + fput(filp); +out: + return error; +} +#endif /* BITS_PER_LONG == 32 */ + /* * This function is called when the file is being removed * from the task's fd array. @@ -638,7 +807,7 @@ * style lock. */ static int posix_make_lock(struct file *filp, struct file_lock *fl, - struct flock *l) + struct flock64 *l) { loff_t start; diff -urN aa/include/asm-alpha/fcntl.h lfs/include/asm-alpha/fcntl.h --- aa/include/asm-alpha/fcntl.h Fri Apr 21 16:33:09 2000 +++ lfs/include/asm-alpha/fcntl.h Fri Apr 21 16:33:18 2000 @@ -63,4 +63,8 @@ __kernel_pid_t l_pid; }; +#ifdef __KERNEL__ +#define flock64 flock +#endif + #endif diff -urN aa/include/asm-i386/fcntl.h lfs/include/asm-i386/fcntl.h --- aa/include/asm-i386/fcntl.h Fri Apr 21 16:33:09 2000 +++ lfs/include/asm-i386/fcntl.h Fri Apr 21 16:33:18 2000 @@ -35,6 +35,10 @@ #define F_SETSIG 10 /* for sockets. */ #define F_GETSIG 11 /* for sockets. */ +#define F_GETLK64 12 /* using 'struct flock64' */ +#define F_SETLK64 13 +#define F_SETLKW64 14 + /* for F_[GET|SET]FL */ #define FD_CLOEXEC 1 /* actually anything with low bit set goes */ @@ -60,6 +64,14 @@ off_t l_start; off_t l_len; pid_t l_pid; +}; + +struct flock64 { + short l_type; + short l_whence; + loff_t l_start; + loff_t l_len; + pid_t l_pid; }; #endif diff -urN aa/include/asm-m68k/fcntl.h lfs/include/asm-m68k/fcntl.h --- aa/include/asm-m68k/fcntl.h Fri Apr 21 16:33:09 2000 +++ lfs/include/asm-m68k/fcntl.h Fri Apr 21 16:33:18 2000 @@ -35,6 +35,10 @@ #define F_SETSIG 10 /* for sockets. */ #define F_GETSIG 11 /* for sockets. */ +#define F_GETLK64 12 /* using 'struct flock64' */ +#define F_SETLK64 13 +#define F_SETLKW64 14 + /* for F_[GET|SET]FL */ #define FD_CLOEXEC 1 /* actually anything with low bit set goes */ @@ -60,6 +64,14 @@ off_t l_start; off_t l_len; pid_t l_pid; +}; + +struct flock64 { + short l_type; + short l_whence; + loff_t l_start; + loff_t l_len; + pid_t l_pid; }; #endif /* _M68K_FCNTL_H */ diff -urN aa/include/asm-mips/fcntl.h lfs/include/asm-mips/fcntl.h --- aa/include/asm-mips/fcntl.h Fri Apr 21 16:33:09 2000 +++ lfs/include/asm-mips/fcntl.h Fri Apr 21 16:33:18 2000 @@ -44,6 +44,10 @@ #define F_SETSIG 10 /* for sockets. */ #define F_GETSIG 11 /* for sockets. */ +#define F_GETLK64 33 /* using 'struct flock64' */ +#define F_SETLK64 34 +#define F_SETLKW64 35 + /* for F_[GET|SET]FL */ #define FD_CLOEXEC 1 /* actually anything with low bit set goes */ @@ -72,5 +76,13 @@ __kernel_pid_t l_pid; long pad[4]; /* ZZZZZZZZZZZZZZZZZZZZZZZZZZ */ } flock_t; + +typedef struct flock64 { + short l_type; + short l_whence; + loff_t l_start; + loff_t l_len; + pid_t l_pid; +} flock64_t; #endif /* __ASM_MIPS_FCNTL_H */ diff -urN aa/include/asm-mips64/fcntl.h lfs/include/asm-mips64/fcntl.h --- aa/include/asm-mips64/fcntl.h Fri Apr 21 16:33:09 2000 +++ lfs/include/asm-mips64/fcntl.h Fri Apr 21 16:33:18 2000 @@ -73,4 +73,8 @@ long pad[4]; /* ZZZZZZZZZZZZZZZZZZZZZZZZZZ */ } flock_t; +#ifdef __KERNEL__ +#define flock64 flock +#endif + #endif /* _ASM_FCNTL_H */ diff -urN aa/include/asm-ppc/fcntl.h lfs/include/asm-ppc/fcntl.h --- aa/include/asm-ppc/fcntl.h Fri Apr 21 16:33:09 2000 +++ lfs/include/asm-ppc/fcntl.h Fri Apr 21 16:33:18 2000 @@ -35,6 +35,10 @@ #define F_SETSIG 10 /* for sockets. */ #define F_GETSIG 11 /* for sockets. */ +#define F_GETLK64 12 /* using 'struct flock64' */ +#define F_SETLK64 13 +#define F_SETLKW64 14 + /* for F_[GET|SET]FL */ #define FD_CLOEXEC 1 /* actually anything with low bit set goes */ @@ -66,6 +70,14 @@ off_t l_start; off_t l_len; pid_t l_pid; +}; + +struct flock64 { + short l_type; + short l_whence; + loff_t l_start; + loff_t l_len; + pid_t l_pid; }; #endif diff -urN aa/include/asm-sparc/fcntl.h lfs/include/asm-sparc/fcntl.h --- aa/include/asm-sparc/fcntl.h Fri Apr 21 16:33:09 2000 +++ lfs/include/asm-sparc/fcntl.h Fri Apr 21 16:33:18 2000 @@ -33,6 +33,9 @@ #define F_SETLKW 9 #define F_SETSIG 10 /* for sockets. */ #define F_GETSIG 11 /* for sockets. */ +#define F_GETLK64 12 +#define F_SETLK64 13 +#define F_SETLKW64 14 /* for F_[GET|SET]FL */ #define FD_CLOEXEC 1 /* actually anything with low bit set goes */ @@ -58,6 +61,15 @@ short l_whence; off_t l_start; off_t l_len; + pid_t l_pid; + short __unused; +}; + +struct flock64 { + short l_type; + short l_whence; + loff_t l_start; + loff_t l_len; pid_t l_pid; short __unused; }; diff -urN aa/include/asm-sparc64/fcntl.h lfs/include/asm-sparc64/fcntl.h --- aa/include/asm-sparc64/fcntl.h Fri Apr 21 16:33:09 2000 +++ lfs/include/asm-sparc64/fcntl.h Fri Apr 21 16:33:18 2000 @@ -33,6 +33,11 @@ #define F_SETLKW 9 #define F_SETSIG 10 /* for sockets. */ #define F_GETSIG 11 /* for sockets. */ +#ifdef __KERNEL__ +#define F_GETLK64 12 +#define F_SETLK64 13 +#define F_SETLKW64 14 +#endif /* for F_[GET|SET]FL */ #define FD_CLOEXEC 1 /* actually anything with low bit set goes */ @@ -71,6 +76,17 @@ __kernel_pid_t32 l_pid; short __unused; }; + +struct flock32_64 { + short l_type; + short l_whence; + __kernel_loff_t32 l_start; + __kernel_loff_t32 l_len; + __kernel_pid_t32 l_pid; + short __unused; +}; + +#define flock64 flock #endif #endif /* !(_SPARC64_FCNTL_H) */ diff -urN aa/include/linux/fs.h lfs/include/linux/fs.h --- aa/include/linux/fs.h Fri Apr 21 16:33:09 2000 +++ lfs/include/linux/fs.h Fri Apr 21 16:33:18 2000 @@ -251,6 +251,12 @@ #define touch_buffer(bh) set_bit(PG_referenced, &bh->b_page->flags) +static int off_t_presentable(loff_t) __attribute((const)); +static __inline__ int off_t_presentable(loff_t loff) +{ + return loff > 0 && loff <= (~0UL >> 1); +} + #include #include @@ -531,6 +537,9 @@ extern int fcntl_getlk(unsigned int, struct flock *); extern int fcntl_setlk(unsigned int, unsigned int, struct flock *); + +extern int fcntl_getlk64(unsigned int, struct flock64 *); +extern int fcntl_setlk64(unsigned int, unsigned int, struct flock64 *); /* fs/locks.c */ extern void locks_remove_posix(struct file *, fl_owner_t);