[XFS] Add EA list callbacks for xfs kernel use. Cleanup some namespace
authorTim Shimmin <tes@sgi.com>
Thu, 28 Sep 2006 01:01:37 +0000 (11:01 +1000)
committerTim Shimmin <tes@sgi.com>
Thu, 28 Sep 2006 01:01:37 +0000 (11:01 +1000)
code.

SGI-PV: 954372
SGI-Modid: xfs-linux-melb:xfs-kern:26583a

Signed-off-by: Tim Shimmin <tes@sgi.com>
fs/xfs/xfs_attr.c
fs/xfs/xfs_attr.h
fs/xfs/xfs_attr_leaf.c
fs/xfs/xfs_attr_leaf.h

index 1a21010..9ada7bd 100644 (file)
@@ -91,7 +91,6 @@ STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
 /*
  * Routines to manipulate out-of-line attribute values.
  */
-STATIC int xfs_attr_rmtval_get(xfs_da_args_t *args);
 STATIC int xfs_attr_rmtval_set(xfs_da_args_t *args);
 STATIC int xfs_attr_rmtval_remove(xfs_da_args_t *args);
 
@@ -180,7 +179,7 @@ xfs_attr_get(bhv_desc_t *bdp, const char *name, char *value, int *valuelenp,
        return(error);
 }
 
-STATIC int
+int
 xfs_attr_set_int(xfs_inode_t *dp, const char *name, int namelen,
                 char *value, int valuelen, int flags)
 {
@@ -440,7 +439,7 @@ xfs_attr_set(bhv_desc_t *bdp, const char *name, char *value, int valuelen, int f
  * Generic handler routine to remove a name from an attribute list.
  * Transitions attribute list from Btree to shortform as necessary.
  */
-STATIC int
+int
 xfs_attr_remove_int(xfs_inode_t *dp, const char *name, int namelen, int flags)
 {
        xfs_da_args_t   args;
@@ -591,6 +590,110 @@ xfs_attr_remove(bhv_desc_t *bdp, const char *name, int flags, struct cred *cred)
        return xfs_attr_remove_int(dp, name, namelen, flags);
 }
 
+int                                                            /* error */
+xfs_attr_list_int(xfs_attr_list_context_t *context)
+{
+       int error;
+       xfs_inode_t *dp = context->dp;
+
+       /*
+        * Decide on what work routines to call based on the inode size.
+        */
+       if (XFS_IFORK_Q(dp) == 0 ||
+           (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
+            dp->i_d.di_anextents == 0)) {
+               error = 0;
+       } else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
+               error = xfs_attr_shortform_list(context);
+       } else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
+               error = xfs_attr_leaf_list(context);
+       } else {
+               error = xfs_attr_node_list(context);
+       }
+       return error;
+}
+
+#define        ATTR_ENTBASESIZE                /* minimum bytes used by an attr */ \
+       (((struct attrlist_ent *) 0)->a_name - (char *) 0)
+#define        ATTR_ENTSIZE(namelen)           /* actual bytes used by an attr */ \
+       ((ATTR_ENTBASESIZE + (namelen) + 1 + sizeof(u_int32_t)-1) \
+        & ~(sizeof(u_int32_t)-1))
+
+/*
+ * Format an attribute and copy it out to the user's buffer.
+ * Take care to check values and protect against them changing later,
+ * we may be reading them directly out of a user buffer.
+ */
+/*ARGSUSED*/
+STATIC int
+xfs_attr_put_listent(xfs_attr_list_context_t *context, attrnames_t *namesp,
+                    char *name, int namelen,
+                    int valuelen, char *value)
+{
+       attrlist_ent_t *aep;
+       int arraytop;
+
+       ASSERT(!(context->flags & ATTR_KERNOVAL));
+       ASSERT(context->count >= 0);
+       ASSERT(context->count < (ATTR_MAX_VALUELEN/8));
+       ASSERT(context->firstu >= sizeof(*context->alist));
+       ASSERT(context->firstu <= context->bufsize);
+
+       arraytop = sizeof(*context->alist) +
+                       context->count * sizeof(context->alist->al_offset[0]);
+       context->firstu -= ATTR_ENTSIZE(namelen);
+       if (context->firstu < arraytop) {
+               xfs_attr_trace_l_c("buffer full", context);
+               context->alist->al_more = 1;
+               context->seen_enough = 1;
+               return 1;
+       }
+
+       aep = (attrlist_ent_t *)&(((char *)context->alist)[ context->firstu ]);
+       aep->a_valuelen = valuelen;
+       memcpy(aep->a_name, name, namelen);
+       aep->a_name[ namelen ] = 0;
+       context->alist->al_offset[ context->count++ ] = context->firstu;
+       context->alist->al_count = context->count;
+       xfs_attr_trace_l_c("add", context);
+       return 0;
+}
+
+STATIC int
+xfs_attr_kern_list(xfs_attr_list_context_t *context, attrnames_t *namesp,
+                    char *name, int namelen,
+                    int valuelen, char *value)
+{
+       char *offset;
+       int arraytop;
+
+       ASSERT(context->count >= 0);
+
+       arraytop = context->count + namesp->attr_namelen + namelen + 1;
+       if (arraytop > context->firstu) {
+               context->count = -1;    /* insufficient space */
+               return 1;
+       }
+       offset = (char *)context->alist + context->count;
+       strncpy(offset, namesp->attr_name, namesp->attr_namelen);
+       offset += namesp->attr_namelen;
+       strncpy(offset, name, namelen);                 /* real name */
+       offset += namelen;
+       *offset = '\0';
+       context->count += namesp->attr_namelen + namelen + 1;
+       return 0;
+}
+
+/*ARGSUSED*/
+STATIC int
+xfs_attr_kern_list_sizes(xfs_attr_list_context_t *context, attrnames_t *namesp,
+                    char *name, int namelen,
+                    int valuelen, char *value)
+{
+       context->count += namesp->attr_namelen + namelen + 1;
+       return 0;
+}
+
 /*
  * Generate a list of extended attribute names and optionally
  * also value lengths.  Positive return value follows the XFS
@@ -615,13 +718,13 @@ xfs_attr_list(bhv_desc_t *bdp, char *buffer, int bufsize, int flags,
                return(XFS_ERROR(EINVAL));
        if ((cursor->initted == 0) &&
            (cursor->hashval || cursor->blkno || cursor->offset))
-               return(XFS_ERROR(EINVAL));
+               return XFS_ERROR(EINVAL);
 
        /*
         * Check for a properly aligned buffer.
         */
        if (((long)buffer) & (sizeof(int)-1))
