Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src Implement extended attribute listing for UFS1.



details:   https://anonhg.NetBSD.org/src/rev/2dd88aa55f43
branches:  trunk
changeset: 766557:2dd88aa55f43
user:      manu <manu%NetBSD.org@localhost>
date:      Mon Jun 27 16:34:47 2011 +0000

description:
Implement extended attribute listing for UFS1.

Modify lsextattr(8) so that it does not expect each attribute name to be
prefixed by its length. This enable extattr_list_(file|link|fd) to
return a buffer matching its documentation. This also makes the interface
similar to what Linux and FUSE do, which is nice for interoperability.

Note that since we had no EA implementation supporting listing, we do
not break anything.

diffstat:

 sys/ufs/ffs/ffs_vnops.c      |   18 +-
 sys/ufs/ufs/ufs_extattr.c    |  323 ++++++++++++++++++++++++++----------------
 usr.bin/extattr/getextattr.c |    5 +-
 3 files changed, 215 insertions(+), 131 deletions(-)

diffs (truncated from 470 to 300 lines):

diff -r 441ebb846586 -r 2dd88aa55f43 sys/ufs/ffs/ffs_vnops.c
--- a/sys/ufs/ffs/ffs_vnops.c   Mon Jun 27 15:56:36 2011 +0000
+++ b/sys/ufs/ffs/ffs_vnops.c   Mon Jun 27 16:34:47 2011 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ffs_vnops.c,v 1.119 2011/06/12 03:36:00 rmind Exp $    */
+/*     $NetBSD: ffs_vnops.c,v 1.120 2011/06/27 16:34:47 manu Exp $     */
 
 /*-
  * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
@@ -61,7 +61,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ffs_vnops.c,v 1.119 2011/06/12 03:36:00 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ffs_vnops.c,v 1.120 2011/06/27 16:34:47 manu Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_ffs.h"
@@ -736,9 +736,19 @@
        struct inode *ip = VTOI(ap->a_vp);
        struct fs *fs = ip->i_fs;
 
-       /* Not supported for UFS1 file systems. */
-       if (fs->fs_magic == FS_UFS1_MAGIC)
+       if (fs->fs_magic == FS_UFS1_MAGIC) {
+#ifdef UFS_EXTATTR
+               struct vnode *vp = ap->a_vp;
+               int error;
+
+               fstrans_start(vp->v_mount, FSTRANS_SHARED);
+               error = ufs_listextattr(ap);
+               fstrans_done(vp->v_mount);
+               return error;
+#else
                return (EOPNOTSUPP);
+#endif
+       }
 
        /* XXX Not implemented for UFS2 file systems. */
        return (EOPNOTSUPP);
