]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - fs/nfs/file.c
Merge branch 'master' into tk71
[mv-sheeva.git] / fs / nfs / file.c
index 05bf3c0dc751d5d489b1c7be2cf594005caf1695..7bf029ef4084c6e7f02e05e355382168e85e2cb8 100644 (file)
@@ -36,6 +36,7 @@
 #include "internal.h"
 #include "iostat.h"
 #include "fscache.h"
+#include "pnfs.h"
 
 #define NFSDBG_FACILITY                NFSDBG_FILE
 
@@ -386,6 +387,10 @@ static int nfs_write_begin(struct file *file, struct address_space *mapping,
                file->f_path.dentry->d_name.name,
                mapping->host->i_ino, len, (long long) pos);
 
+       pnfs_update_layout(mapping->host,
+                          nfs_file_open_context(file),
+                          IOMODE_RW);
+
 start:
        /*
         * Prevent starvation issues if someone is doing a consistency
@@ -551,7 +556,7 @@ static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
        struct file *filp = vma->vm_file;
        struct dentry *dentry = filp->f_path.dentry;
        unsigned pagelen;
-       int ret = -EINVAL;
+       int ret = VM_FAULT_NOPAGE;
        struct address_space *mapping;
 
        dfprintk(PAGECACHE, "NFS: vm_page_mkwrite(%s/%s(%ld), offset %lld)\n",
@@ -567,21 +572,20 @@ static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
        if (mapping != dentry->d_inode->i_mapping)
                goto out_unlock;
 
-       ret = 0;
        pagelen = nfs_page_length(page);
        if (pagelen == 0)
                goto out_unlock;
 
-       ret = nfs_flush_incompatible(filp, page);
-       if (ret != 0)
-               goto out_unlock;
+       ret = VM_FAULT_LOCKED;
+       if (nfs_flush_incompatible(filp, page) == 0 &&
+           nfs_updatepage(filp, page, 0, pagelen) == 0)
+               goto out;
 
-       ret = nfs_updatepage(filp, page, 0, pagelen);
+       ret = VM_FAULT_SIGBUS;
 out_unlock:
-       if (!ret)
-               return VM_FAULT_LOCKED;
        unlock_page(page);
-       return VM_FAULT_SIGBUS;
+out:
+       return ret;
 }
 
 static const struct vm_operations_struct nfs_file_vm_ops = {
@@ -684,10 +688,12 @@ static ssize_t nfs_file_splice_write(struct pipe_inode_info *pipe,
        return ret;
 }
 
-static int do_getlk(struct file *filp, int cmd, struct file_lock *fl)
+static int
+do_getlk(struct file *filp, int cmd, struct file_lock *fl, int is_local)
 {
        struct inode *inode = filp->f_mapping->host;
        int status = 0;
+       unsigned int saved_type = fl->fl_type;
 
        /* Try local locking first */
        posix_test_lock(filp, fl);
@@ -695,11 +701,12 @@ static int do_getlk(struct file *filp, int cmd, struct file_lock *fl)
                /* found a conflict */
                goto out;
        }
+       fl->fl_type = saved_type;
 
        if (nfs_have_delegation(inode, FMODE_READ))
                goto out_noconflict;
 
-       if (NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM)
+       if (is_local)
                goto out_noconflict;
 
        status = NFS_PROTO(inode)->lock(filp, cmd, fl);
@@ -726,7 +733,8 @@ static int do_vfs_lock(struct file *file, struct file_lock *fl)
        return res;
 }
 
-static int do_unlk(struct file *filp, int cmd, struct file_lock *fl)
+static int
+do_unlk(struct file *filp, int cmd, struct file_lock *fl, int is_local)
 {
        struct inode *inode = filp->f_mapping->host;
        int status;
@@ -741,15 +749,24 @@ static int do_unlk(struct file *filp, int cmd, struct file_lock *fl)
         *      If we're signalled while cleaning up locks on process exit, we
         *      still need to complete the unlock.
         */
-       /* Use local locking if mounted with "-onolock" */
-       if (!(NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM))
+       /*
+        * Use local locking if mounted with "-onolock" or with appropriate
+        * "-olocal_lock="
+        */
+       if (!is_local)
                status = NFS_PROTO(inode)->lock(filp, cmd, fl);
        else
                status = do_vfs_lock(filp, fl);
        return status;
 }
 
