Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 5 Oct 2002 06:48:10 +0000
From:      Dima Dorfman <dima@trit.org>
To:        fs@freebsd.org
Cc:        rwatson@freebsd.org
Subject:   Retrieving filesystem-specific mount parameters from the kernel
Message-ID:  <20021005064810.GF26530@trit.org>

next in thread | raw e-mail | index | archive | help
[ rwatson cc'd because I want him to be aware of this possible abuse
  of extended attributes. ]

It is occasionally desirable to display filesystem-specific mount
parameters in the output of mount(8).  For example, it would be useful
if one could tell whether an NFS mount was tcp or udp, v2 or v3, etc.;
likewise, it would be useful if one could tell which ruleset is
associated with a particular devfs mount.  This kind of information is
traditionally included in 'struct statfs', but this doesn't scale well
(since it requires breaking the ABI whenever we add a new filesystem)
and doesn't work at all for third-party filesystems.  I propose for
the filesystem to export this information via an extended attribute
(idea courtesy of Boris Popov).  This is entirely backwards and
forwards compatible, and is easy to implement even in third-party
filesystems.

The following patch implements the framework (which is basically a few
#defines and code in mount(8) to read the extattrs) and exports
information out of NFS and DEVFS as described above.  The output looks
like this:

	dima@hornet% ./mount 
	63.198.170.138:/n/root/hornet on / (nfs, read-only, v3, tcp)
	devfs on /dev (devfs, local, ruleset 0)
	/dev/md0 on /etc (ufs, local, soft-updates)
	procfs on /proc (procfs, local)
	/dev/md1 on /var (ufs, local, soft-updates)
	phalanx:/n on /n (nfs, v3, tcp)
	phalanx:/n/local/hornet on /usr/local (nfs, v3, tcp)
	/dev/md2 on /tmp (ufs, local, soft-updates)
	pid269@hornet:/host on /host (nfs, v2, udp, intr)

Comments?  Objections?

Thanks,

Dima.

Index: sbin/mount/mount.c
===================================================================
RCS file: /ref/cvsf/src/sbin/mount/mount.c,v
retrieving revision 1.49
diff -u -r1.49 mount.c
--- sbin/mount/mount.c	21 Aug 2002 18:10:52 -0000	1.49
+++ sbin/mount/mount.c	4 Oct 2002 05:54:19 -0000
@@ -46,6 +46,7 @@
 #endif /* not lint */
 
 #include <sys/param.h>
+#include <sys/extattr.h>
 #include <sys/mount.h>
 #include <sys/stat.h>
 #include <sys/wait.h>
@@ -526,6 +527,9 @@
 	int flags;
 	struct opt *o;
 	struct passwd *pw;
+	const char *attrname;
+	char *buf;
+	ssize_t rv;
 
 	(void)printf("%s on %s (%s", sfp->f_mntfromname, sfp->f_mntonname,
 	    sfp->f_fstypename);
@@ -536,6 +540,22 @@
 			(void)printf(", %s", o->o_name);
 			flags &= ~o->o_opt;
 		}
