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