-static int do_setlk(struct file *filp, int cmd, struct file_lock *fl)
+static int
+is_time_granular(struct timespec *ts) {
+       return ((ts->tv_sec == 0) && (ts->tv_nsec <= 1000));
+}
+
+static int
+do_setlk(struct file *filp, int cmd, struct file_lock *fl, int is_local)
 {
        struct inode *inode = filp->f_mapping->host;
        int status;
@@ -762,20 +779,31 @@ static int do_setlk(struct file *filp, int cmd, struct file_lock *fl)
        if (status != 0)
                goto out;
 
-       /* Use local locking if mounted with "-onolock" */
-       if (!(NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM))
+       /*
+        * Use local locking if mounted with "-onolock" or with appropriate
+        * "-olocal_lock="
+        */
+       if (!is_local)
                status = NFS_PROTO(inode)->lock(filp, cmd, fl);
        else
                status = do_vfs_lock(filp, fl);
        if (status < 0)
                goto out;
+
        /*
-        * Make sure we clear the cache whenever we try to get the lock.
+        * Revalidate the cache if the server has time stamps granular
+        * enough to detect subsecond changes.  Otherwise, clear the
+        * cache to prevent missing any changes.
+        *
         * This makes locking act as a cache coherency point.
         */
        nfs_sync_mapping(filp->f_mapping);
-       if (!nfs_have_delegation(inode, FMODE_READ))
-               nfs_zap_caches(inode);
+       if (!nfs_have_delegation(inode, FMODE_READ)) {
+               if (is_time_granular(&NFS_SERVER(inode)->time_delta))
+                       __nfs_revalidate_inode(NFS_SERVER(inode), inode);
+               else
+                       nfs_zap_caches(inode);
+       }
 out:
        return status;
 }
@@ -787,6 +815,7 @@ static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
 {
        struct inode *inode = filp->f_mapping->host;
        int ret = -ENOLCK;
+       int is_local = 0;
 
        dprintk("NFS: lock(%s/%s, t=%x, fl=%x, r=%lld:%lld)\n",
                        filp->f_path.dentry->d_parent->d_name.name,
@@ -800,6 +829,9 @@ static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
        if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK)
                goto out_err;
 
+       if (NFS_SERVER(inode)->flags & NFS_MOUNT_LOCAL_FCNTL)
+               is_local = 1;
+
        if (NFS_PROTO(inode)->lock_check_bounds != NULL) {
                ret = NFS_PROTO(inode)->lock_check_bounds(fl);
                if (ret < 0)
@@ -807,11 +839,11 @@ static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
        }
 
        if (IS_GETLK(cmd))
-               ret = do_getlk(filp, cmd, fl);
+               ret = do_getlk(filp, cmd, fl, is_local);
        else if (fl->fl_type == F_UNLCK)
-               ret = do_unlk(filp, cmd, fl);
+               ret = do_unlk(filp, cmd, fl, is_local);
        else
-               ret = do_setlk(filp, cmd, fl);
+               ret = do_setlk(filp, cmd, fl, is_local);
 out_err:
        return ret;
 }
@@ -821,6 +853,9 @@ out_err:
  */
 static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl)
 {
+       struct inode *inode = filp->f_mapping->host;
+       int is_local = 0;
+
        dprintk("NFS: flock(%s/%s, t=%x, fl=%x)\n",
                        filp->f_path.dentry->d_parent->d_name.name,
                        filp->f_path.dentry->d_name.name,
@@ -829,14 +864,17 @@ static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl)
        if (!(fl->fl_flags & FL_FLOCK))
                return -ENOLCK;
 
+       if (NFS_SERVER(inode)->flags & NFS_MOUNT_LOCAL_FLOCK)
+               is_local = 1;
+
        /* We're simulating flock() locks using posix locks on the server */
        fl->fl_owner = (fl_owner_t)filp;
        fl->fl_start = 0;
        fl->fl_end = OFFSET_MAX;
 
        if (fl->fl_type == F_UNLCK)
-               return do_unlk(filp, cmd, fl);
-       return do_setlk(filp, cmd, fl);
+               return do_unlk(filp, cmd, fl, is_local);
+       return do_setlk(filp, cmd, fl, is_local);
 }
 
 /*
@@ -848,6 +886,5 @@ static int nfs_setlease(struct file *file, long arg, struct file_lock **fl)
        dprintk("NFS: setlease(%s/%s, arg=%ld)\n",
                        file->f_path.dentry->d_parent->d_name.name,
                        file->f_path.dentry->d_name.name, arg);
-
        return -EINVAL;
 }