This patch is a backport of the -o local_lock option for nfs mounts.
The local_lock option was introduced into the mainline in kernel 2.6.37.
Use of -o local_lock=flock is required to avoid deadlocks when running
SMB over NFS.
>From the updated nfs(5) manpage:
  To support legacy flock behavior similar to that of NFS clients < 2.6.12, use
  'local_lock=flock'.  This optioin is required when exporting NFS mounts via
  Samba as Samba maps Windows share mode locks as flock.  Since NFS clients >
  2.6.12 impelment flock by emulating POSIX locks, this will result in
  conflicting locks.

Signed-off-by: Peter Holland <[email protected]>

---
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ 
b/target/linux/generic-2.6/patches-2.6.32/981-backport_local_lock_mount_option.patch
        Fri
Oct 14 12:33:37 2011 -0700
@@ -0,0 +1,285 @@
+diff -ru linux-2.6.32.27/fs/nfs/client.c linux-2.6.32.27-new/fs/nfs/client.c
+--- linux-2.6.32.27/fs/nfs/client.c    2010-12-09 13:29:45.000000000 -0800
++++ linux-2.6.32.27-new/fs/nfs/client.c        2011-10-14 12:01:18.000000000 
-0700
+@@ -633,7 +633,8 @@
+  */
+ static void nfs_destroy_server(struct nfs_server *server)
+ {
+-      if (!(server->flags & NFS_MOUNT_NONLM))
++      if (!(server->flags & NFS_MOUNT_LOCAL_FLOCK) ||
++            !(server->flags & NFS_MOUNT_LOCAL_FCNTL))
+               nlmclnt_done(server->nlm_host);
+ }
+
+@@ -655,7 +656,8 @@
+
+       if (nlm_init.nfs_version > 3)
+               return 0;
+-      if (server->flags & NFS_MOUNT_NONLM)
++      if ((server->flags & NFS_MOUNT_LOCAL_FLOCK) &&
++            (server->flags & NFS_MOUNT_LOCAL_FCNTL))
+               return 0;
+
+       switch (clp->cl_proto) {
+diff -ru linux-2.6.32.27/fs/nfs/file.c linux-2.6.32.27-new/fs/nfs/file.c
+--- linux-2.6.32.27/fs/nfs/file.c      2010-12-09 13:29:45.000000000 -0800
++++ linux-2.6.32.27-new/fs/nfs/file.c  2011-10-14 11:59:08.000000000 -0700
+@@ -676,7 +676,7 @@
+       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;
+@@ -691,7 +691,7 @@
+       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);
+@@ -722,7 +722,7 @@
+       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;
+@@ -738,14 +738,14 @@
+        *      still need to complete the unlock.
+        */
+       /* Use local locking if mounted with "-onolock" */
+-      if (!(NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM))
++        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 do_setlk(struct file *filp, int cmd, struct file_lock
*fl, int is_local)
+ {
+       struct inode *inode = filp->f_mapping->host;
+       int status;
+@@ -759,7 +759,7 @@
+               goto out;
+
+       /* Use local locking if mounted with "-onolock" */
+-      if (!(NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM))
++        if (!is_local)
+               status = NFS_PROTO(inode)->lock(filp, cmd, fl);
+       else
+               status = do_vfs_lock(filp, fl);
+@@ -783,6 +783,7 @@
+ {
+       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,
+@@ -802,12 +803,15 @@
+                       goto out_err;
+       }
+
++        if (NFS_SERVER(inode)->flags & NFS_MOUNT_LOCAL_FCNTL)
++                is_local = 1;
++
+       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;
+ }
+@@ -817,6 +821,9 @@
+  */
+ 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,
+@@ -825,14 +832,17 @@
+       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);
+ }
+
+ /*
+diff -ru linux-2.6.32.27/fs/nfs/super.c linux-2.6.32.27-new/fs/nfs/super.c
+--- linux-2.6.32.27/fs/nfs/super.c     2010-12-09 13:29:45.000000000 -0800
++++ linux-2.6.32.27-new/fs/nfs/super.c 2011-10-14 12:14:51.000000000 -0700
+@@ -99,6 +99,7 @@
+       Opt_addr, Opt_mountaddr, Opt_clientaddr,
+       Opt_lookupcache,
+       Opt_fscache_uniq,
++        Opt_local_lock,
+
+       /* Special mount options */
+       Opt_userspace, Opt_deprecated, Opt_sloppy,
+@@ -170,7 +171,7 @@
+       { Opt_mountaddr, "mountaddr=%s" },
+
+       { Opt_lookupcache, "lookupcache=%s" },
+-
++        { Opt_local_lock, "local_lock=%s" },
+       { Opt_err, NULL }
+ };
+
+@@ -233,6 +234,22 @@
+       { Opt_lookupcache_err, NULL }
+ };
+
++enum {
++    Opt_local_lock_all, Opt_local_lock_flock, Opt_local_lock_posix,
++    Opt_local_lock_none,
++
++    Opt_local_lock_err
++};
++
++static match_table_t nfs_local_lock_tokens = {
++    { Opt_local_lock_all, "all" },
++    { Opt_local_lock_flock, "flock" },
++    { Opt_local_lock_posix, "posix" },
++    { Opt_local_lock_none, "none" },
++
++    { Opt_local_lock_err, NULL }
++};
++
+
+ static void nfs_umount_begin(struct super_block *);
+ static int  nfs_statfs(struct dentry *, struct kstatfs *);
+@@ -575,6 +592,7 @@
+       const struct proc_nfs_info *nfs_infop;
+       struct nfs_client *clp = nfss->nfs_client;
+       u32 version = clp->rpc_ops->version;
++        int local_flock, local_fcntl;
+
+       seq_printf(m, ",vers=%u", version);
+       seq_printf(m, ",rsize=%u", nfss->rsize);
+@@ -609,6 +627,18 @@
+       seq_printf(m, ",retrans=%u", nfss->client->cl_timeout->to_retries);
+       seq_printf(m, ",sec=%s",
nfs_pseudoflavour_to_name(nfss->client->cl_auth->au_flavor));
+
++        local_flock = nfss->flags & NFS_MOUNT_LOCAL_FLOCK;
++        local_fcntl = nfss->flags & NFS_MOUNT_LOCAL_FCNTL;
++
++        if (!local_flock && !local_fcntl)
++                seq_printf(m, ",local_lock=none");
++        else if (local_flock && local_fcntl)
++                seq_printf(m, ",local_lock=all");
++        else if (local_flock)
++                seq_printf(m, ",local_lock=flock");
++        else if (local_fcntl)
++                seq_printf(m, ",local_lock=posix");
++
+       if (version != 4)
+               nfs_show_mountd_options(m, nfss, showdefaults);
+       else
+@@ -971,11 +1001,41 @@
+                       mnt->flags |= NFS_MOUNT_NOAC;
+                       break;
+               case Opt_lock:
+-                      mnt->flags &= ~NFS_MOUNT_NONLM;
++                        mnt->flags &= ~(NFS_MOUNT_LOCAL_FLOCK |
++                                        NFS_MOUNT_LOCAL_FCNTL);
+                       break;
+               case Opt_nolock:
+-                      mnt->flags |= NFS_MOUNT_NONLM;
++                        mnt->flags |= (NFS_MOUNT_LOCAL_FLOCK |
++                                       NFS_MOUNT_LOCAL_FCNTL);
+                       break;
++                case Opt_local_lock:
++                        string = match_strdup(args);
++                                            args);
++                        kfree(string);
++                        switch(token) {
++                        case Opt_local_lock_all:
++                                mnt->flags |= (NFS_MOUNT_LOCAL_FLOCK |
++                                               NFS_MOUNT_LOCAL_FCNTL);
++                                break;
++                        case Opt_local_lock_flock:
++                                mnt->flags |= NFS_MOUNT_LOCAL_FLOCK;
++                                break;
++                        case Opt_local_lock_posix:
++                                mnt->flags |= NFS_MOUNT_LOCAL_FCNTL;
++                                break;
++                        case Opt_local_lock_none:
++                                mnt->flags &= ~(NFS_MOUNT_LOCAL_FLOCK |
++                                                NFS_MOUNT_LOCAL_FCNTL);
++                                break;
++                        default:
++                                dfprintk(MOUNT, "NFS:    invalid "
++                                         "local_lock argument\n");
++                                return 0;
++                        };
++                        break;
+               case Opt_v2:
+                       mnt->flags &= ~NFS_MOUNT_VER3;
+                       mnt->version = 2;
+@@ -1744,6 +1804,13 @@
+               if (!args->nfs_server.hostname)
+                       goto out_nomem;
+
++                if (!(data->flags & NFS_MOUNT_NONLM))
++                    args->flags &= ~(NFS_MOUNT_LOCAL_FLOCK|
++                                   NFS_MOUNT_LOCAL_FCNTL);
++              else
++                    args->flags |= (NFS_MOUNT_LOCAL_FLOCK|
++                                    NFS_MOUNT_LOCAL_FCNTL);
++
+               /*
+                * The legacy version 6 binary mount data from userspace has a
+                * field used only to transport selinux information into the
+@@ -2355,7 +2422,8 @@
+
+ static void nfs4_validate_mount_flags(struct nfs_parsed_mount_data *args)
+ {
+-      args->flags &= ~(NFS_MOUNT_NONLM|NFS_MOUNT_NOACL|NFS_MOUNT_VER3);
++      args->flags &= ~(NFS_MOUNT_NONLM|NFS_MOUNT_NOACL|NFS_MOUNT_VER3|
++                         NFS_MOUNT_LOCAL_FLOCK|NFS_MOUNT_LOCAL_FCNTL);
+ }
+
+ static int nfs4_validate_text_mount_data(void *options,
+diff -ru linux-2.6.32.27/include/linux/nfs_mount.h
linux-2.6.32.27-new/include/linux/nfs_mount.h
+--- linux-2.6.32.27/include/linux/nfs_mount.h  2010-12-09
13:29:45.000000000 -0800
++++ linux-2.6.32.27-new/include/linux/nfs_mount.h      2011-10-14
12:16:59.676603537 -0700
+@@ -69,5 +69,6 @@
+ #define NFS_MOUNT_LOOKUP_CACHE_NONEG  0x10000
+ #define NFS_MOUNT_LOOKUP_CACHE_NONE   0x20000
+ #define NFS_MOUNT_NORESVPORT          0x40000
+-
++#define NFS_MOUNT_LOCAL_FLOCK          0x100000
++#define NFS_MOUNT_LOCAL_FCNTL          0x200000
+ #endif
_______________________________________________
openwrt-devel mailing list
[email protected]
https://lists.openwrt.org/mailman/listinfo/openwrt-devel

Reply via email to