-               return(XFS_ERROR(EFAULT));
+               return XFS_ERROR(EFAULT);
        if (flags & ATTR_KERNOVAL)
                bufsize = 0;
 
@@ -634,53 +737,47 @@ xfs_attr_list(bhv_desc_t *bdp, char *buffer, int bufsize, int flags,
        context.dupcnt = 0;
        context.resynch = 1;
        context.flags = flags;
-       if (!(flags & ATTR_KERNAMELS)) {
+       context.seen_enough = 0;
+       context.alist = (attrlist_t *)buffer;
+       context.put_value = 0;
+
+       if (flags & ATTR_KERNAMELS) {
+               context.bufsize = bufsize;
+               context.firstu = context.bufsize;
+               if (flags & ATTR_KERNOVAL)
+                       context.put_listent = xfs_attr_kern_list_sizes;
+               else
+                       context.put_listent = xfs_attr_kern_list;
+       } else {
                context.bufsize = (bufsize & ~(sizeof(int)-1));  /* align */
                context.firstu = context.bufsize;
-               context.alist = (attrlist_t *)buffer;
                context.alist->al_count = 0;
                context.alist->al_more = 0;
                context.alist->al_offset[0] = context.bufsize;
-       }
-       else {
-               context.bufsize = bufsize;
-               context.firstu = context.bufsize;
-               context.alist = (attrlist_t *)buffer;
+               context.put_listent = xfs_attr_put_listent;
        }
 
        if (XFS_FORCED_SHUTDOWN(dp->i_mount))
-               return (EIO);
+               return EIO;
 
        xfs_ilock(dp, XFS_ILOCK_SHARED);
-       /*
-        * Decide on what work routines to call based on the inode size.
-        */
        xfs_attr_trace_l_c("syscall start", &context);
-       if (XFS_IFORK_Q(dp) == 0 ||
-           (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
-            dp->i_d.di_anextents == 0)) {
-               error = 0;
-       } else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
-               error = xfs_attr_shortform_list(&context);
-       } else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
-               error = xfs_attr_leaf_list(&context);
-       } else {
-               error = xfs_attr_node_list(&context);
-       }
+
+       error = xfs_attr_list_int(&context);
+
        xfs_iunlock(dp, XFS_ILOCK_SHARED);
        xfs_attr_trace_l_c("syscall end", &context);
 
-       if (!(context.flags & (ATTR_KERNOVAL|ATTR_KERNAMELS))) {
-               ASSERT(error >= 0);
-       }
-       else {  /* must return negated buffer size or the error */
+       if (context.flags & (ATTR_KERNOVAL|ATTR_KERNAMELS)) {
+               /* must return negated buffer size or the error */
                if (context.count < 0)
                        error = XFS_ERROR(ERANGE);
                else
                        error = -context.count;
-       }
+       } else
+               ASSERT(error >= 0);
 
-       return(error);
+       return error;
 }
 
 int                                                            /* error */
@@ -1122,19 +1219,19 @@ xfs_attr_leaf_list(xfs_attr_list_context_t *context)
        context->cursor->blkno = 0;
        error = xfs_da_read_buf(NULL, context->dp, 0, -1, &bp, XFS_ATTR_FORK);
        if (error)
-               return(error);
+               return XFS_ERROR(error);
        ASSERT(bp != NULL);
        leaf = bp->data;
        if (unlikely(be16_to_cpu(leaf->hdr.info.magic) != XFS_ATTR_LEAF_MAGIC)) {
                XFS_CORRUPTION_ERROR("xfs_attr_leaf_list", XFS_ERRLEVEL_LOW,
                                     context->dp->i_mount, leaf);
                xfs_da_brelse(NULL, bp);
-               return(XFS_ERROR(EFSCORRUPTED));
+               return XFS_ERROR(EFSCORRUPTED);
        }
 