diff -r 441ebb846586 -r 2dd88aa55f43 sys/ufs/ufs/ufs_extattr.c
--- a/sys/ufs/ufs/ufs_extattr.c Mon Jun 27 15:56:36 2011 +0000
+++ b/sys/ufs/ufs/ufs_extattr.c Mon Jun 27 16:34:47 2011 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ufs_extattr.c,v 1.32 2011/06/17 14:23:52 manu Exp $    */
+/*     $NetBSD: ufs_extattr.c,v 1.33 2011/06/27 16:34:47 manu Exp $    */
 
 /*-
  * Copyright (c) 1999-2002 Robert N. M. Watson
@@ -48,7 +48,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ufs_extattr.c,v 1.32 2011/06/17 14:23:52 manu Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ufs_extattr.c,v 1.33 2011/06/27 16:34:47 manu Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_ffs.h"
@@ -95,6 +95,9 @@
 static int     ufs_extattr_get(struct vnode *vp, int attrnamespace,
                    const char *name, struct uio *uio, size_t *size,
                    kauth_cred_t cred, struct lwp *l);
+static int     ufs_extattr_list(struct vnode *vp, int attrnamespace,
+                   struct uio *uio, size_t *size,
+                   kauth_cred_t cred, struct lwp *l);
 static int     ufs_extattr_set(struct vnode *vp, int attrnamespace,
                    const char *name, struct uio *uio, kauth_cred_t cred,
                    struct lwp *l);
@@ -102,6 +105,9 @@
                    const char *name, kauth_cred_t cred, struct lwp *l);
 static struct ufs_extattr_list_entry *ufs_extattr_find_attr(struct ufsmount *,
                    int, const char *);
+static int     ufs_extattr_get_header(struct vnode *, 
+                   struct ufs_extattr_list_entry *, 
+                   struct ufs_extattr_header *, off_t *);
 
 /*
  * Per-FS attribute lock protecting attribute operations.
@@ -925,6 +931,86 @@
 }
 
 /*
+ * Read extended attribute header for a given vnode and attribute.
+ * Backing vnode should be locked and unlocked by caller.
+ */
+static int
+ufs_extattr_get_header(struct vnode *vp, struct ufs_extattr_list_entry *uele,
+    struct ufs_extattr_header *ueh, off_t *bap)
+{
+       struct mount *mp = vp->v_mount;
+       struct ufsmount *ump = VFSTOUFS(mp);
+       struct inode *ip = VTOI(vp);
+       off_t base_offset;
+       struct iovec aiov;
+       struct uio aio;
+       int error;
+
+       /*
+        * Find base offset of header in file based on file header size, and
+        * data header size + maximum data size, indexed by inode number.
+        */
+       base_offset = sizeof(struct ufs_extattr_fileheader) +
+           ip->i_number * (sizeof(struct ufs_extattr_header) +
+           uele->uele_fileheader.uef_size);
+
+       /*
+        * Read in the data header to see if the data is defined, and if so
+        * how much.
+        */
+       memset(ueh, 0, sizeof(struct ufs_extattr_header));
+       aiov.iov_base = ueh;
+       aiov.iov_len = sizeof(struct ufs_extattr_header);
+       aio.uio_iov = &aiov;
+       aio.uio_iovcnt = 1;
+       aio.uio_rw = UIO_READ;
+       aio.uio_offset = base_offset;
+       aio.uio_resid = sizeof(struct ufs_extattr_header);
+       UIO_SETUP_SYSSPACE(&aio);
+
+       error = VOP_READ(uele->uele_backing_vnode, &aio,
+           IO_NODELOCKED, ump->um_extattr.uepm_ucred);
+       if (error)
+               return error;
+
+       /*
+        * Attribute headers are kept in file system byte order.
+        * XXX What about the blob of data?
+        */
+       ueh->ueh_flags = ufs_rw32(ueh->ueh_flags, UELE_NEEDSWAP(uele));
+       ueh->ueh_len   = ufs_rw32(ueh->ueh_len, UELE_NEEDSWAP(uele));
+       ueh->ueh_i_gen = ufs_rw32(ueh->ueh_i_gen, UELE_NEEDSWAP(uele));
+
+       /* Defined? */
+       if ((ueh->ueh_flags & UFS_EXTATTR_ATTR_FLAG_INUSE) == 0)
+               return ENOATTR;
+
+       /* Valid for the current inode generation? */
+       if (ueh->ueh_i_gen != ip->i_gen) {
+               /*
+                * The inode itself has a different generation number
+                * than the uele data.  For now, the best solution
+                * is to coerce this to undefined, and let it get cleaned
+                * up by the next write or extattrctl clean.
+                */
+               printf("%s (%s): inode gen inconsistency (%u, %jd)\n",
+                      __func__,  mp->mnt_stat.f_mntonname, ueh->ueh_i_gen,
+                      (intmax_t)ip->i_gen);
+               return ENOATTR;
+       }
+
+       /* Local size consistency check. */
+       if (ueh->ueh_len > uele->uele_fileheader.uef_size)
+               return ENXIO;
+
+       /* Return base offset */
+       if (bap != NULL)
+               *bap = base_offset;
+
+       return 0;
+}
+
+/*
  * Vnode operation to retrieve a named extended attribute.
  */
 int
