]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - fs/locks.c
i2c: add MODULE_ALIAS to twl4030 drivers
[linux-2.6-omap-h63xx.git] / fs / locks.c
index 49354b9c7dc1234779a7c21114e0c976d12e7e1d..11dbf08651b70861d31530ef73436dc2e3beffc1 100644 (file)
 
 #include <linux/capability.h>
 #include <linux/file.h>
+#include <linux/fdtable.h>
 #include <linux/fs.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/rcupdate.h>
 #include <linux/pid_namespace.h>
 
-#include <asm/semaphore.h>
 #include <asm/uaccess.h>
 
 #define IS_POSIX(fl)   (fl->fl_flags & FL_POSIX)
@@ -225,7 +225,7 @@ static void locks_copy_private(struct file_lock *new, struct file_lock *fl)
 /*
  * Initialize a new lock from an existing file_lock structure.
  */
-static void __locks_copy_lock(struct file_lock *new, const struct file_lock *fl)
+void __locks_copy_lock(struct file_lock *new, const struct file_lock *fl)
 {
        new->fl_owner = fl->fl_owner;
        new->fl_pid = fl->fl_pid;
@@ -237,6 +237,7 @@ static void __locks_copy_lock(struct file_lock *new, const struct file_lock *fl)
        new->fl_ops = NULL;
        new->fl_lmops = NULL;
 }
+EXPORT_SYMBOL(__locks_copy_lock);
 
 void locks_copy_lock(struct file_lock *new, struct file_lock *fl)
 {
@@ -658,8 +659,7 @@ posix_test_lock(struct file *filp, struct file_lock *fl)
        if (cfl) {
                __locks_copy_lock(fl, cfl);
                if (cfl->fl_nspid)
-                       fl->fl_pid = pid_nr_ns(cfl->fl_nspid,
-                                               task_active_pid_ns(current));
+                       fl->fl_pid = pid_vnr(cfl->fl_nspid);
        } else
                fl->fl_type = F_UNLCK;
        unlock_kernel();
@@ -773,7 +773,7 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
         * give it the opportunity to lock the file.
         */
        if (found)
-               cond_resched();
+               cond_resched_bkl();
 
 find_conflict:
        for_each_lock(inode, before) {
@@ -835,7 +835,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
                        if (!posix_locks_conflict(request, fl))
                                continue;
                        if (conflock)
-                               locks_copy_lock(conflock, fl);
+                               __locks_copy_lock(conflock, fl);
                        error = -EAGAIN;
                        if (!(request->fl_flags & FL_SLEEP))
                                goto out;
@@ -1276,13 +1276,13 @@ out:
 EXPORT_SYMBOL(__break_lease);
 
 /**
- *     lease_get_mtime
+ *     lease_get_mtime - get the last modified time of an inode
  *     @inode: the inode
  *      @time:  pointer to a timespec which will contain the last modified time
  *
  * This is to force NFS clients to flush their caches for files with
  * exclusive leases.  The justification is that if someone has an
- * exclusive lease, then they could be modifiying it.
+ * exclusive lease, then they could be modifying it.
  */
 void lease_get_mtime(struct inode *inode, struct timespec *time)
 {
@@ -1369,18 +1369,20 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
 
        lease = *flp;
 
-       error = -EAGAIN;
-       if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0))
-               goto out;
-       if ((arg == F_WRLCK)
-           && ((atomic_read(&dentry->d_count) > 1)
-               || (atomic_read(&inode->i_count) > 1)))
-               goto out;
+       if (arg != F_UNLCK) {
+               error = -ENOMEM;
+               new_fl = locks_alloc_lock();
+               if (new_fl == NULL)
+                       goto out;
 
-       error = -ENOMEM;
-       new_fl = locks_alloc_lock();
-       if (new_fl == NULL)
-               goto out;
+               error = -EAGAIN;
+               if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0))
+                       goto out;
+               if ((arg == F_WRLCK)
+                   && ((atomic_read(&dentry->d_count) > 1)
+                       || (atomic_read(&inode->i_count) > 1)))
+                       goto out;
+       }
 
        /*
         * At this point, we know that if there is an exclusive
@@ -1406,6 +1408,7 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
                        rdlease_count++;
        }
 
+       error = -EAGAIN;
        if ((arg == F_RDLCK && (wrlease_count > 0)) ||
            (arg == F_WRLCK && ((rdlease_count + wrlease_count) > 0)))
                goto out;
@@ -1492,8 +1495,7 @@ EXPORT_SYMBOL_GPL(vfs_setlease);
 int fcntl_setlease(unsigned int fd, struct file *filp, long arg)
 {
        struct file_lock fl, *flp = &fl;
-       struct dentry *dentry = filp->f_path.dentry;
-       struct inode *inode = dentry->d_inode;
+       struct inode *inode = filp->f_path.dentry->d_inode;
        int error;
 
        locks_init_lock(&fl);
@@ -1751,6 +1753,7 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd,
        struct file_lock *file_lock = locks_alloc_lock();
        struct flock flock;
        struct inode *inode;
+       struct file *f;
        int error;
 
        if (file_lock == NULL)
@@ -1802,24 +1805,36 @@ again:
        if (error)
                goto out;
 
-       for (;;) {
-               error = vfs_lock_file(filp, cmd, file_lock, NULL);
-               if (error != -EAGAIN || cmd == F_SETLK)
-                       break;
-               error = wait_event_interruptible(file_lock->fl_wait,
-                               !file_lock->fl_next);
-               if (!error)
-                       continue;
+       if (filp->f_op && filp->f_op->lock != NULL)
+               error = filp->f_op->lock(filp, cmd, file_lock);
+       else {
+               for (;;) {
+                       error = posix_lock_file(filp, file_lock, NULL);
+                       if (error != -EAGAIN || cmd == F_SETLK)
+                               break;
+                       error = wait_event_interruptible(file_lock->fl_wait,
+                                       !file_lock->fl_next);
+                       if (!error)
+                               continue;
 
-               locks_delete_block(file_lock);
-               break;
+                       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) {
+       /*
+        * we need that spin_lock here - it prevents reordering between
+        * update of inode->i_flock and check for it done in close().
+        * rcu_read_lock() wouldn't do.
+        */
+       spin_lock(&current->files->file_lock);
+       f = fcheck(fd);
+       spin_unlock(&current->files->file_lock);
+       if (!error && f != filp && flock.l_type != F_UNLCK) {
                flock.l_type = F_UNLCK;
                goto again;
        }
