diff -urN 2.4.0-test6/arch/i386/kernel/entry.S 2.4.0-test6-file_lock-2/arch/i386/kernel/entry.S --- 2.4.0-test6/arch/i386/kernel/entry.S Fri Aug 11 03:09:43 2000 +++ 2.4.0-test6-file_lock-2/arch/i386/kernel/entry.S Sat Aug 12 03:07:02 2000 @@ -641,6 +641,7 @@ .long SYMBOL_NAME(sys_pivot_root) .long SYMBOL_NAME(sys_mincore) .long SYMBOL_NAME(sys_madvise) + .long SYMBOL_NAME(sys_fcntl64) /* 220 */ /* @@ -649,6 +650,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 2.4.0-test6/fs/fcntl.c 2.4.0-test6-file_lock-2/fs/fcntl.c --- 2.4.0-test6/fs/fcntl.c Fri Aug 11 03:09:45 2000 +++ 2.4.0-test6-file_lock-2/fs/fcntl.c Sat Aug 12 03:07:02 2000 @@ -209,16 +209,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; @@ -287,11 +282,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 2.4.0-test6/fs/locks.c 2.4.0-test6-file_lock-2/fs/locks.c --- 2.4.0-test6/fs/locks.c Tue Jul 11 03:50:35 2000 +++ 2.4.0-test6-file_lock-2/fs/locks.c Sat Aug 12 03:17:34 2000 @@ -205,8 +205,8 @@ /* Verify a "struct flock" and copy it to a "struct file_lock" as a POSIX * style lock. */ -static int posix_make_lock(struct file *filp, struct file_lock *fl, - struct flock *l) +static int flock_to_posix_lock(struct file *filp, struct file_lock *fl, + struct flock *l) { loff_t start; @@ -254,6 +254,57 @@ return (1); } +#if BITS_PER_LONG == 32 +static int flock64_to_posix_lock(struct file *filp, struct file_lock *fl, + struct flock64 *l) +{ + loff_t start; + + switch (l->l_whence) { + case 0: /*SEEK_SET*/ + start = 0; + break; + case 1: /*SEEK_CUR*/ + start = filp->f_pos; + break; + case 2: /*SEEK_END*/ + start = filp->f_dentry->d_inode->i_size; + break; + default: + return (0); + } + + if (((start += l->l_start) < 0) || (l->l_len < 0)) + return (0); + fl->fl_end = start + l->l_len - 1; + if (l->l_len > 0 && fl->fl_end < 0) + return (0); + fl->fl_start = start; /* we record the absolute position */ + if (l->l_len == 0) + fl->fl_end = OFFSET_MAX; + + fl->fl_owner = current->files; + fl->fl_pid = current->pid; + fl->fl_file = filp; + fl->fl_flags = FL_POSIX; + fl->fl_notify = NULL; + fl->fl_insert = NULL; + fl->fl_remove = NULL; + + switch (l->l_type) { + case F_RDLCK: + case F_WRLCK: + case F_UNLCK: + fl->fl_type = l->l_type; + break; + default: + return (0); + } + + return (1); +} +#endif + /* Check if two locks overlap each other. */ static inline int locks_overlap(struct file_lock *fl1, struct file_lock *fl2) @@ -909,7 +960,8 @@ if (!filp) goto out; - if (!posix_make_lock(filp, file_lock, &flock)) + error = -EINVAL; + if (!flock_to_posix_lock(filp, file_lock, &flock)) goto out_putf; if (filp->f_op->lock) { @@ -928,8 +980,21 @@ flock.l_type = F_UNLCK; if (fl != NULL) { flock.l_pid = fl->fl_pid; +#if BITS_PER_LONG == 32 + /* + * Make sure we can represent the posix lock via + * legacy 32bit flock. + */ + error = -EOVERFLOW; + if (fl->fl_end > OFFT_OFFSET_MAX) + goto out_putf; +#endif flock.l_start = fl->fl_start; +#if BITS_PER_LONG == 32 + flock.l_len = fl->fl_end == OFFT_OFFSET_MAX ? 0 : +#else flock.l_len = fl->fl_end == OFFSET_MAX ? 0 : +#endif fl->fl_end - fl->fl_start + 1; flock.l_whence = 0; flock.l_type = fl->fl_type; @@ -993,7 +1058,7 @@ } error = -EINVAL; - if (!posix_make_lock(filp, file_lock, &flock)) + if (!flock_to_posix_lock(filp, file_lock, &flock)) goto out_putf; error = -EBADF; @@ -1043,6 +1108,151 @@ locks_free_lock(file_lock); 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 = locks_alloc_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 (!flock64_to_posix_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: + locks_free_lock(file_lock); + 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 = locks_alloc_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 (!flock64_to_posix_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: + locks_free_lock(file_lock); + return error; +} +#endif /* BITS_PER_LONG == 32 */ /* * This function is called when the file is being removed diff -urN 2.4.0-test6/fs/stat.c 2.4.0-test6-file_lock-2/fs/stat.c --- 2.4.0-test6/fs/stat.c Fri Aug 11 03:09:45 2000 +++ 2.4.0-test6-file_lock-2/fs/stat.c Sat Aug 12 03:07:02 2000 @@ -52,6 +52,10 @@ SET_OLDSTAT_UID(tmp, inode->i_uid); SET_OLDSTAT_GID(tmp, inode->i_gid); tmp.st_rdev = kdev_t_to_nr(inode->i_rdev); +#if BITS_PER_LONG == 32 + if (inode->i_size > 0x7fffffff) + return -EOVERFLOW; +#endif tmp.st_size = inode->i_size; tmp.st_atime = inode->i_atime; tmp.st_mtime = inode->i_mtime; @@ -74,6 +78,10 @@ SET_STAT_UID(tmp, inode->i_uid); SET_STAT_GID(tmp, inode->i_gid); tmp.st_rdev = kdev_t_to_nr(inode->i_rdev); +#if BITS_PER_LONG == 32 + if (inode->i_size > 0x7fffffff) + return -EOVERFLOW; +#endif tmp.st_size = inode->i_size; tmp.st_atime = inode->i_atime; tmp.st_mtime = inode->i_mtime; diff -urN 2.4.0-test6/include/asm-alpha/fcntl.h 2.4.0-test6-file_lock-2/include/asm-alpha/fcntl.h --- 2.4.0-test6/include/asm-alpha/fcntl.h Tue Jul 11 03:50:36 2000 +++ 2.4.0-test6-file_lock-2/include/asm-alpha/fcntl.h Sat Aug 12 03:07:02 2000 @@ -63,4 +63,8 @@ __kernel_pid_t l_pid; }; +#ifdef __KERNEL__ +#define flock64 flock +#endif + #endif diff -urN 2.4.0-test6/include/asm-i386/fcntl.h 2.4.0-test6-file_lock-2/include/asm-i386/fcntl.h --- 2.4.0-test6/include/asm-i386/fcntl.h Tue Jul 11 03:50:37 2000 +++ 2.4.0-test6-file_lock-2/include/asm-i386/fcntl.h Sat Aug 12 03:07:02 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 2.4.0-test6/include/asm-i386/unistd.h 2.4.0-test6-file_lock-2/include/asm-i386/unistd.h --- 2.4.0-test6/include/asm-i386/unistd.h Wed Mar 15 16:45:13 2000 +++ 2.4.0-test6-file_lock-2/include/asm-i386/unistd.h Sat Aug 12 03:07:02 2000 @@ -225,6 +225,7 @@ #define __NR_mincore 218 #define __NR_madvise 219 #define __NR_madvise1 219 /* delete when C lib stub is removed */ +#define __NR_fcntl64 220 /* user-visible error numbers are in the range -1 - -124: see */ diff -urN 2.4.0-test6/include/linux/fs.h 2.4.0-test6-file_lock-2/include/linux/fs.h --- 2.4.0-test6/include/linux/fs.h Fri Aug 11 03:09:45 2000 +++ 2.4.0-test6-file_lock-2/include/linux/fs.h Sat Aug 12 03:24:34 2000 @@ -535,6 +535,7 @@ #ifndef OFFSET_MAX #define INT_LIMIT(x) (~((x)1 << (sizeof(x)*8 - 1))) #define OFFSET_MAX INT_LIMIT(loff_t) +#define OFFT_OFFSET_MAX INT_LIMIT(off_t) #endif extern struct list_head file_lock_list; @@ -543,6 +544,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);