@@ -964,11 +1050,8 @@
 {
        struct ufs_extattr_list_entry *attribute;
        struct ufs_extattr_header ueh;
-       struct iovec local_aiov;
-       struct uio local_aio;
        struct mount *mp = vp->v_mount;
        struct ufsmount *ump = VFSTOUFS(mp);
-       struct inode *ip = VTOI(vp);
        off_t base_offset;
        size_t len, old_len;
        int error = 0;
@@ -996,75 +1079,16 @@
                return (ENXIO);
 
        /*
-        * Find base offset of header in file based on file header size, and
-        * data header size + maximum data size, indexed by inode number.
-        */
-       base_offset = sizeof(struct ufs_extattr_fileheader) +
-           ip->i_number * (sizeof(struct ufs_extattr_header) +
-           attribute->uele_fileheader.uef_size);
-
-       /*
-        * Read in the data header to see if the data is defined, and if so
-        * how much.
-        */
-       memset(&ueh, 0, sizeof(struct ufs_extattr_header));
-       local_aiov.iov_base = &ueh;
-       local_aiov.iov_len = sizeof(struct ufs_extattr_header);
-       local_aio.uio_iov = &local_aiov;
-       local_aio.uio_iovcnt = 1;
-       local_aio.uio_rw = UIO_READ;
-       local_aio.uio_offset = base_offset;
-       local_aio.uio_resid = sizeof(struct ufs_extattr_header);
-       UIO_SETUP_SYSSPACE(&local_aio);
-
-       /*
         * Don't need to get a lock on the backing file if the getattr is
         * being applied to the backing file, as the lock is already held.
         */
        if (attribute->uele_backing_vnode != vp)
-               vn_lock(attribute->uele_backing_vnode, LK_SHARED |
-                   LK_RETRY);
+               vn_lock(attribute->uele_backing_vnode, LK_SHARED | LK_RETRY);
 
-       error = VOP_READ(attribute->uele_backing_vnode, &local_aio,
-           IO_NODELOCKED, ump->um_extattr.uepm_ucred);
+       error = ufs_extattr_get_header(vp, attribute, &ueh, &base_offset);
        if (error)
                goto vopunlock_exit;
 
-       /*
-        * Attribute headers are kept in file system byte order.
-        * XXX What about the blob of data?
-        */
-       ueh.ueh_flags = ufs_rw32(ueh.ueh_flags, UELE_NEEDSWAP(attribute));
-       ueh.ueh_len   = ufs_rw32(ueh.ueh_len, UELE_NEEDSWAP(attribute));
-       ueh.ueh_i_gen = ufs_rw32(ueh.ueh_i_gen, UELE_NEEDSWAP(attribute));
-
-       /* Defined? */
-       if ((ueh.ueh_flags & UFS_EXTATTR_ATTR_FLAG_INUSE) == 0) {
-               error = ENOATTR;
-               goto vopunlock_exit;
-       }
-
-       /* Valid for the current inode generation? */
-       if (ueh.ueh_i_gen != ip->i_gen) {
-               /*
-                * The inode itself has a different generation number
-                * than the attribute data.  For now, the best solution
-                * is to coerce this to undefined, and let it get cleaned
-                * up by the next write or extattrctl clean.
-                */
-               printf("ufs_extattr_get (%s): inode gen inconsistency (%u, %jd)\n",
-                   mp->mnt_stat.f_mntonname, ueh.ueh_i_gen,
-                   (intmax_t)ip->i_gen);
-               error = ENOATTR;
-               goto vopunlock_exit;
-       }
-
-       /* Local size consistency check. */
-       if (ueh.ueh_len > attribute->uele_fileheader.uef_size) {
-               error = ENXIO;
-               goto vopunlock_exit;
-       }
-
        /* Return full data size if caller requested it. */
        if (size != NULL)
                *size = ueh.ueh_len;
@@ -1103,6 +1127,109 @@
 }
 
 /*
+ * Vnode operation to list extended attribute for a vnode
+ */
+int
+ufs_listextattr(struct vop_listextattr_args *ap)
+/*
+vop_listextattr {
+       IN struct vnode *a_vp;
+       IN int a_attrnamespace;
+       INOUT struct uio *a_uio;
+       OUT size_t *a_size;
+       IN kauth_cred_t a_cred;
+       struct proc *a_p;
+};
+*/
+{
+       struct mount *mp = ap->a_vp->v_mount;
+       struct ufsmount *ump = VFSTOUFS(mp);
+       int error;
+
+       ufs_extattr_uepm_lock(ump);
+
+       error = ufs_extattr_list(ap->a_vp, ap->a_attrnamespace,
+           ap->a_uio, ap->a_size, ap->a_cred, curlwp);
+
+       ufs_extattr_uepm_unlock(ump);
+
+       return (error);
+}
+
+/*
+ * Real work associated with retrieving list of attributes--assumes that
+ * the attribute lock has already been grabbed.
+ */
+static int
+ufs_extattr_list(struct vnode *vp, int attrnamespace,
+    struct uio *uio, size_t *size, kauth_cred_t cred, struct lwp *l)
+{
+       struct ufs_extattr_list_entry *uele;
+       struct ufs_extattr_header ueh;
+       struct mount *mp = vp->v_mount;
+       struct ufsmount *ump = VFSTOUFS(mp);



Home | Main Index | Thread Index | Old Index