-       (void)xfs_attr_leaf_list_int(bp, context);
+       error = xfs_attr_leaf_list_int(bp, context);
        xfs_da_brelse(NULL, bp);
-       return(0);
+       return XFS_ERROR(error);
 }
 
 
@@ -1858,8 +1955,12 @@ xfs_attr_node_list(xfs_attr_list_context_t *context)
                        return(XFS_ERROR(EFSCORRUPTED));
                }
                error = xfs_attr_leaf_list_int(bp, context);
-               if (error || !leaf->hdr.info.forw)
-                       break;  /* not really an error, buffer full or EOF */
+               if (error) {
+                       xfs_da_brelse(NULL, bp);
+                       return error;
+               }
+               if (context->seen_enough || leaf->hdr.info.forw == 0)
+                       break;
                cursor->blkno = be32_to_cpu(leaf->hdr.info.forw);
                xfs_da_brelse(NULL, bp);
                error = xfs_da_read_buf(NULL, context->dp, cursor->blkno, -1,
@@ -1886,7 +1987,7 @@ xfs_attr_node_list(xfs_attr_list_context_t *context)
  * Read the value associated with an attribute from the out-of-line buffer
  * that we stored it in.
  */
-STATIC int
+int
 xfs_attr_rmtval_get(xfs_da_args_t *args)
 {
        xfs_bmbt_irec_t map[ATTR_RMTVALUE_MAPSIZE];
index 981633f..783977d 100644 (file)
@@ -37,6 +37,7 @@
 
 struct cred;
 struct bhv_vnode;
+struct xfs_attr_list_context;
 
 typedef int (*attrset_t)(struct bhv_vnode *, char *, void *, size_t, int);
 typedef int (*attrget_t)(struct bhv_vnode *, char *, void *, size_t, int);
@@ -160,13 +161,16 @@ struct xfs_da_args;
  */
 int xfs_attr_get(bhv_desc_t *, const char *, char *, int *, int, struct cred *);
 int xfs_attr_set(bhv_desc_t *, const char *, char *, int, int, struct cred *);
+int xfs_attr_set_int(struct xfs_inode *, const char *, int, char *, int, int);
 int xfs_attr_remove(bhv_desc_t *, const char *, int, struct cred *);
-int xfs_attr_list(bhv_desc_t *, char *, int, int,
-                        struct attrlist_cursor_kern *, struct cred *);
+int xfs_attr_remove_int(struct xfs_inode *, const char *, int, int);
+int xfs_attr_list(bhv_desc_t *, char *, int, int, struct attrlist_cursor_kern *, struct cred *);
+int xfs_attr_list_int(struct xfs_attr_list_context *);
 int xfs_attr_inactive(struct xfs_inode *dp);
 
 int xfs_attr_shortform_getvalue(struct xfs_da_args *);
 int xfs_attr_fetch(struct xfs_inode *, const char *, int,
                        char *, int *, int, struct cred *);
+int xfs_attr_rmtval_get(struct xfs_da_args *args);
 
 #endif /* __XFS_ATTR_H__ */
index 9455051..9719bbe 100644 (file)
@@ -89,9 +89,46 @@ STATIC void xfs_attr_leaf_moveents(xfs_attr_leafblock_t *src_leaf,
                                         int dst_start, int move_count,
                                         xfs_mount_t *mp);
 STATIC int xfs_attr_leaf_entsize(xfs_attr_leafblock_t *leaf, int index);
-STATIC int xfs_attr_put_listent(xfs_attr_list_context_t *context,
-                            attrnames_t *, char *name, int namelen,
-                            int valuelen);
+
+/*========================================================================
+ * Namespace helper routines
+ *========================================================================*/
+
+STATIC inline attrnames_t *
+xfs_attr_flags_namesp(int flags)
+{
+       return ((flags & XFS_ATTR_SECURE) ? &attr_secure:
+                 ((flags & XFS_ATTR_ROOT) ? &attr_trusted : &attr_user));
+}
+
+/*
+ * If namespace bits don't match return 0.
+ * If all match then return 1.
+ */
+STATIC inline int
+xfs_attr_namesp_match(int arg_flags, int ondisk_flags)
+{
+       return XFS_ATTR_NSP_ONDISK(ondisk_flags) == XFS_ATTR_NSP_ARGS_TO_ONDISK(arg_flags);
+}
+
+/*
+ * If namespace bits don't match and we don't have an override for it
+ * then return 0.
+ * If all match or are overridable then return 1.
+ */
+STATIC inline int
+xfs_attr_namesp_match_overrides(int arg_flags, int ondisk_flags)
+{
+       if (((arg_flags & ATTR_SECURE) == 0) !=
+           ((ondisk_flags & XFS_ATTR_SECURE) == 0) &&
+           !(arg_flags & ATTR_KERNORMALS))
+               return 0;
+       if (((arg_flags & ATTR_ROOT) == 0) !=
+           ((ondisk_flags & XFS_ATTR_ROOT) == 0) &&
+           !(arg_flags & ATTR_KERNROOTLS))
+               return 0;
+       return 1;
+}
 
 
 /*========================================================================
@@ -228,11 +265,7 @@ xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff)
                        continue;
                if (memcmp(args->name, sfe->nameval, args->namelen) != 0)
                        continue;
-               if (((args->flags & ATTR_SECURE) != 0) !=
-                   ((sfe->flags & XFS_ATTR_SECURE) != 0))
-                       continue;
-               if (((args->flags & ATTR_ROOT) != 0) !=
-                   ((sfe->flags & XFS_ATTR_ROOT) != 0))
+               if (!xfs_attr_namesp_match(args->flags, sfe->flags))
                        continue;
                ASSERT(0);
 #endif
@@ -246,8 +279,7 @@ xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff)
 
        sfe->namelen = args->namelen;
        sfe->valuelen = args->valuelen;
-       sfe->flags = (args->flags & ATTR_SECURE) ? XFS_ATTR_SECURE :
-                       ((args->flags & ATTR_ROOT) ? XFS_ATTR_ROOT : 0);
+       sfe->flags = XFS_ATTR_NSP_ARGS_TO_ONDISK(args->flags);
        memcpy(sfe->nameval, args->name, args->namelen);
        memcpy(&sfe->nameval[args->namelen], args->value, args->valuelen);
        sf->hdr.count++;
@@ -282,11 +314,7 @@ xfs_attr_shortform_remove(xfs_da_args_t *args)
                        continue;
                if (memcmp(sfe->nameval, args->name, args->namelen) != 0)
                        continue;
-               if (((args->flags & ATTR_SECURE) != 0) !=
-                   ((sfe->flags & XFS_ATTR_SECURE) != 0))
-                       continue;
-               if (((args->flags & ATTR_ROOT) != 0) !=
-                   ((sfe->flags & XFS_ATTR_ROOT) != 0))
+               if (!xfs_attr_namesp_match(args->flags, sfe->flags))
                        continue;
                break;
        }
@@ -363,11 +391,7 @@ xfs_attr_shortform_lookup(xfs_da_args_t *args)
                        continue;
                if (memcmp(args->name, sfe->nameval, args->namelen) != 0)
                        continue;
-               if (((args->flags & ATTR_SECURE) != 0) !=
-                   ((sfe->flags & XFS_ATTR_SECURE) != 0))
-                       continue;
-               if (((args->flags & ATTR_ROOT) != 0) !=
-                   ((sfe->flags & XFS_ATTR_ROOT) != 0))
+               if (!xfs_attr_namesp_match(args->flags, sfe->flags))
                        continue;
                return(XFS_ERROR(EEXIST));
        }
@@ -394,11 +418,7 @@ xfs_attr_shortform_getvalue(xfs_da_args_t *args)
                        continue;
                if (memcmp(args->name, sfe->nameval, args->namelen) != 0)
                        continue;
-               if (((args->flags & ATTR_SECURE) != 0) !=
-                   ((sfe->flags & XFS_ATTR_SECURE) != 0))
-                       continue;
-               if (((args->flags & ATTR_ROOT) != 0) !=
-                   ((sfe->flags & XFS_ATTR_ROOT) != 0))
+               if (!xfs_attr_namesp_match(args->flags, sfe->flags))
                        continue;
                if (args->flags & ATTR_KERNOVAL) {
                        args->valuelen = sfe->valuelen;
@@ -485,8 +505,7 @@ xfs_attr_shortform_to_leaf(xfs_da_args_t *args)
                nargs.valuelen = sfe->valuelen;
                nargs.hashval = xfs_da_hashname((char *)sfe->nameval,
                                                sfe->namelen);
-               nargs.flags = (sfe->flags & XFS_ATTR_SECURE) ? ATTR_SECURE :
-                               ((sfe->flags & XFS_ATTR_ROOT) ? ATTR_ROOT : 0);
+               nargs.flags = XFS_ATTR_NSP_ONDISK_TO_ARGS(sfe->flags);
                error = xfs_attr_leaf_lookup_int(bp, &nargs); /* set a->index */
                ASSERT(error == ENOATTR);
                error = xfs_attr_leaf_add(bp, &nargs);
@@ -520,6 +539,10 @@ xfs_attr_shortform_compare(const void *a, const void *b)
        }
 }
 