@@ -1875,6 +1890,7 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd,
        struct file_lock *file_lock = locks_alloc_lock();
        struct flock64 flock;
        struct inode *inode;
+       struct file *f;
        int error;
 
        if (file_lock == NULL)
@@ -1926,24 +1942,31 @@ again:
        if (error)
                goto out;
 
-       for (;;) {
-               error = vfs_lock_file(filp, cmd, file_lock, NULL);
-               if (error != -EAGAIN || cmd == F_SETLK64)
-                       break;
-               error = wait_event_interruptible(file_lock->fl_wait,
-                               !file_lock->fl_next);
-               if (!error)
-                       continue;
+       if (filp->f_op && filp->f_op->lock != NULL)
+               error = filp->f_op->lock(filp, cmd, file_lock);
+       else {
+               for (;;) {
+                       error = posix_lock_file(filp, file_lock, NULL);
+                       if (error != -EAGAIN || cmd == F_SETLK64)
+                               break;
+                       error = wait_event_interruptible(file_lock->fl_wait,
+                                       !file_lock->fl_next);
+                       if (!error)
+                               continue;
 
-               locks_delete_block(file_lock);
-               break;
+                       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) {
+       spin_lock(&current->files->file_lock);
+       f = fcheck(fd);
+       spin_unlock(&current->files->file_lock);
+       if (!error && f != filp && flock.l_type != F_UNLCK) {
                flock.l_type = F_UNLCK;
                goto again;
        }
@@ -2084,7 +2107,7 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl,
        unsigned int fl_pid;
 
        if (fl->fl_nspid)
-               fl_pid = pid_nr_ns(fl->fl_nspid, task_active_pid_ns(current));
+               fl_pid = pid_vnr(fl->fl_nspid);
        else
                fl_pid = fl->fl_pid;