+	attrname = verbose ? MOUNTPARAM_EXTATTR_VERBOSE_NAME :
+	    MOUNTPARAM_EXTATTR_NAME;
+	rv = extattr_get_file(sfp->f_mntonname, MOUNTPARAM_EXTATTR_NAMESPACE,
+	    attrname, NULL, 0);
+	if (rv > 0) {
+		buf = malloc(rv);
+		if (buf == NULL)
+			errx(1, "malloc failed");
+		rv = extattr_get_file(sfp->f_mntonname,
+		    MOUNTPARAM_EXTATTR_NAMESPACE, attrname, buf, rv);
+		if (rv == -1)
+			err(1, "extattr_get_file: %s", sfp->f_mntonname);
+		(void)printf(", %.*s", rv, buf);
+		free(buf);
+	} else if (rv == -1 && errno != EOPNOTSUPP && errno != ENOENT)
+		err(1, "extattr_get_file: %s", sfp->f_mntonname);
 	if (sfp->f_owner) {
 		(void)printf(", mounted by ");
 		if ((pw = getpwuid(sfp->f_owner)) != NULL)
Index: sys/sys/mount.h
===================================================================
RCS file: /ref/cvsf/src/sys/sys/mount.h,v
retrieving revision 1.140
diff -u -r1.140 mount.h
--- sys/sys/mount.h	19 Aug 2002 06:52:21 -0000	1.140
+++ sys/sys/mount.h	2 Oct 2002 04:11:52 -0000
@@ -359,6 +359,14 @@
 #define	VFCF_LOOPBACK	0x00100000	/* aliases some other mounted FS */
 #define	VFCF_UNICODE	0x00200000	/* stores file names as Unicode*/
 
+/*
+ * Pseudo-attributes to retrieve filesystem mount parameters in
+ * user-readable form.
+ */
+#define	MOUNTPARAM_EXTATTR_NAMESPACE	EXTATTR_NAMESPACE_SYSTEM
+#define	MOUNTPARAM_EXTATTR_NAME		"mountparams"
+#define	MOUNTPARAM_EXTATTR_VERBOSE_NAME	"mountparams.verbose"
+
 #ifdef _KERNEL
 
 #ifdef MALLOC_DECLARE
Index: sys/fs/devfs/devfs_vnops.c
===================================================================
RCS file: /ref/cvsf/src/sys/fs/devfs/devfs_vnops.c,v
retrieving revision 1.49
diff -u -r1.49 devfs_vnops.c
--- sys/fs/devfs/devfs_vnops.c	1 Oct 2002 10:08:08 -0000	1.49
+++ sys/fs/devfs/devfs_vnops.c	4 Oct 2002 06:03:23 -0000
@@ -53,17 +53,20 @@
 #include <sys/lock.h>
 #include <sys/mac.h>
 #include <sys/malloc.h>
+#include <sys/extattr.h>
 #include <sys/mount.h>
 #include <sys/namei.h>
 #include <sys/proc.h>
 #include <sys/time.h>
 #include <sys/unistd.h>
 #include <sys/vnode.h>
+#include <sys/sbuf.h>
 
 #include <fs/devfs/devfs.h>
 
 static int	devfs_access(struct vop_access_args *ap);
 static int	devfs_getattr(struct vop_getattr_args *ap);
+static int	devfs_getextattr(struct vop_getextattr_args *ap);
 static int	devfs_ioctl(struct vop_ioctl_args *ap);
 static int	devfs_lookupx(struct vop_lookup_args *ap);
 static int	devfs_mknod(struct vop_mknod_args *ap);
@@ -260,6 +263,47 @@
 	return (error);
 }
 