+
+#define XFS_ISRESET_CURSOR(cursor) \
+       (!((cursor)->initted) && !((cursor)->hashval) && \
+        !((cursor)->blkno) && !((cursor)->offset))
 /*
  * Copy out entries of shortform attribute lists for attr_list().
  * Shortform attribute lists are not stored in hashval sorted order.
@@ -537,6 +560,7 @@ xfs_attr_shortform_list(xfs_attr_list_context_t *context)
        xfs_attr_sf_entry_t *sfe;
        xfs_inode_t *dp;
        int sbsize, nsbuf, count, i;
+       int error;
 
        ASSERT(context != NULL);
        dp = context->dp;
@@ -552,46 +576,51 @@ xfs_attr_shortform_list(xfs_attr_list_context_t *context)
        xfs_attr_trace_l_c("sf start", context);
 
        /*
-        * If the buffer is large enough, do not bother with sorting.
+        * If the buffer is large enough and the cursor is at the start,
+        * do not bother with sorting since we will return everything in
+        * one buffer and another call using the cursor won't need to be
+        * made.
         * Note the generous fudge factor of 16 overhead bytes per entry.
+        * If bufsize is zero then put_listent must be a search function
+        * and can just scan through what we have.
         */
-       if ((dp->i_afp->if_bytes + sf->hdr.count * 16) < context->bufsize) {
+       if (context->bufsize == 0 ||
+           (XFS_ISRESET_CURSOR(cursor) &&
+             (dp->i_afp->if_bytes + sf->hdr.count * 16) < context->bufsize)) {
                for (i = 0, sfe = &sf->list[0]; i < sf->hdr.count; i++) {
                        attrnames_t     *namesp;
 
-                       if (((context->flags & ATTR_SECURE) != 0) !=
-                           ((sfe->flags & XFS_ATTR_SECURE) != 0) &&
-                           !(context->flags & ATTR_KERNORMALS)) {
-                               sfe = XFS_ATTR_SF_NEXTENTRY(sfe);
-                               continue;
-                       }
-                       if (((context->flags & ATTR_ROOT) != 0) !=
-                           ((sfe->flags & XFS_ATTR_ROOT) != 0) &&
-                           !(context->flags & ATTR_KERNROOTLS)) {
+                       if (!xfs_attr_namesp_match_overrides(context->flags, sfe->flags)) {
                                sfe = XFS_ATTR_SF_NEXTENTRY(sfe);
                                continue;
                        }
-                       namesp = (sfe->flags & XFS_ATTR_SECURE) ? &attr_secure:
-                               ((sfe->flags & XFS_ATTR_ROOT) ? &attr_trusted :
-                                 &attr_user);
-                       if (context->flags & ATTR_KERNOVAL) {
-                               ASSERT(context->flags & ATTR_KERNAMELS);
-                               context->count += namesp->attr_namelen +
-                                       sfe->namelen + 1;
-                       }
-                       else {
-                               if (xfs_attr_put_listent(context, namesp,
-                                                  (char *)sfe->nameval,
-                                                  (int)sfe->namelen,
-                                                  (int)sfe->valuelen))
-                                       break;
-                       }
+                       namesp = xfs_attr_flags_namesp(sfe->flags);
+                       error = context->put_listent(context,
+                                          namesp,
+                                          (char *)sfe->nameval,
+                                          (int)sfe->namelen,
+                                          (int)sfe->valuelen,
+                                          (char*)&sfe->nameval[sfe->namelen]);
+
+                       /*
+                        * Either search callback finished early or
+                        * didn't fit it all in the buffer after all.
+                        */
+                       if (context->seen_enough)
+                               break;
+
+                       if (error)
+                               return error;
                        sfe = XFS_ATTR_SF_NEXTENTRY(sfe);
                }
                xfs_attr_trace_l_c("sf big-gulp", context);
                return(0);
        }
 
+       /* do no more for a search callback */
+       if (context->bufsize == 0)
+               return 0;
+
        /*
         * It didn't all fit, so we have to sort everything on hashval.
         */
@@ -614,15 +643,7 @@ xfs_attr_shortform_list(xfs_attr_list_context_t *context)
                        kmem_free(sbuf, sbsize);
                        return XFS_ERROR(EFSCORRUPTED);
                }
-               if (((context->flags & ATTR_SECURE) != 0) !=
-                   ((sfe->flags & XFS_ATTR_SECURE) != 0) &&
-                   !(context->flags & ATTR_KERNORMALS)) {
-                       sfe = XFS_ATTR_SF_NEXTENTRY(sfe);
-                       continue;
-               }
-               if (((context->flags & ATTR_ROOT) != 0) !=
-                   ((sfe->flags & XFS_ATTR_ROOT) != 0) &&
-                   !(context->flags & ATTR_KERNROOTLS)) {
+               if (!xfs_attr_namesp_match_overrides(context->flags, sfe->flags)) {
                        sfe = XFS_ATTR_SF_NEXTENTRY(sfe);
                        continue;
                }
@@ -671,24 +692,22 @@ xfs_attr_shortform_list(xfs_attr_list_context_t *context)
        for ( ; i < nsbuf; i++, sbp++) {
                attrnames_t     *namesp;
 
-               namesp = (sbp->flags & XFS_ATTR_SECURE) ? &attr_secure :
-                       ((sbp->flags & XFS_ATTR_ROOT) ? &attr_trusted :
-                         &attr_user);
+               namesp = xfs_attr_flags_namesp(sbp->flags);
 
                if (cursor->hashval != sbp->hash) {
                        cursor->hashval = sbp->hash;
                        cursor->offset = 0;
                }
-               if (context->flags & ATTR_KERNOVAL) {
-                       ASSERT(context->flags & ATTR_KERNAMELS);
-                       context->count += namesp->attr_namelen +
-                                               sbp->namelen + 1;
-               } else {
-                       if (xfs_attr_put_listent(context, namesp,
-                                       sbp->name, sbp->namelen,
-                                       sbp->valuelen))
-                               break;
-               }
+               error = context->put_listent(context,
+                                       namesp,
+                                       sbp->name,
+                                       sbp->namelen,
+                                       sbp->valuelen,
+                                       &sbp->name[sbp->namelen]);
+               if (error)
+                       return error;
+               if (context->seen_enough)
+                       break;
                cursor->offset++;
        }
 
@@ -810,8 +829,7 @@ xfs_attr_leaf_to_shortform(xfs_dabuf_t *bp, xfs_da_args_t *args, int forkoff)
                nargs.value = (char *)&name_loc->nameval[nargs.namelen];
                nargs.valuelen = be16_to_cpu(name_loc->valuelen);
                nargs.hashval = be32_to_cpu(entry->hashval);
-               nargs.flags = (entry->flags & XFS_ATTR_SECURE) ? ATTR_SECURE :
-                             ((entry->flags & XFS_ATTR_ROOT) ? ATTR_ROOT : 0);
+               nargs.flags = XFS_ATTR_NSP_ONDISK_TO_ARGS(entry->flags);
                xfs_attr_shortform_add(&nargs, forkoff);
        }
        error = 0;
@@ -1098,8 +1116,7 @@ xfs_attr_leaf_add_work(xfs_dabuf_t *bp, xfs_da_args_t *args, int mapindex)
                                     be16_to_cpu(map->size));
        entry->hashval = cpu_to_be32(args->hashval);
        entry->flags = tmp ? XFS_ATTR_LOCAL : 0;
