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>