+int
+devfs_getextattr(ap)
+	struct vop_getextattr_args /* {
+		struct vnode *a_vp;
+		int a_attrnamespace;
+		const char *a_name;
+		struct uio *a_uio;
+		size_t *a_size;
+		struct ucred *a_cred;
+		struct thread *a_td;
+	} */ *ap;
+{
+	struct devfs_mount *dmp = VFSTODEVFS(ap->a_vp->v_mount);
+	int error, outl;
+	struct sbuf *sb;
+	char *outp;
+
+	error = 0;
+	if (ap->a_attrnamespace != MOUNTPARAM_EXTATTR_NAMESPACE)
+		return (ENOENT);
+	if (strcmp(ap->a_name, MOUNTPARAM_EXTATTR_NAME) == 0 ||
+	    strcmp(ap->a_name, MOUNTPARAM_EXTATTR_VERBOSE_NAME) == 0) {
+		sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND);
+		if (sb == NULL)
+			return (ENOMEM);
+		sbuf_printf(sb, "ruleset %d", dmp->dm_ruleset);
+
+		KASSERT(!sbuf_overflowed(sb), ("autoextending sbuf overflow"));
+		sbuf_finish(sb);
+		outp = sbuf_data(sb);
+		outl = sbuf_len(sb);
+		if (ap->a_size != NULL)
+			*ap->a_size = outl;
+		if (ap->a_uio != NULL)
+			error = uiomove(outp, outl, ap->a_uio);
+		sbuf_delete(sb);
+	} else
+		error = ENOENT;
+	return (error);
+}
+
 static int
 devfs_ioctl(ap)
 	struct vop_ioctl_args /* {
@@ -882,6 +926,7 @@
 	{ &vop_default_desc,		(vop_t *) vop_defaultop },
 	{ &vop_access_desc,		(vop_t *) devfs_access },
 	{ &vop_getattr_desc,		(vop_t *) devfs_getattr },
+	{ &vop_getextattr_desc,		(vop_t *) devfs_getextattr },
 	{ &vop_ioctl_desc,		(vop_t *) devfs_ioctl },
 	{ &vop_islocked_desc,		(vop_t *) vop_stdislocked },
 	{ &vop_lock_desc,		(vop_t *) vop_stdlock },
Index: sys/nfsclient/nfs_vnops.c
===================================================================
RCS file: /ref/cvsf/src/sys/nfsclient/nfs_vnops.c,v
retrieving revision 1.188
diff -u -r1.188 nfs_vnops.c
--- sys/nfsclient/nfs_vnops.c	25 Sep 2002 02:38:43 -0000	1.188
+++ sys/nfsclient/nfs_vnops.c	4 Oct 2002 06:00:58 -0000
@@ -63,6 +63,8 @@
 #include <sys/lockf.h>
 #include <sys/stat.h>
 #include <sys/sysctl.h>
+#include <sys/extattr.h>
+#include <sys/sbuf.h>
 
 #include <vm/vm.h>
 #include <vm/vm_extern.h>
@@ -131,6 +133,7 @@
 static int	nfs_readlink(struct vop_readlink_args *);
 static int	nfs_print(struct vop_print_args *);
 static int	nfs_advlock(struct vop_advlock_args *);
+static int	nfs_getextattr(struct vop_getextattr_args *);
 
 /*
  * Global vfs data structures for nfs
@@ -144,6 +147,7 @@
 	{ &vop_create_desc,		(vop_t *) nfs_create },
 	{ &vop_fsync_desc,		(vop_t *) nfs_fsync },
 	{ &vop_getattr_desc,		(vop_t *) nfs_getattr },
+	{ &vop_getextattr_desc,		(vop_t *) nfs_getextattr },
 	{ &vop_getpages_desc,		(vop_t *) nfs_getpages },
 	{ &vop_putpages_desc,		(vop_t *) nfs_putpages },
 	{ &vop_inactive_desc,		(vop_t *) nfs_inactive },
@@ -2952,6 +2956,53 @@
 	}
 
 	return (0);
+}
+
+/*
+ * Get extended attributes.  Currently, this is only used to retrieve
+ * filesystem-specific mount parameterts for consumption by mount(8).
+ */
+static int
+nfs_getextattr(struct vop_getextattr_args *ap)
+{
+	struct nfsmount *nmp = VFSTONFS(ap->a_vp->v_mount);
+	int error, outl, verbose;
+	struct sbuf *sb;
+	char *outp;
+
+	if (ap->a_attrnamespace != MOUNTPARAM_EXTATTR_NAMESPACE)
+		return (ENOENT);
+	if (strcmp(ap->a_name, MOUNTPARAM_EXTATTR_NAME) == 0)
+		verbose = 0;
+	else if (strcmp(ap->a_name, MOUNTPARAM_EXTATTR_VERBOSE_NAME) == 0)
+		verbose = 1;
+	else
+		return (ENOENT);
+
+	sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND);
+	if (sb == NULL)
+		return (ENOMEM);
+	sbuf_printf(sb, "%s", nmp->nm_flag & NFSMNT_NFSV3 ? "v3" : "v2");
+	sbuf_printf(sb, ", %s", nmp->nm_sotype == SOCK_DGRAM ? "udp" : "tcp");
+	if (nmp->nm_flag & NFSMNT_SOFT)
+		sbuf_cat(sb, ", soft");
+	else if (verbose)
+		sbuf_cat(sb, ", hard");
+	if (nmp->nm_flag & NFSMNT_INT)
+		sbuf_cat(sb, ", intr");
+	
+	KASSERT(!sbuf_overflowed(sb), ("autoextending sbuf overflow"));
+	sbuf_finish(sb);
+	outp = sbuf_data(sb);
+	outl = sbuf_len(sb);
+	if (ap->a_size != NULL)
+		*ap->a_size = outl;
+	if (ap->a_uio != NULL)
+		error = uiomove(outp, outl, ap->a_uio);
+	else
+		error = 0;
+	sbuf_delete(sb);
+	return (error);
 }
 
 /*

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-fs" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20021005064810.GF26530>