-       entry->flags |= (args->flags & ATTR_SECURE) ? XFS_ATTR_SECURE :
-                       ((args->flags & ATTR_ROOT) ? XFS_ATTR_ROOT : 0);
+       entry->flags |= XFS_ATTR_NSP_ARGS_TO_ONDISK(args->flags);
        if (args->rename) {
                entry->flags |= XFS_ATTR_INCOMPLETE;
                if ((args->blkno2 == args->blkno) &&
@@ -1926,7 +1943,7 @@ xfs_attr_leaf_lookup_int(xfs_dabuf_t *bp, xfs_da_args_t *args)
                else
                        break;
        }
-       ASSERT((probe >= 0) && 
+       ASSERT((probe >= 0) &&
               (!leaf->hdr.count
               || (probe < be16_to_cpu(leaf->hdr.count))));
        ASSERT((span <= 4) || (be32_to_cpu(entry->hashval) == hashval));
@@ -1971,14 +1988,9 @@ xfs_attr_leaf_lookup_int(xfs_dabuf_t *bp, xfs_da_args_t *args)
                        name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, probe);
                        if (name_loc->namelen != args->namelen)
                                continue;
-                       if (memcmp(args->name, (char *)name_loc->nameval,
-                                            args->namelen) != 0)
+                       if (memcmp(args->name, (char *)name_loc->nameval, args->namelen) != 0)
                                continue;
-                       if (((args->flags & ATTR_SECURE) != 0) !=
-                           ((entry->flags & XFS_ATTR_SECURE) != 0))
-                               continue;
-                       if (((args->flags & ATTR_ROOT) != 0) !=
-                           ((entry->flags & XFS_ATTR_ROOT) != 0))
+                       if (!xfs_attr_namesp_match(args->flags, entry->flags))
                                continue;
                        args->index = probe;
                        return(XFS_ERROR(EEXIST));
@@ -1989,11 +2001,7 @@ xfs_attr_leaf_lookup_int(xfs_dabuf_t *bp, xfs_da_args_t *args)
                        if (memcmp(args->name, (char *)name_rmt->name,
                                             args->namelen) != 0)
                                continue;
-                       if (((args->flags & ATTR_SECURE) != 0) !=
-                           ((entry->flags & XFS_ATTR_SECURE) != 0))
-                               continue;
-                       if (((args->flags & ATTR_ROOT) != 0) !=
-                           ((entry->flags & XFS_ATTR_ROOT) != 0))
+                       if (!xfs_attr_namesp_match(args->flags, entry->flags))
                                continue;
                        args->index = probe;
                        args->rmtblkno = be32_to_cpu(name_rmt->valueblk);
@@ -2312,8 +2320,6 @@ xfs_attr_leaf_list_int(xfs_dabuf_t *bp, xfs_attr_list_context_t *context)
        attrlist_cursor_kern_t *cursor;
        xfs_attr_leafblock_t *leaf;
        xfs_attr_leaf_entry_t *entry;
-       xfs_attr_leaf_name_local_t *name_loc;
-       xfs_attr_leaf_name_remote_t *name_rmt;
        int retval, i;
 
        ASSERT(bp != NULL);
@@ -2355,9 +2361,8 @@ xfs_attr_leaf_list_int(xfs_dabuf_t *bp, xfs_attr_list_context_t *context)
         * We have found our place, start copying out the new attributes.
         */
        retval = 0;
-       for (  ; (i < be16_to_cpu(leaf->hdr.count))
-            && (retval == 0); entry++, i++) {
-               attrnames_t     *namesp;
+       for (  ; (i < be16_to_cpu(leaf->hdr.count)); entry++, i++) {
+               attrnames_t *namesp;
 
                if (be32_to_cpu(entry->hashval) != cursor->hashval) {
                        cursor->hashval = be32_to_cpu(entry->hashval);
@@ -2366,115 +2371,69 @@ xfs_attr_leaf_list_int(xfs_dabuf_t *bp, xfs_attr_list_context_t *context)
 
                if (entry->flags & XFS_ATTR_INCOMPLETE)
                        continue;               /* skip incomplete entries */
-               if (((context->flags & ATTR_SECURE) != 0) !=
-                   ((entry->flags & XFS_ATTR_SECURE) != 0) &&
-                   !(context->flags & ATTR_KERNORMALS))
-                       continue;               /* skip non-matching entries */
-               if (((context->flags & ATTR_ROOT) != 0) !=
-                   ((entry->flags & XFS_ATTR_ROOT) != 0) &&
-                   !(context->flags & ATTR_KERNROOTLS))
-                       continue;               /* skip non-matching entries */
-
-               namesp = (entry->flags & XFS_ATTR_SECURE) ? &attr_secure :
-                       ((entry->flags & XFS_ATTR_ROOT) ? &attr_trusted :
-                         &attr_user);
+               if (!xfs_attr_namesp_match_overrides(context->flags, entry->flags))
+                       continue;
+
+               namesp = xfs_attr_flags_namesp(entry->flags);
 
                if (entry->flags & XFS_ATTR_LOCAL) {
-                       name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, i);
-                       if (context->flags & ATTR_KERNOVAL) {
-                               ASSERT(context->flags & ATTR_KERNAMELS);
-                               context->count += namesp->attr_namelen +
-                                               (int)name_loc->namelen + 1;
-                       } else {
-                               retval = xfs_attr_put_listent(context, namesp,
-                                       (char *)name_loc->nameval,
-                                       (int)name_loc->namelen,
-                                       be16_to_cpu(name_loc->valuelen));
-                       }
+                       xfs_attr_leaf_name_local_t *name_loc =
+                               XFS_ATTR_LEAF_NAME_LOCAL(leaf, i);
+
+                       retval = context->put_listent(context,
+                                               namesp,
+                                               (char *)name_loc->nameval,
+                                               (int)name_loc->namelen,
+                                               be16_to_cpu(name_loc->valuelen),
+                                               (char *)&name_loc->nameval[name_loc->namelen]);
+                       if (retval)
+                               return retval;
                } else {
-                       name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, i);
-                       if (context->flags & ATTR_KERNOVAL) {
-                               ASSERT(context->flags & ATTR_KERNAMELS);
-                               context->count += namesp->attr_namelen +
-                                               (int)name_rmt->namelen + 1;
-                       } else {
-                               retval = xfs_attr_put_listent(context, namesp,
-                                       (char *)name_rmt->name,
-                                       (int)name_rmt->namelen,
-                                       be32_to_cpu(name_rmt->valuelen));
+                       xfs_attr_leaf_name_remote_t *name_rmt =
+                               XFS_ATTR_LEAF_NAME_REMOTE(leaf, i);
+
+                       int valuelen = be32_to_cpu(name_rmt->valuelen);
+
+                       if (context->put_value) {
+                               xfs_da_args_t args;
+
+                               memset((char *)&args, 0, sizeof(args));
+                               args.dp = context->dp;
+                               args.whichfork = XFS_ATTR_FORK;
+                               args.valuelen = valuelen;
+                               args.value = kmem_alloc(valuelen, KM_SLEEP);
+                               args.rmtblkno = be32_to_cpu(name_rmt->valueblk);
+                               args.rmtblkcnt = XFS_B_TO_FSB(args.dp->i_mount, valuelen);
+                               retval = xfs_attr_rmtval_get(&args);
+                               if (retval)
+                                       return retval;
+                               retval = context->put_listent(context,
+                                               namesp,
+                                               (char *)name_rmt->name,
+                                               (int)name_rmt->namelen,
+                                               valuelen,
+                                               (char*)args.value);
+                               kmem_free(args.value, valuelen);
                        }
+                       else {
+                               retval = context->put_listent(context,
+                                               namesp,
+                                               (char *)name_rmt->name,
+                                               (int)name_rmt->namelen,
+                                               valuelen,
+                                               NULL);
+                       }
+                       if (retval)
+                               return retval;
                }
-               if (retval == 0) {
-                       cursor->offset++;
-               }
+               if (context->seen_enough)
+                       break;
+               cursor->offset++;
        }
        xfs_attr_trace_l_cl("blk end", context, leaf);
        return(retval);
 }
 
-#define        ATTR_ENTBASESIZE                /* minimum bytes used by an attr */ \
-       (((struct attrlist_ent *) 0)->a_name - (char *) 0)
-#define        ATTR_ENTSIZE(namelen)           /* actual bytes used by an attr */ \
-       ((ATTR_ENTBASESIZE + (namelen) + 1 + sizeof(u_int32_t)-1) \
-        & ~(sizeof(u_int32_t)-1))
-
-/*
- * Format an attribute and copy it out to the user's buffer.
- * Take care to check values and protect against them changing later,
- * we may be reading them directly out of a user buffer.
- */
-/*ARGSUSED*/
-STATIC int
-xfs_attr_put_listent(xfs_attr_list_context_t *context,
-                    attrnames_t *namesp, char *name, int namelen, int valuelen)
-{
-       attrlist_ent_t *aep;
-       int arraytop;
-
-       ASSERT(!(context->flags & ATTR_KERNOVAL));
-       if (context->flags & ATTR_KERNAMELS) {
-               char *offset;
-
-               ASSERT(context->count >= 0);
-
-               arraytop = context->count + namesp->attr_namelen + namelen + 1;
-               if (arraytop > context->firstu) {
-                       context->count = -1;    /* insufficient space */
-                       return(1);
-               }
-               offset = (char *)context->alist + context->count;
-               strncpy(offset, namesp->attr_name, namesp->attr_namelen);
-               offset += namesp->attr_namelen;
-               strncpy(offset, name, namelen);                 /* real name */
-               offset += namelen;
-               *offset = '\0';
-               context->count += namesp->attr_namelen + namelen + 1;
-               return(0);
-       }
-
-       ASSERT(context->count >= 0);
-       ASSERT(context->count < (ATTR_MAX_VALUELEN/8));
-       ASSERT(context->firstu >= sizeof(*context->alist));
-       ASSERT(context->firstu <= context->bufsize);
-
-       arraytop = sizeof(*context->alist) +
-                       context->count * sizeof(context->alist->al_offset[0]);
-       context->firstu -= ATTR_ENTSIZE(namelen);
-       if (context->firstu < arraytop) {
-               xfs_attr_trace_l_c("buffer full", context);
-               context->alist->al_more = 1;
-               return(1);
-       }
-
-       aep = (attrlist_ent_t *)&(((char *)context->alist)[ context->firstu ]);
-       aep->a_valuelen = valuelen;
-       memcpy(aep->a_name, name, namelen);
-       aep->a_name[ namelen ] = 0;
-       context->alist->al_offset[ context->count++ ] = context->firstu;
-       context->alist->al_count = context->count;
-       xfs_attr_trace_l_c("add", context);
-       return(0);
-}
 
 /*========================================================================
  * Manage the INCOMPLETE flag in a leaf entry
index 51c3ee1..040f732 100644 (file)
@@ -129,6 +129,19 @@ typedef struct xfs_attr_leafblock {
 #define XFS_ATTR_SECURE                (1 << XFS_ATTR_SECURE_BIT)
 #define XFS_ATTR_INCOMPLETE    (1 << XFS_ATTR_INCOMPLETE_BIT)
 
+/*
+ * Conversion macros for converting namespace bits from argument flags
+ * to ondisk flags.
+ */
+#define XFS_ATTR_NSP_ARGS_MASK         (ATTR_ROOT | ATTR_SECURE)
+#define XFS_ATTR_NSP_ONDISK_MASK       (XFS_ATTR_ROOT | XFS_ATTR_SECURE)
+#define XFS_ATTR_NSP_ONDISK(flags)     ((flags) & XFS_ATTR_NSP_ONDISK_MASK)
+#define XFS_ATTR_NSP_ARGS(flags)       ((flags) & XFS_ATTR_NSP_ARGS_MASK)
+#define XFS_ATTR_NSP_ARGS_TO_ONDISK(x) (((x) & ATTR_ROOT ? XFS_ATTR_ROOT : 0) |\
+                                        ((x) & ATTR_SECURE ? XFS_ATTR_SECURE : 0))
+#define XFS_ATTR_NSP_ONDISK_TO_ARGS(x) (((x) & XFS_ATTR_ROOT ? ATTR_ROOT : 0) |\
+                                        ((x) & XFS_ATTR_SECURE ? ATTR_SECURE : 0))
+
 /*
  * Alignment for namelist and valuelist entries (since they are mixed
  * there can be only one alignment value)
@@ -196,16 +209,26 @@ static inline int xfs_attr_leaf_entsize_local_max(int bsize)
  * Structure used to pass context around among the routines.
  *========================================================================*/
 
