* [PATCH 08/13] NFS: Add functions to parse nfs mount options to fs/nfs/super.c
@ 2007-05-21 16:09 Chuck Lever
2007-05-29 20:21 ` Karel Zak
0 siblings, 1 reply; 4+ messages in thread
From: Chuck Lever @ 2007-05-21 16:09 UTC (permalink / raw)
To: akpm; +Cc: linux-fsdevel
For NFSv2 and NFSv3 mount options.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/nfs/super.c | 449 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 449 insertions(+), 0 deletions(-)
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 1974648..a9f698b 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -514,6 +514,455 @@ static void nfs_umount_begin(struct vfsmount *vfsmnt, int flags)
shrink_submounts(vfsmnt, &nfs_automount_list);
}
+
+static match_table_t nfs_tokens = {
+ {Opt_userspace, "bg"},
+ {Opt_userspace, "fg"},
+ {Opt_soft, "soft"},
+ {Opt_hard, "hard"},
+ {Opt_intr, "intr"},
+ {Opt_nointr, "nointr"},
+ {Opt_posix, "posix"},
+ {Opt_noposix, "noposix"},
+ {Opt_cto, "cto"},
+ {Opt_nocto, "nocto"},
+ {Opt_ac, "ac"},
+ {Opt_noac, "noac"},
+ {Opt_lock, "lock"},
+ {Opt_nolock, "nolock"},
+ {Opt_v2, "v2"},
+ {Opt_v3, "v3"},
+ {Opt_udp, "udp"},
+ {Opt_tcp, "tcp"},
+ {Opt_acl, "acl"},
+ {Opt_noacl, "noacl"},
+
+ {Opt_port, "port=%u"},
+ {Opt_rsize, "rsize=%u"},
+ {Opt_wsize, "wsize=%u"},
+ {Opt_timeo, "timeo=%u"},
+ {Opt_retrans, "retrans=%u"},
+ {Opt_acregmin, "acregmin=%u"},
+ {Opt_acregmax, "acregmax=%u"},
+ {Opt_acdirmin, "acdirmin=%u"},
+ {Opt_acdirmax, "acdirmax=%u"},
+ {Opt_actimeo, "actimeo=%u"},
+ {Opt_userspace, "retry=%u"},
+ {Opt_namelen, "namlen=%u"},
+ {Opt_mountport, "mountport=%u"},
+ {Opt_mountprog, "mountprog=%u"},
+ {Opt_mountvers, "mountvers=%u"},
+ {Opt_nfsprog, "nfsprog=%u"},
+ {Opt_nfsvers, "nfsvers=%u"},
+ {Opt_nfsvers, "vers=%u"},
+
+ {Opt_sec, "sec=%s"},
+ {Opt_proto, "proto=%s"},
+ {Opt_addr, "addr=%s"},
+ {Opt_mounthost, "mounthost=%s"},
+ {Opt_context, "context=%s"},
+
+ {Opt_err, NULL},
+};
+
+static int nfs_parse_options(char *raw, struct nfs_mount_args *mnt)
+{
+ char *p, *string;
+
+ if (!raw) {
+ dprintk("NFS: mount options string was NULL.\n");
+ return 1;
+ }
+
+ while ((p = strsep (&raw, ",")) != NULL) {
+ substring_t args[MAX_OPT_ARGS];
+ int option, token;
+
+ if (!*p)
+ continue;
+ token = match_token(p, nfs_tokens, args);
+
+ dprintk("NFS: nfs mount option '%s': parsing token %d\n",
+ p, token);
+
+ switch (token) {
+ case Opt_soft:
+ mnt->nmd.flags |= NFS_MOUNT_SOFT;
+ break;
+ case Opt_hard:
+ mnt->nmd.flags &= ~NFS_MOUNT_SOFT;
+ break;
+ case Opt_intr:
+ mnt->nmd.flags |= NFS_MOUNT_INTR;
+ break;
+ case Opt_nointr:
+ mnt->nmd.flags &= ~NFS_MOUNT_INTR;
+ break;
+ case Opt_posix:
+ mnt->nmd.flags |= NFS_MOUNT_POSIX;
+ break;
+ case Opt_noposix:
+ mnt->nmd.flags &= ~NFS_MOUNT_POSIX;
+ break;
+ case Opt_cto:
+ mnt->nmd.flags &= ~NFS_MOUNT_NOCTO;
+ break;
+ case Opt_nocto:
+ mnt->nmd.flags |= NFS_MOUNT_NOCTO;
+ break;
+ case Opt_ac:
+ mnt->nmd.flags &= ~NFS_MOUNT_NOAC;
+ break;
+ case Opt_noac:
+ mnt->nmd.flags |= NFS_MOUNT_NOAC;
+ break;
+ case Opt_lock:
+ mnt->nmd.flags &= ~NFS_MOUNT_NONLM;
+ break;
+ case Opt_nolock:
+ mnt->nmd.flags |= NFS_MOUNT_NONLM;
+ break;
+ case Opt_v2:
+ mnt->nmd.flags &= ~NFS_MOUNT_VER3;
+ break;
+ case Opt_v3:
+ mnt->nmd.flags |= NFS_MOUNT_VER3;
+ break;
+ case Opt_udp:
+ mnt->nmd.flags &= ~NFS_MOUNT_TCP;
+ break;
+ case Opt_tcp:
+ mnt->nmd.flags |= NFS_MOUNT_TCP;
+ break;
+ case Opt_acl:
+ mnt->nmd.flags &= ~NFS_MOUNT_NOACL;
+ break;
+ case Opt_noacl:
+ mnt->nmd.flags |= NFS_MOUNT_NOACL;
+ break;
+
+ case Opt_port:
+ if (match_int(args, &option))
+ return 0;
+ if (option < 0 || option > 65535)
+ return 0;
+ mnt->nmd.addr.sin_port = htonl(option);
+ break;
+ case Opt_rsize:
+ if (match_int(args, &mnt->nmd.rsize))
+ return 0;
+ break;
+ case Opt_wsize:
+ if (match_int(args, &mnt->nmd.wsize))
+ return 0;
+ break;
+ case Opt_timeo:
+ if (match_int(args, &mnt->nmd.timeo))
+ return 0;
+ break;
+ case Opt_retrans:
+ if (match_int(args, &mnt->nmd.retrans))
+ return 0;
+ break;
+ case Opt_acregmin:
+ if (match_int(args, &mnt->nmd.acregmin))
+ return 0;
+ break;
+ case Opt_acregmax:
+ if (match_int(args, &mnt->nmd.acregmax))
+ return 0;
+ break;
+ case Opt_acdirmin:
+ if (match_int(args, &mnt->nmd.acdirmin))
+ return 0;
+ break;
+ case Opt_acdirmax:
+ if (match_int(args, &mnt->nmd.acdirmax))
+ return 0;
+ break;
+ case Opt_actimeo:
+ if (match_int(args, &option))
+ return 0;
+ if (option < 0)
+ return 0;
+ mnt->nmd.acregmin =
+ mnt->nmd.acregmax =
+ mnt->nmd.acdirmin =
+ mnt->nmd.acdirmax = option;
+ break;
+ case Opt_namelen:
+ if (match_int(args, &mnt->nmd.namlen))
+ return 0;
+ break;
+ case Opt_mountport:
+ if (match_int(args, &option))
+ return 0;
+ if (option < 0 || option > 65535)
+ return 0;
+ mnt->mnthost.sin_port = htonl(option);
+ break;
+ case Opt_mountprog:
+ if (match_int(args, &option))
+ return 0;
+ if (option < 0)
+ return 0;
+ mnt->mntprog = option;
+ break;
+ case Opt_mountvers:
+ if (match_int(args, &option))
+ return 0;
+ if (option < 0)
+ return 0;
+ mnt->mntvers = option;
+ break;
+ case Opt_nfsprog:
+ if (match_int(args, &option))
+ return 0;
+ if (option < 0)
+ return 0;
+ mnt->nfsprog = option;
+ break;
+ case Opt_nfsvers:
+ if (match_int(args, &option))
+ return 0;
+ switch (option) {
+ case 2:
+ mnt->nmd.flags &= ~NFS_MOUNT_VER3;
+ break;
+ case 3:
+ mnt->nmd.flags |= NFS_MOUNT_VER3;
+ break;
+ default:
+ goto out_unrec_vers;
+ }
+ break;
+
+ case Opt_sec: {
+ string = match_strdup(args);
+ if (string == NULL)
+ goto out_nomem;
+ token = match_token(string, nfs_sec_tokens, args);
+ kfree(string);
+
+ mnt->nmd.flags |= NFS_MOUNT_SECFLAVOUR;
+
+ switch (token) {
+ case Opt_sec_none:
+ mnt->nmd.flags &= ~NFS_MOUNT_SECFLAVOUR;
+ mnt->nmd.pseudoflavor = RPC_AUTH_NULL;
+ break;
+ case Opt_sec_sys:
+ mnt->nmd.flags &= ~NFS_MOUNT_SECFLAVOUR;
+ mnt->nmd.pseudoflavor = RPC_AUTH_UNIX;
+ break;
+ case Opt_sec_krb5:
+ mnt->nmd.pseudoflavor = RPC_AUTH_GSS_KRB5;
+ break;
+ case Opt_sec_krb5i:
+ mnt->nmd.pseudoflavor = RPC_AUTH_GSS_KRB5I;
+ break;
+ case Opt_sec_krb5p:
+ mnt->nmd.pseudoflavor = RPC_AUTH_GSS_KRB5P;
+ break;
+ case Opt_sec_lkey:
+ mnt->nmd.pseudoflavor = RPC_AUTH_GSS_LKEY;
+ break;
+ case Opt_sec_lkeyi:
+ mnt->nmd.pseudoflavor = RPC_AUTH_GSS_LKEYI;
+ break;
+ case Opt_sec_lkeyp:
+ mnt->nmd.pseudoflavor = RPC_AUTH_GSS_LKEYP;
+ break;
+ case Opt_sec_spkm:
+ mnt->nmd.pseudoflavor = RPC_AUTH_GSS_SPKM;
+ break;
+ case Opt_sec_spkmi:
+ mnt->nmd.pseudoflavor = RPC_AUTH_GSS_SPKMI;
+ break;
+ case Opt_sec_spkmp:
+ mnt->nmd.pseudoflavor = RPC_AUTH_GSS_SPKMP;
+ break;
+ default:
+ goto out_unrec_sec;
+ }
+ break;
+ }
+ case Opt_proto:
+ string = match_strdup(args);
+ if (string == NULL)
+ goto out_nomem;
+ if (strcmp(string, "udp") == 0) {
+ mnt->nmd.flags &= ~NFS_MOUNT_TCP;
+ kfree(string);
+ break;
+ }
+ if (strcmp(string, "tcp") == 0) {
+ mnt->nmd.flags |= NFS_MOUNT_TCP;
+ kfree(string);
+ break;
+ }
+ goto out_unrec_xprt;
+ case Opt_addr:
+ string = match_strdup(args);
+ if (string == NULL)
+ goto out_nomem;
+ mnt->nmd.addr.sin_family = AF_INET;
+ mnt->nmd.addr.sin_addr.s_addr = in_aton(string);
+ kfree(string);
+ break;
+ case Opt_mounthost:
+ string = match_strdup(args);
+ if (string == NULL)
+ goto out_nomem;
+ mnt->mnthost.sin_family = AF_INET;
+ mnt->mnthost.sin_addr.s_addr = in_aton(string);
+ kfree(string);
+ mnt->use_mnthost = 1;
+ break;
+ case Opt_context:
+ match_strcpy(mnt->nmd.context, args);
+ break;
+
+ case Opt_userspace:
+ case Opt_deprecated:
+ break;
+
+ default:
+ goto out_unknown;
+ }
+ }
+
+ return 1;
+
+out_nomem:
+ printk(KERN_INFO "NFS: not enough memory to parse option\n");
+ return 0;
+
+out_unrec_vers:
+ printk(KERN_INFO "NFS: unrecognized NFS version number\n");
+ return 0;
+
+out_unrec_xprt:
+ printk(KERN_INFO "NFS: unrecognized transport protocol\n");
+ return 0;
+
+out_unrec_sec:
+ printk(KERN_INFO "NFS: unrecognized security flavor\n");
+ return 0;
+
+out_unknown:
+ printk(KERN_INFO "NFS: unknown mount option: %s\n", p);
+ return 0;
+}
+
+/*
+ * Use the remote server's MOUNT service to request the NFS file handle
+ * corresponding to the provided path.
+ */
+static int nfs_try_mount(struct nfs_mount_data *nmd, char *path)
+{
+ struct nfs_mount_args *args;
+ int status, version, protocol;
+ struct sockaddr_in sin;
+ struct nfs_fh fh;
+
+ args = container_of(nmd, struct nfs_mount_args, nmd);
+ if (args->mntvers == 0) {
+ version = (args->nmd.flags & NFS_MOUNT_VER3) ?
+ NFS_MNT3_VERSION : NFS_MNT_VERSION;
+ } else
+ version = args->mntvers;
+ protocol = (args->nmd.flags & NFS_MOUNT_TCP) ?
+ IPPROTO_TCP : IPPROTO_UDP;
+
+ sin.sin_family = AF_INET;
+ if (args->use_mnthost == 0)
+ sin.sin_addr.s_addr = args->nmd.addr.sin_addr.s_addr;
+ else
+ sin.sin_addr.s_addr = args->mnthost.sin_addr.s_addr;
+ if (args->mntport == 0) {
+ status = rpcb_getport_sync(&sin, args->mntprog, version, protocol);
+ if (status < 0)
+ goto out_bind_err;
+ sin.sin_port = htons(status);
+ } else
+ sin.sin_port = htons(args->mntport);
+
+ sin.sin_addr.s_addr = args->nmd.addr.sin_addr.s_addr;
+ status = nfs_mount(&sin, path, &fh, version, protocol);
+ if (status < 0)
+ goto out_mnt_err;
+
+ args->nmd.root.size = fh.size;
+ memcpy(args->nmd.root.data, fh.data, fh.size);
+ return status;
+
+out_bind_err:
+ printk(KERN_INFO "NFS: unable to contact bind server on host %s\n",
+ nmd->hostname);
+ return status;
+out_mnt_err:
+ printk(KERN_INFO "NFS: unable to contact NFS server on host %s\n",
+ nmd->hostname);
+ return status;
+}
+
+/*
+ * Convert a string of nfs mount options into an nfs_mount_data struct.
+ *
+ * User space handles the following behaviors:
+ *
+ * + DNS: mapping server host name to IP address ("addr=" option)
+ *
+ * + failure mode: how to behave if a mount request can't be handled
+ * immediately ("fg/bg" option)
+ *
+ * + retry: how often to retry a mount request ("retry=" option)
+ *
+ * + breaking back: trying UDP after TCP, and v2 after v3
+ *
+ * XXX: as far as I can tell, changing the NFS program is not really supported
+ * in the NFS client.
+ *
+ */
+static struct nfs_mount_data *nfs_convert_mount_opts(const char *options)
+{
+ struct nfs_mount_args *args;
+
+ dprintk("NFS: nfs mount opts='%s'\n", options);
+
+ args = kzalloc(sizeof(*args), GFP_KERNEL);
+ if (args == NULL)
+ return ERR_PTR(-ENOMEM);
+
+ args->nmd.version = 7;
+
+ args->nmd.flags = (NFS_MOUNT_VER3 | NFS_MOUNT_TCP);
+ args->nmd.rsize = NFS_MAX_FILE_IO_SIZE;
+ args->nmd.wsize = NFS_MAX_FILE_IO_SIZE;
+ args->nmd.timeo = 600; /* in tenths of a second */
+ args->nmd.retrans = 2;
+ args->nmd.acregmin = 3;
+ args->nmd.acregmax = 60;
+ args->nmd.acdirmin = 30;
+ args->nmd.acdirmax = 60;
+
+ args->nfsprog = NFS_PROGRAM;
+ args->use_mnthost = 0;
+ args->mntprog = NFS_MNT_PROGRAM;
+ args->mntvers = 0;
+ args->mntport = 0;
+
+ if (nfs_parse_options((char *) options, args) == 0)
+ goto out_err;
+
+ return &args->nmd;
+
+out_err:
+ kfree(args);
+ return ERR_PTR(-EINVAL);
+}
+
/*
* Sanity-check a server address provided by the mount command
*/
^ permalink raw reply related [flat|nested] 4+ messages in thread* Re: [PATCH 08/13] NFS: Add functions to parse nfs mount options to fs/nfs/super.c
2007-05-21 16:09 [PATCH 08/13] NFS: Add functions to parse nfs mount options to fs/nfs/super.c Chuck Lever
@ 2007-05-29 20:21 ` Karel Zak
2007-05-29 21:08 ` Chuck Lever
0 siblings, 1 reply; 4+ messages in thread
From: Karel Zak @ 2007-05-29 20:21 UTC (permalink / raw)
To: Chuck Lever; +Cc: akpm, linux-fsdevel
On Mon, May 21, 2007 at 12:09:54PM -0400, Chuck Lever wrote:
> For NFSv2 and NFSv3 mount options.
> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
....
> +static int nfs_parse_options(char *raw, struct nfs_mount_args *mnt)
> +{
> + char *p, *string;
> +
> + if (!raw) {
> + dprintk("NFS: mount options string was NULL.\n");
> + return 1;
> + }
> +
> + while ((p = strsep (&raw, ",")) != NULL) {
> + substring_t args[MAX_OPT_ARGS];
> + int option, token;
> +
> + if (!*p)
> + continue;
> + token = match_token(p, nfs_tokens, args);
....
> +
> + case Opt_context:
> + match_strcpy(mnt->nmd.context, args);
> + break;
The userspace version (nfs-utils) of this code supports a quoted
context strings. For example:
context="aaa,bbb,ccc",hard
It seems your code blindly parses a raw option string by ",".
Karel
--
Karel Zak <kzak@redhat.com>
^ permalink raw reply [flat|nested] 4+ messages in thread* Re: [PATCH 08/13] NFS: Add functions to parse nfs mount options to fs/nfs/super.c
2007-05-29 20:21 ` Karel Zak
@ 2007-05-29 21:08 ` Chuck Lever
2007-05-30 0:18 ` Karel Zak
0 siblings, 1 reply; 4+ messages in thread
From: Chuck Lever @ 2007-05-29 21:08 UTC (permalink / raw)
To: Karel Zak; +Cc: akpm, linux-fsdevel
[-- Attachment #1: Type: text/plain, Size: 1115 bytes --]
Karel Zak wrote:
> On Mon, May 21, 2007 at 12:09:54PM -0400, Chuck Lever wrote:
>> For NFSv2 and NFSv3 mount options.
>> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
>
> ....
>
>> +static int nfs_parse_options(char *raw, struct nfs_mount_args *mnt)
>> +{
>> + char *p, *string;
>> +
>> + if (!raw) {
>> + dprintk("NFS: mount options string was NULL.\n");
>> + return 1;
>> + }
>> +
>> + while ((p = strsep (&raw, ",")) != NULL) {
>> + substring_t args[MAX_OPT_ARGS];
>> + int option, token;
>> +
>> + if (!*p)
>> + continue;
>> + token = match_token(p, nfs_tokens, args);
>
> ....
>
>> +
>> + case Opt_context:
>> + match_strcpy(mnt->nmd.context, args);
>> + break;
>
> The userspace version (nfs-utils) of this code supports a quoted
> context strings. For example:
>
> context="aaa,bbb,ccc",hard
>
> It seems your code blindly parses a raw option string by ",".
Karel-
I've never used the context= option, and didn't find any documentation
describing how it was used.
Is there a clean example of how to use the in-kernel parser to handle
quoted strings containing commas?
[-- Attachment #2: chuck.lever.vcf --]
[-- Type: text/x-vcard, Size: 291 bytes --]
begin:vcard
fn:Chuck Lever
n:Lever;Chuck
org:Oracle Corporation;Corporate Architecture: Linux Projects Group
adr:;;1015 Granger Avenue;Ann Arbor;MI;48104;USA
title:Principal Member of Staff
tel;work:+1 248 614 5091
x-mozilla-html:FALSE
url:http://oss.oracle.com/~cel/
version:2.1
end:vcard
^ permalink raw reply [flat|nested] 4+ messages in thread* Re: [PATCH 08/13] NFS: Add functions to parse nfs mount options to fs/nfs/super.c
2007-05-29 21:08 ` Chuck Lever
@ 2007-05-30 0:18 ` Karel Zak
0 siblings, 0 replies; 4+ messages in thread
From: Karel Zak @ 2007-05-30 0:18 UTC (permalink / raw)
To: Chuck Lever; +Cc: akpm, linux-fsdevel
On Tue, May 29, 2007 at 05:08:01PM -0400, Chuck Lever wrote:
> Karel Zak wrote:
> >On Mon, May 21, 2007 at 12:09:54PM -0400, Chuck Lever wrote:
> >>For NFSv2 and NFSv3 mount options.
> >>Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
> >
> > ....
> >
> >>+static int nfs_parse_options(char *raw, struct nfs_mount_args *mnt)
> >>+{
> >>+ char *p, *string;
> >>+
> >>+ if (!raw) {
> >>+ dprintk("NFS: mount options string was NULL.\n");
> >>+ return 1;
> >>+ }
> >>+
> >>+ while ((p = strsep (&raw, ",")) != NULL) {
> >>+ substring_t args[MAX_OPT_ARGS];
> >>+ int option, token;
> >>+
> >>+ if (!*p)
> >>+ continue;
> >>+ token = match_token(p, nfs_tokens, args);
> >
> > ....
> >
> >>+
> >>+ case Opt_context:
> >>+ match_strcpy(mnt->nmd.context, args);
> >>+ break;
> >
> > The userspace version (nfs-utils) of this code supports a quoted
> > context strings. For example:
> >
> > context="aaa,bbb,ccc",hard
> >
> > It seems your code blindly parses a raw option string by ",".
>
> Karel-
>
> I've never used the context= option, and didn't find any documentation
> describing how it was used.
That's SELinux stuff. See original discussion:
http://thread.gmane.org/gmane.linux.redhat.security.lspp/1002/focus=1004
There are also fscontext, defcontext and context for normal (non-NFS)
mounts. See the mount.8 patch (where is basic docs):
http://git.kernel.org/?p=utils/util-linux-ng/util-linux-ng.git;a=blobdiff;f=mount/mount.8;h=8ed5a11b77985c8da2dcac4602a67f8785a95070;hp=4692a42b3487b8e0db6dc0b7d17cfd214e8aefc8;hb=3a620ba4bffade41d81c429560c40bb65c9b81a7;hpb=6573c985a4077fa7d50ccb993bae177526fde8ec
> Is there a clean example of how to use the in-kernel parser to handle
> quoted strings containing commas?
Not sure.
It was introduced by "[PATCH] SELinux: support mls categories for context
mounts":
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=3528a95322b5c1ce882ab723f175a1845430cd89
The SELinux specific options are extracted from mount options by the
sb_copy_data hook (fs/super.c, vfs_kern_mount()) -- that's probably
transparent for all filesystems, maybe for your NFS options too. (I
didn't study it in detail.)
Karel
--
Karel Zak <kzak@redhat.com>
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2007-05-30 0:18 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-05-21 16:09 [PATCH 08/13] NFS: Add functions to parse nfs mount options to fs/nfs/super.c Chuck Lever
2007-05-29 20:21 ` Karel Zak
2007-05-29 21:08 ` Chuck Lever
2007-05-30 0:18 ` Karel Zak
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).