Name: Detect POSIX Lock Surprises Status: Booted on 2.6.7-rc3-bk7 POSIX locks vanish whenever you close any file descriptor which has the file open, ie: fd1 = open("file", O_RDONLY); fcntl(fd1, F_SETLKW, &lock); fd2 = open("file", O_RDONLY); close(fd2); /* Lock is gone... */ Warn whenever a lock is removed due to fd close on an fd other than the one it was opened on. diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .11897-linux-2.6.7-rc3-bk7/drivers/usb/gadget/file_storage.c .11897-linux-2.6.7-rc3-bk7.updated/drivers/usb/gadget/file_storage.c --- .11897-linux-2.6.7-rc3-bk7/drivers/usb/gadget/file_storage.c 2004-06-08 09:48:58.000000000 +1000 +++ .11897-linux-2.6.7-rc3-bk7.updated/drivers/usb/gadget/file_storage.c 2004-06-16 12:03:14.000000000 +1000 @@ -3490,7 +3490,7 @@ static int NORMALLY_INIT open_backing_fi rc = 0; out: - filp_close(filp, current->files); + filp_close(filp, current->files, -1); return rc; } diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .11897-linux-2.6.7-rc3-bk7/fs/autofs4/root.c .11897-linux-2.6.7-rc3-bk7.updated/fs/autofs4/root.c --- .11897-linux-2.6.7-rc3-bk7/fs/autofs4/root.c 2004-06-08 09:49:02.000000000 +1000 +++ .11897-linux-2.6.7-rc3-bk7.updated/fs/autofs4/root.c 2004-06-16 12:03:14.000000000 +1000 @@ -242,7 +242,7 @@ static int autofs4_dir_close(struct inod if (!fp) return -ENOENT; - filp_close(fp, current->files); + filp_close(fp, current->files, -1); file->private_data = NULL; } out: diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .11897-linux-2.6.7-rc3-bk7/fs/dquot.c .11897-linux-2.6.7-rc3-bk7.updated/fs/dquot.c --- .11897-linux-2.6.7-rc3-bk7/fs/dquot.c 2004-06-08 09:49:03.000000000 +1000 +++ .11897-linux-2.6.7-rc3-bk7.updated/fs/dquot.c 2004-06-16 12:03:14.000000000 +1000 @@ -1458,7 +1458,7 @@ int vfs_quota_on(struct super_block *sb, if (!error) return 0; out_f: - filp_close(f, NULL); + filp_close(f, NULL, -1); return error; } diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .11897-linux-2.6.7-rc3-bk7/fs/exec.c .11897-linux-2.6.7-rc3-bk7.updated/fs/exec.c --- .11897-linux-2.6.7-rc3-bk7/fs/exec.c 2004-06-08 09:49:03.000000000 +1000 +++ .11897-linux-2.6.7-rc3-bk7.updated/fs/exec.c 2004-06-16 12:03:14.000000000 +1000 @@ -1391,7 +1391,7 @@ int do_coredump(long signr, int exit_cod current->signal->group_exit_code |= 0x80; close_fail: - filp_close(file, NULL); + filp_close(file, NULL, -1); fail_unlock: complete_all(&mm->core_done); fail: diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .11897-linux-2.6.7-rc3-bk7/fs/fcntl.c .11897-linux-2.6.7-rc3-bk7.updated/fs/fcntl.c --- .11897-linux-2.6.7-rc3-bk7/fs/fcntl.c 2004-06-08 09:49:03.000000000 +1000 +++ .11897-linux-2.6.7-rc3-bk7.updated/fs/fcntl.c 2004-06-16 12:03:14.000000000 +1000 @@ -188,7 +188,7 @@ asmlinkage long sys_dup2(unsigned int ol spin_unlock(&files->file_lock); if (tofree) - filp_close(tofree, files); + filp_close(tofree, files, newfd); err = newfd; out: return err; @@ -310,7 +310,7 @@ long generic_file_fcntl(int fd, unsigned break; case F_SETLK: case F_SETLKW: - err = fcntl_setlk(filp, cmd, (struct flock __user *) arg); + err = fcntl_setlk(filp, cmd, (struct flock __user *) arg, fd); break; case F_GETOWN: /* @@ -407,7 +407,7 @@ asmlinkage long sys_fcntl64(unsigned int break; case F_SETLK64: case F_SETLKW64: - err = fcntl_setlk64(filp, cmd, (struct flock64 __user *) arg); + err = fcntl_setlk64(filp, cmd, (struct flock64 __user *) arg, fd); break; default: err = do_fcntl(fd, cmd, arg, filp); diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .11897-linux-2.6.7-rc3-bk7/fs/locks.c .11897-linux-2.6.7-rc3-bk7.updated/fs/locks.c --- .11897-linux-2.6.7-rc3-bk7/fs/locks.c 2004-06-08 09:49:04.000000000 +1000 +++ .11897-linux-2.6.7-rc3-bk7.updated/fs/locks.c 2004-06-16 12:08:48.000000000 +1000 @@ -221,6 +221,7 @@ void locks_copy_lock(struct file_lock *n new->fl_insert = fl->fl_insert; new->fl_remove = fl->fl_remove; new->fl_u = fl->fl_u; + new->fl_origfd = fl->fl_origfd; } EXPORT_SYMBOL(locks_copy_lock); @@ -850,6 +851,7 @@ static int __posix_lock_file(struct inod fl->fl_end = request->fl_end; fl->fl_type = request->fl_type; fl->fl_u = request->fl_u; + fl->fl_origfd = request->fl_origfd; request = fl; added = 1; } @@ -1430,7 +1432,8 @@ out: /* 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_setlk(struct file *filp, unsigned int cmd, struct flock __user *l) +int fcntl_setlk(struct file *filp, unsigned int cmd, struct flock __user *l, + int fd) { struct file_lock *file_lock = locks_alloc_lock(); struct flock flock; @@ -1462,6 +1465,7 @@ int fcntl_setlk(struct file *filp, unsig error = flock_to_posix_lock(filp, file_lock, &flock); if (error) goto out; + file_lock->fl_origfd = fd; if (cmd == F_SETLKW) { file_lock->fl_flags |= FL_SLEEP; } @@ -1565,7 +1569,8 @@ out: /* 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(struct file *filp, unsigned int cmd, struct flock64 __user *l) +int fcntl_setlk64(struct file *filp, unsigned int cmd, struct flock64 __user *l, + int fd) { struct file_lock *file_lock = locks_alloc_lock(); struct flock64 flock; @@ -1600,6 +1605,8 @@ int fcntl_setlk64(struct file *filp, uns if (cmd == F_SETLKW64) { file_lock->fl_flags |= FL_SLEEP; } + + file_lock->fl_origfd = fd; error = -EBADF; switch (flock.l_type) { @@ -1652,7 +1659,7 @@ out: * from the task's fd array. POSIX locks belonging to this task * are deleted at this time. */ -void locks_remove_posix(struct file *filp, fl_owner_t owner) +void locks_remove_posix(struct file *filp, fl_owner_t owner, int fd) { struct file_lock lock, **before; @@ -1685,6 +1692,11 @@ void locks_remove_posix(struct file *fil while (*before != NULL) { struct file_lock *fl = *before; if (IS_POSIX(fl) && (fl->fl_owner == owner)) { + if (fd != -1 && fl->fl_origfd != fd) + printk("close(%i) unlocks %s %i(%lli:%lli) %s\n", + fd, filp->f_dentry->d_name.name, + fl->fl_origfd, fl->fl_start, fl->fl_end, + current->comm); locks_delete_lock(before); continue; } diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .11897-linux-2.6.7-rc3-bk7/fs/open.c .11897-linux-2.6.7-rc3-bk7.updated/fs/open.c --- .11897-linux-2.6.7-rc3-bk7/fs/open.c 2004-06-08 09:49:04.000000000 +1000 +++ .11897-linux-2.6.7-rc3-bk7.updated/fs/open.c 2004-06-16 12:03:14.000000000 +1000 @@ -986,7 +986,7 @@ asmlinkage long sys_creat(const char __u * "id" is the POSIX thread ID. We use the * files pointer for this.. */ -int filp_close(struct file *filp, fl_owner_t id) +int filp_close(struct file *filp, fl_owner_t id, int fd) { int retval; @@ -1007,7 +1007,7 @@ int filp_close(struct file *filp, fl_own } dnotify_flush(filp, id); - locks_remove_posix(filp, id); + locks_remove_posix(filp, id, fd); fput(filp); return retval; } @@ -1034,7 +1034,7 @@ asmlinkage long sys_close(unsigned int f FD_CLR(fd, files->close_on_exec); __put_unused_fd(files, fd); spin_unlock(&files->file_lock); - return filp_close(filp, files); + return filp_close(filp, files, fd); out_unlock: spin_unlock(&files->file_lock); diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .11897-linux-2.6.7-rc3-bk7/fs/reiserfs/journal.c .11897-linux-2.6.7-rc3-bk7.updated/fs/reiserfs/journal.c --- .11897-linux-2.6.7-rc3-bk7/fs/reiserfs/journal.c 2004-06-08 09:49:05.000000000 +1000 +++ .11897-linux-2.6.7-rc3-bk7.updated/fs/reiserfs/journal.c 2004-06-16 12:03:14.000000000 +1000 @@ -2163,7 +2163,7 @@ static int release_journal_dev( struct s result = 0; if( journal -> j_dev_file != NULL ) { - result = filp_close( journal -> j_dev_file, NULL ); + result = filp_close( journal -> j_dev_file, NULL, -1 ); journal -> j_dev_file = NULL; journal -> j_dev_bd = NULL; } else if( journal -> j_dev_bd != NULL ) { diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .11897-linux-2.6.7-rc3-bk7/include/linux/fs.h .11897-linux-2.6.7-rc3-bk7.updated/include/linux/fs.h --- .11897-linux-2.6.7-rc3-bk7/include/linux/fs.h 2004-06-08 09:49:14.000000000 +1000 +++ .11897-linux-2.6.7-rc3-bk7.updated/include/linux/fs.h 2004-06-16 12:03:14.000000000 +1000 @@ -631,6 +631,7 @@ struct file_lock { struct file *fl_file; unsigned char fl_flags; unsigned char fl_type; + int fl_origfd; loff_t fl_start; loff_t fl_end; @@ -661,11 +662,11 @@ extern long generic_file_fcntl(int fd, u unsigned long arg, struct file *filp); extern int fcntl_getlk(struct file *, struct flock __user *); -extern int fcntl_setlk(struct file *, unsigned int, struct flock __user *); +extern int fcntl_setlk(struct file *, unsigned int, struct flock __user *, int); #if BITS_PER_LONG == 32 extern int fcntl_getlk64(struct file *, struct flock64 __user *); -extern int fcntl_setlk64(struct file *, unsigned int, struct flock64 __user *); +extern int fcntl_setlk64(struct file *, unsigned int, struct flock64 __user *, int); #endif extern void send_sigio(struct fown_struct *fown, int fd, int band); @@ -675,7 +676,7 @@ extern int fcntl_getlease(struct file *f /* fs/locks.c */ extern void locks_init_lock(struct file_lock *); extern void locks_copy_lock(struct file_lock *, struct file_lock *); -extern void locks_remove_posix(struct file *, fl_owner_t); +extern void locks_remove_posix(struct file *, fl_owner_t, int); extern void locks_remove_flock(struct file *); extern struct file_lock *posix_test_lock(struct file *, struct file_lock *); extern int posix_lock_file(struct file *, struct file_lock *); @@ -1195,7 +1196,7 @@ static inline int break_lease(struct ino extern int do_truncate(struct dentry *, loff_t start); extern struct file *filp_open(const char *, int, int); extern struct file * dentry_open(struct dentry *, struct vfsmount *, int); -extern int filp_close(struct file *, fl_owner_t id); +extern int filp_close(struct file *, fl_owner_t id, int fd); extern char * getname(const char __user *); /* fs/dcache.c */ diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .11897-linux-2.6.7-rc3-bk7/kernel/acct.c .11897-linux-2.6.7-rc3-bk7.updated/kernel/acct.c --- .11897-linux-2.6.7-rc3-bk7/kernel/acct.c 2004-06-08 09:49:18.000000000 +1000 +++ .11897-linux-2.6.7-rc3-bk7.updated/kernel/acct.c 2004-06-16 12:03:14.000000000 +1000 @@ -193,7 +193,7 @@ void acct_file_reopen(struct file *file) if (old_acct) { spin_unlock(&acct_globals.lock); do_acct_process(0, old_acct); - filp_close(old_acct, NULL); + filp_close(old_acct, NULL, -1); spin_lock(&acct_globals.lock); } } @@ -225,12 +225,12 @@ asmlinkage long sys_acct(const char __us return (PTR_ERR(file)); } if (!S_ISREG(file->f_dentry->d_inode->i_mode)) { - filp_close(file, NULL); + filp_close(file, NULL, -1); return (-EACCES); } if (!file->f_op->write) { - filp_close(file, NULL); + filp_close(file, NULL, -1); return (-EIO); } } @@ -238,7 +238,7 @@ asmlinkage long sys_acct(const char __us error = security_acct(file); if (error) { if (file) - filp_close(file, NULL); + filp_close(file, NULL, -1); return error; } diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .11897-linux-2.6.7-rc3-bk7/kernel/exit.c .11897-linux-2.6.7-rc3-bk7.updated/kernel/exit.c --- .11897-linux-2.6.7-rc3-bk7/kernel/exit.c 2004-06-16 08:17:15.000000000 +1000 +++ .11897-linux-2.6.7-rc3-bk7.updated/kernel/exit.c 2004-06-16 12:03:14.000000000 +1000 @@ -379,7 +379,7 @@ static inline void close_files(struct fi if (set & 1) { struct file * file = xchg(&files->fd[i], NULL); if (file) - filp_close(file, files); + filp_close(file, files, -1); } i++; set >>= 1; diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .11897-linux-2.6.7-rc3-bk7/mm/swapfile.c .11897-linux-2.6.7-rc3-bk7.updated/mm/swapfile.c --- .11897-linux-2.6.7-rc3-bk7/mm/swapfile.c 2004-06-08 09:49:18.000000000 +1000 +++ .11897-linux-2.6.7-rc3-bk7.updated/mm/swapfile.c 2004-06-16 12:03:14.000000000 +1000 @@ -1165,11 +1165,11 @@ asmlinkage long sys_swapoff(const char _ } else { up(&mapping->host->i_sem); } - filp_close(swap_file, NULL); + filp_close(swap_file, NULL, -1); err = 0; out_dput: - filp_close(victim, NULL); + filp_close(victim, NULL, -1); out: return err; } @@ -1545,7 +1545,7 @@ bad_swap_2: if (swap_map) vfree(swap_map); if (swap_file) - filp_close(swap_file, NULL); + filp_close(swap_file, NULL, -1); out: if (page && !IS_ERR(page)) { kunmap(page); diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .11897-linux-2.6.7-rc3-bk7/sound/sound_firmware.c .11897-linux-2.6.7-rc3-bk7.updated/sound/sound_firmware.c --- .11897-linux-2.6.7-rc3-bk7/sound/sound_firmware.c 2003-09-22 09:48:23.000000000 +1000 +++ .11897-linux-2.6.7-rc3-bk7.updated/sound/sound_firmware.c 2004-06-16 12:03:14.000000000 +1000 @@ -22,14 +22,14 @@ static int do_mod_firmware_load(const ch if (l <= 0 || l > 131072) { printk(KERN_INFO "Invalid firmware '%s'\n", fn); - filp_close(filp, current->files); + filp_close(filp, current->files, -1); return 0; } dp = vmalloc(l); if (dp == NULL) { printk(KERN_INFO "Out of memory loading '%s'.\n", fn); - filp_close(filp, current->files); + filp_close(filp, current->files, -1); return 0; } pos = 0; @@ -37,10 +37,10 @@ static int do_mod_firmware_load(const ch { printk(KERN_INFO "Failed to read '%s'.\n", fn); vfree(dp); - filp_close(filp, current->files); + filp_close(filp, current->files, -1); return 0; } - filp_close(filp, current->files); + filp_close(filp, current->files, -1); *fp = dp; return (int) l; }