+
+struct xfs_attr_list_context;
+
+typedef int (*put_listent_func_t)(struct xfs_attr_list_context *, struct attrnames *,
+                                     char *, int, int, char *);
+
 typedef struct xfs_attr_list_context {
-       struct xfs_inode                *dp;    /* inode */
-       struct attrlist_cursor_kern     *cursor;/* position in list */
-       struct attrlist                 *alist; /* output buffer */
-       int                             count;  /* num used entries */
-       int                             dupcnt; /* count dup hashvals seen */
-       int                             bufsize;/* total buffer size */
-       int                             firstu; /* first used byte in buffer */
-       int                             flags;  /* from VOP call */
-       int                             resynch;/* T/F: resynch with cursor */
+       struct xfs_inode                *dp;            /* inode */
+       struct attrlist_cursor_kern     *cursor;        /* position in list */
+       struct attrlist                 *alist;         /* output buffer */
+       int                             seen_enough;    /* T/F: seen enough of list? */
+       int                             count;          /* num used entries */
+       int                             dupcnt;         /* count dup hashvals seen */
+       int                             bufsize;        /* total buffer size */
+       int                             firstu;         /* first used byte in buffer */
+       int                             flags;          /* from VOP call */
+       int                             resynch;        /* T/F: resynch with cursor */
+       int                             put_value;      /* T/F: need value for listent */
+       put_listent_func_t              put_listent;    /* list output fmt function */
+       int                             index;          /* index into output buffer */
 } xfs_attr_list_context_t;
 
 /*