From patchwork Tue Feb 11 02:30:13 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: NeilBrown X-Patchwork-Id: 3624661 Return-Path: X-Original-To: patchwork-linux-nfs@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 74A559F2F6 for ; Tue, 11 Feb 2014 02:30:28 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id AB46A201F4 for ; Tue, 11 Feb 2014 02:30:27 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id AC408201F2 for ; Tue, 11 Feb 2014 02:30:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752180AbaBKCaZ (ORCPT ); Mon, 10 Feb 2014 21:30:25 -0500 Received: from cantor2.suse.de ([195.135.220.15]:33790 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752148AbaBKCaY (ORCPT ); Mon, 10 Feb 2014 21:30:24 -0500 Received: from relay2.suse.de (charybdis-ext.suse.de [195.135.220.254]) by mx2.suse.de (Postfix) with ESMTP id 94527ABA6; Tue, 11 Feb 2014 02:30:23 +0000 (UTC) Date: Tue, 11 Feb 2014 13:30:13 +1100 From: NeilBrown To: Trond Myklebust Cc: NFS Subject: "nosharecache" option prevent "mount" from detecting when the mount is a duplicate. Message-ID: <20140211133013.1ccf8615@notabene.brown> X-Mailer: Claws Mail 3.9.2 (GTK+ 2.24.22; x86_64-suse-linux-gnu) Mime-Version: 1.0 Sender: linux-nfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-nfs@vger.kernel.org X-Spam-Status: No, score=-7.5 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, T_TVD_MIME_EPI, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP (I seem to have quite a pile of NFS issues lately.... some if it is tidying up issues from before Christmas, some of it just keeps on coming :-) If you run "mount -a" it will attempt to mount all filesystems listed in /etc/fstab, but filesystems that are already mounted will not be mounted again. So it is normally safe to run "mount -a" multiple times. However if an NFS mount in /etc/fstab has the "nosharecache" option set, mount doesn't notice that it is already mounted as so mounts it again. So repeated "mount -a" is no longer safe. This happens because the prevention of multiple mounts happens in do_add_mount in fs/namespace.c: err = -EBUSY; if (path->mnt->mnt_sb == newmnt->mnt.mnt_sb && path->mnt->mnt_root == path->dentry) goto unlock; i.e. if the exact same superblock is being mounted in the exact same place, return EBUSY. With nosharecache, every mount attempt produces a new superblock so this test never fires. One way to address this would be to have a different option, e.g. sharecache=27 where the '27' is an arbitrary number meaning that if two mount attempts have different sharecache numbers they will have different superblocks. If they have the same sharecache number they can have the same superblock. This is not the most elegant interface ever and I would be very happy for suggestions to improve it. Maybe a string rather than a number ??? This probably isn't a very serious issue, but is a regression in terms of the usability of "mount -a" and I think it would be best to fix it if the cost is not too high. Below is my patch to implement the "sharecache=%u" syntax. Any ideas? Thanks, NeilBrown diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 1d09289c8f0e..7ed2f1e37a18 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -779,6 +779,7 @@ static int nfs_init_server(struct nfs_server *server, server->acregmax = data->acregmax * HZ; server->acdirmin = data->acdirmin * HZ; server->acdirmax = data->acdirmax * HZ; + server->cache_id = data->cache_id; /* Start lockd here, before we might error out */ error = nfs_start_lockd(server); @@ -931,6 +932,7 @@ void nfs_server_copy_userdata(struct nfs_server *target, struct nfs_server *sour target->caps = source->caps; target->options = source->options; target->auth_info = source->auth_info; + target->cache_id = source->cache_id; } EXPORT_SYMBOL_GPL(nfs_server_copy_userdata); diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 8b5cc04a8611..b1c2b9164f25 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h @@ -95,6 +95,7 @@ struct nfs_parsed_mount_data { unsigned int minorversion; char *fscache_uniq; bool need_mount; + unsigned int cache_id; struct { struct sockaddr_storage address; diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c index dbb3e1f30c68..25f426db68f9 100644 --- a/fs/nfs/nfs4client.c +++ b/fs/nfs/nfs4client.c @@ -997,6 +997,7 @@ static int nfs4_init_server(struct nfs_server *server, server->acregmax = data->acregmax * HZ; server->acdirmin = data->acdirmin * HZ; server->acdirmax = data->acdirmax * HZ; + server->cache_id = data->cache_id; server->port = data->nfs_server.port; diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 910ed906eb82..27edb581affa 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -103,6 +103,7 @@ enum { Opt_mountport, Opt_mountvers, Opt_minorversion, + Opt_sharecacheid, /* Mount options that take string arguments */ Opt_nfsvers, @@ -145,6 +146,7 @@ static const match_table_t nfs_mount_option_tokens = { { Opt_rdirplus, "rdirplus" }, { Opt_nordirplus, "nordirplus" }, { Opt_sharecache, "sharecache" }, + { Opt_sharecacheid, "sharecache=%s" }, { Opt_nosharecache, "nosharecache" }, { Opt_resvport, "resvport" }, { Opt_noresvport, "noresvport" }, @@ -665,6 +667,10 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, else seq_puts(m, nfs_infop->nostr); } + if (!(nfss->flags & NFS_MOUNT_UNSHARED) && + nfss->cache_id) + seq_printf(m, ",sharecache=%u", nfss->cache_id); + rcu_read_lock(); seq_printf(m, ",proto=%s", rpc_peeraddr2str(nfss->client, RPC_DISPLAY_NETID)); @@ -1407,6 +1413,12 @@ static int nfs_parse_mount_options(char *raw, goto out_invalid_value; mnt->minorversion = option; break; + case Opt_sharecacheid: + if (nfs_get_option_ul(args, &option) || + option <= 0) + goto out_invalid_value; + mnt->cache_id = option; + break; /* * options that take text values @@ -2457,6 +2469,9 @@ static int nfs_compare_super(struct super_block *sb, void *data) /* Note: NFS_MOUNT_UNSHARED == NFS4_MOUNT_UNSHARED */ if (old->flags & NFS_MOUNT_UNSHARED) return 0; + if ((old->cache_id || server->cache_id) && + old->cache_id != server->cache_id) + return 0; if (memcmp(&old->fsid, &server->fsid, sizeof(old->fsid)) != 0) return 0; return nfs_compare_mount_options(sb, server, mntflags); diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index 1150ea41b626..8e66d95283e1 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h @@ -145,6 +145,7 @@ struct nfs_server { #define NFS_OPTION_FSCACHE 0x00000001 /* - local caching enabled */ #define NFS_OPTION_MIGRATION 0x00000002 /* - NFSv4 migration enabled */ + unsigned int cache_id; /* For NFS_MOUNT_UNSHARED */ struct nfs_fsid fsid; __u64 maxfilesize; /* maximum file size */ struct timespec time_delta; /* smallest time granularity */