X-Git-Url: http://pilppa.org/gitweb/gitweb.cgi?a=blobdiff_plain;f=fs%2Flocks.c;h=f7daa5f48949c41ea02b687e1521a440387b0592;hb=6c0741fbdee5bd0f8ed13ac287c4ab18e8ba7d83;hp=29fa5da6c1170cab553b17b85eab000a2056793d;hpb=e0d21d9cca25f424f3129649be48a63c128ed42d;p=linux-2.6-omap-h63xx.git diff --git a/fs/locks.c b/fs/locks.c index 29fa5da6c11..f7daa5f4894 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -124,6 +124,7 @@ #include #include #include +#include #include #include @@ -1591,7 +1592,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(unsigned int fd, struct file *filp, unsigned int cmd, + struct flock __user *l) { struct file_lock *file_lock = locks_alloc_lock(); struct flock flock; @@ -1620,6 +1622,7 @@ int fcntl_setlk(struct file *filp, unsigned int cmd, struct flock __user *l) goto out; } +again: error = flock_to_posix_lock(filp, file_lock, &flock); if (error) goto out; @@ -1648,25 +1651,33 @@ int fcntl_setlk(struct file *filp, unsigned int cmd, struct flock __user *l) if (error) goto out; - if (filp->f_op && filp->f_op->lock != NULL) { + if (filp->f_op && filp->f_op->lock != NULL) error = filp->f_op->lock(filp, cmd, file_lock); - goto out; - } + else { + for (;;) { + error = __posix_lock_file(inode, file_lock); + if ((error != -EAGAIN) || (cmd == F_SETLK)) + break; + error = wait_event_interruptible(file_lock->fl_wait, + !file_lock->fl_next); + if (!error) + continue; - for (;;) { - error = __posix_lock_file(inode, file_lock); - if ((error != -EAGAIN) || (cmd == F_SETLK)) + locks_delete_block(file_lock); break; - error = wait_event_interruptible(file_lock->fl_wait, - !file_lock->fl_next); - if (!error) - continue; + } + } - locks_delete_block(file_lock); - break; + /* + * Attempt to detect a close/fcntl race and recover by + * releasing the lock that was just acquired. + */ + if (!error && fcheck(fd) != filp && flock.l_type != F_UNLCK) { + flock.l_type = F_UNLCK; + goto again; } - out: +out: locks_free_lock(file_lock); return error; } @@ -1724,7 +1735,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(unsigned int fd, struct file *filp, unsigned int cmd, + struct flock64 __user *l) { struct file_lock *file_lock = locks_alloc_lock(); struct flock64 flock; @@ -1753,6 +1765,7 @@ int fcntl_setlk64(struct file *filp, unsigned int cmd, struct flock64 __user *l) goto out; } +again: error = flock64_to_posix_lock(filp, file_lock, &flock); if (error) goto out; @@ -1781,22 +1794,30 @@ int fcntl_setlk64(struct file *filp, unsigned int cmd, struct flock64 __user *l) if (error) goto out; - if (filp->f_op && filp->f_op->lock != NULL) { + if (filp->f_op && filp->f_op->lock != NULL) error = filp->f_op->lock(filp, cmd, file_lock); - goto out; - } + else { + for (;;) { + error = __posix_lock_file(inode, file_lock); + if ((error != -EAGAIN) || (cmd == F_SETLK64)) + break; + error = wait_event_interruptible(file_lock->fl_wait, + !file_lock->fl_next); + if (!error) + continue; - for (;;) { - error = __posix_lock_file(inode, file_lock); - if ((error != -EAGAIN) || (cmd == F_SETLK64)) + locks_delete_block(file_lock); break; - error = wait_event_interruptible(file_lock->fl_wait, - !file_lock->fl_next); - if (!error) - continue; + } + } - locks_delete_block(file_lock); - break; + /* + * Attempt to detect a close/fcntl race and recover by + * releasing the lock that was just acquired. + */ + if (!error && fcheck(fd) != filp && flock.l_type != F_UNLCK) { + flock.l_type = F_UNLCK; + goto again; } out: @@ -1888,12 +1909,7 @@ void locks_remove_flock(struct file *filp) while ((fl = *before) != NULL) { if (fl->fl_file == filp) { - /* - * We might have a POSIX lock that was created at the same time - * the filp was closed for the last time. Just remove that too, - * regardless of ownership, since nobody can own it. - */ - if (IS_FLOCK(fl) || IS_POSIX(fl)) { + if (IS_FLOCK(fl)) { locks_delete_lock(before); continue; } @@ -2183,21 +2199,24 @@ void steal_locks(fl_owner_t from) { struct files_struct *files = current->files; int i, j; + struct fdtable *fdt; if (from == files) return; lock_kernel(); j = 0; + rcu_read_lock(); + fdt = files_fdtable(files); for (;;) { unsigned long set; i = j * __NFDBITS; - if (i >= files->max_fdset || i >= files->max_fds) + if (i >= fdt->max_fdset || i >= fdt->max_fds) break; - set = files->open_fds->fds_bits[j++]; + set = fdt->open_fds->fds_bits[j++]; while (set) { if (set & 1) { - struct file *file = files->fd[i]; + struct file *file = fdt->fd[i]; if (file) __steal_locks(file, from); } @@ -2205,6 +2224,7 @@ void steal_locks(fl_owner_t from) set >>= 1; } } + rcu_read_unlock(); unlock_kernel(); } EXPORT_SYMBOL(steal_locks);