X-Git-Url: http://pilppa.org/gitweb/gitweb.cgi?a=blobdiff_plain;f=fs%2Flocks.c;h=efad798824dc19913b7aace09dbee47b8c6ca6a7;hb=99532559dc7a8e686b2cef14c780a7ad5dbd4a31;hp=56f996e98bbcd03459480ce9ea505e2663b46129;hpb=3661f00e2097676847deb01add1a0918044bd816;p=linux-2.6-omap-h63xx.git diff --git a/fs/locks.c b/fs/locks.c index 56f996e98bb..efad798824d 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -142,7 +142,7 @@ int lease_break_time = 45; static LIST_HEAD(file_lock_list); static LIST_HEAD(blocked_list); -static kmem_cache_t *filelock_cache; +static kmem_cache_t *filelock_cache __read_mostly; /* Allocate an empty lock structure. */ static struct file_lock *locks_alloc_lock(void) @@ -168,18 +168,9 @@ static void locks_release_private(struct file_lock *fl) /* Free a lock which is not in use. */ static void locks_free_lock(struct file_lock *fl) { - if (fl == NULL) { - BUG(); - return; - } - if (waitqueue_active(&fl->fl_wait)) - panic("Attempting to free lock with active wait queue"); - - if (!list_empty(&fl->fl_block)) - panic("Attempting to free lock with active block list"); - - if (!list_empty(&fl->fl_link)) - panic("Attempting to free lock on active lock list"); + BUG_ON(waitqueue_active(&fl->fl_wait)); + BUG_ON(!list_empty(&fl->fl_block)); + BUG_ON(!list_empty(&fl->fl_link)); locks_release_private(fl); kmem_cache_free(filelock_cache, fl); @@ -533,12 +524,7 @@ static void locks_delete_block(struct file_lock *waiter) static void locks_insert_block(struct file_lock *blocker, struct file_lock *waiter) { - if (!list_empty(&waiter->fl_block)) { - printk(KERN_ERR "locks_insert_block: removing duplicated lock " - "(pid=%d %Ld-%Ld type=%d)\n", waiter->fl_pid, - waiter->fl_start, waiter->fl_end, waiter->fl_type); - __locks_delete_block(waiter); - } + BUG_ON(!list_empty(&waiter->fl_block)); list_add_tail(&waiter->fl_block, &blocker->fl_block); waiter->fl_next = blocker; if (IS_POSIX(blocker)) @@ -740,8 +726,9 @@ EXPORT_SYMBOL(posix_locks_deadlock); * at the head of the list, but that's secret knowledge known only to * flock_lock_file and posix_lock_file. */ -static int flock_lock_file(struct file *filp, struct file_lock *new_fl) +static int flock_lock_file(struct file *filp, struct file_lock *request) { + struct file_lock *new_fl = NULL; struct file_lock **before; struct inode * inode = filp->f_dentry->d_inode; int error = 0; @@ -756,17 +743,19 @@ static int flock_lock_file(struct file *filp, struct file_lock *new_fl) continue; if (filp != fl->fl_file) continue; - if (new_fl->fl_type == fl->fl_type) + if (request->fl_type == fl->fl_type) goto out; found = 1; locks_delete_lock(before); break; } - unlock_kernel(); - if (new_fl->fl_type == F_UNLCK) - return 0; + if (request->fl_type == F_UNLCK) + goto out; + new_fl = locks_alloc_lock(); + if (new_fl == NULL) + goto out; /* * If a higher-priority process was blocked on the old file lock, * give it the opportunity to lock the file. @@ -774,32 +763,31 @@ static int flock_lock_file(struct file *filp, struct file_lock *new_fl) if (found) cond_resched(); - lock_kernel(); for_each_lock(inode, before) { struct file_lock *fl = *before; if (IS_POSIX(fl)) break; if (IS_LEASE(fl)) continue; - if (!flock_locks_conflict(new_fl, fl)) + if (!flock_locks_conflict(request, fl)) continue; error = -EAGAIN; - if (new_fl->fl_flags & FL_SLEEP) { - locks_insert_block(fl, new_fl); - } + if (request->fl_flags & FL_SLEEP) + locks_insert_block(fl, request); goto out; } + locks_copy_lock(new_fl, request); locks_insert_lock(&inode->i_flock, new_fl); - error = 0; + new_fl = NULL; out: unlock_kernel(); + if (new_fl) + locks_free_lock(new_fl); return error; } -EXPORT_SYMBOL(posix_lock_file); - -static int __posix_lock_file(struct inode *inode, struct file_lock *request) +static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request, struct file_lock *conflock) { struct file_lock *fl; struct file_lock *new_fl, *new_fl2; @@ -823,6 +811,8 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request) continue; if (!posix_locks_conflict(request, fl)) continue; + if (conflock) + locks_copy_lock(conflock, fl); error = -EAGAIN; if (!(request->fl_flags & FL_SLEEP)) goto out; @@ -992,8 +982,24 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request) */ int posix_lock_file(struct file *filp, struct file_lock *fl) { - return __posix_lock_file(filp->f_dentry->d_inode, fl); + return __posix_lock_file_conf(filp->f_dentry->d_inode, fl, NULL); +} +EXPORT_SYMBOL(posix_lock_file); + +/** + * posix_lock_file_conf - Apply a POSIX-style lock to a file + * @filp: The file to apply the lock to + * @fl: The lock to be applied + * @conflock: Place to return a copy of the conflicting lock, if found. + * + * Except for the conflock parameter, acts just like posix_lock_file. + */ +int posix_lock_file_conf(struct file *filp, struct file_lock *fl, + struct file_lock *conflock) +{ + return __posix_lock_file_conf(filp->f_dentry->d_inode, fl, conflock); } +EXPORT_SYMBOL(posix_lock_file_conf); /** * posix_lock_file_wait - Apply a POSIX-style lock to a file @@ -1009,7 +1015,7 @@ int posix_lock_file_wait(struct file *filp, struct file_lock *fl) int error; might_sleep (); for (;;) { - error = __posix_lock_file(filp->f_dentry->d_inode, fl); + error = posix_lock_file(filp, fl); if ((error != -EAGAIN) || !(fl->fl_flags & FL_SLEEP)) break; error = wait_event_interruptible(fl->fl_wait, !fl->fl_next); @@ -1081,7 +1087,7 @@ int locks_mandatory_area(int read_write, struct inode *inode, fl.fl_end = offset + count - 1; for (;;) { - error = __posix_lock_file(inode, &fl); + error = __posix_lock_file_conf(inode, &fl, NULL); if (error != -EAGAIN) break; if (!(fl.fl_flags & FL_SLEEP)) @@ -1558,9 +1564,7 @@ asmlinkage long sys_flock(unsigned int fd, unsigned int cmd) error = flock_lock_file_wait(filp, lock); out_free: - if (list_empty(&lock->fl_link)) { - locks_free_lock(lock); - } + locks_free_lock(lock); out_putf: fput(filp); @@ -1694,7 +1698,7 @@ again: error = filp->f_op->lock(filp, cmd, file_lock); else { for (;;) { - error = __posix_lock_file(inode, file_lock); + error = posix_lock_file(filp, file_lock); if ((error != -EAGAIN) || (cmd == F_SETLK)) break; error = wait_event_interruptible(file_lock->fl_wait, @@ -1837,7 +1841,7 @@ again: error = filp->f_op->lock(filp, cmd, file_lock); else { for (;;) { - error = __posix_lock_file(inode, file_lock); + error = posix_lock_file(filp, file_lock); if ((error != -EAGAIN) || (cmd == F_SETLK64)) break; error = wait_event_interruptible(file_lock->fl_wait, @@ -2226,7 +2230,12 @@ void steal_locks(fl_owner_t from) lock_kernel(); j = 0; - rcu_read_lock(); + + /* + * We are not taking a ref to the file structures, so + * we need to acquire ->file_lock. + */ + spin_lock(&files->file_lock); fdt = files_fdtable(files); for (;;) { unsigned long set; @@ -2244,7 +2253,7 @@ void steal_locks(fl_owner_t from) set >>= 1; } } - rcu_read_unlock(); + spin_unlock(&files->file_lock); unlock_kernel(); } EXPORT_SYMBOL(steal_locks);