ahci: use 0x80 as wait stat value instead of 0xff
[powerpc.git] / fs / xfs / xfs_attr.c
index 093fac4..9ada7bd 100644 (file)
@@ -27,7 +27,6 @@
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir.h"
 #include "xfs_dir2.h"
 #include "xfs_dmapi.h"
 #include "xfs_mount.h"
@@ -35,7 +34,6 @@
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
-#include "xfs_dir_sf.h"
 #include "xfs_dir2_sf.h"
 #include "xfs_attr_sf.h"
 #include "xfs_dinode.h"
@@ -93,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);
 
@@ -182,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)
 {
@@ -294,7 +291,7 @@ xfs_attr_set_int(xfs_inode_t *dp, const char *name, int namelen,
        xfs_trans_ihold(args.trans, dp);
 
        /*
-        * If the attribute list is non-existant or a shortform list,
+        * If the attribute list is non-existent or a shortform list,
         * upgrade it to a single-leaf-block attribute list.
         */
        if ((dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) ||
@@ -442,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;
@@ -593,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
@@ -617,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;
 
@@ -636,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 */
@@ -1124,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);
 }
 
 
@@ -1584,7 +1679,7 @@ out:
  * Fill in the disk block numbers in the state structure for the buffers
  * that are attached to the state structure.
  * This is done so that we can quickly reattach ourselves to those buffers
- * after some set of transaction commit's has released these buffers.
+ * after some set of transaction commits have released these buffers.
  */
 STATIC int
 xfs_attr_fillstate(xfs_da_state_t *state)
@@ -1631,7 +1726,7 @@ xfs_attr_fillstate(xfs_da_state_t *state)
 /*
  * Reattach the buffers to the state structure based on the disk block
  * numbers stored in the state structure.
- * This is done after some set of transaction commit's has released those
+ * This is done after some set of transaction commits have released those
  * buffers from our grip.
  */
 STATIC int
@@ -1860,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,
@@ -1888,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];
@@ -1910,7 +2009,7 @@ xfs_attr_rmtval_get(xfs_da_args_t *args)
                error = xfs_bmapi(args->trans, args->dp, (xfs_fileoff_t)lblkno,
                                  args->rmtblkcnt,
                                  XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA,
-                                 NULL, 0, map, &nmap, NULL);
+                                 NULL, 0, map, &nmap, NULL, NULL);
                if (error)
                        return(error);
                ASSERT(nmap >= 1);
@@ -1988,7 +2087,7 @@ xfs_attr_rmtval_set(xfs_da_args_t *args)
                                  XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA |
                                                        XFS_BMAPI_WRITE,
                                  args->firstblock, args->total, &map, &nmap,
-                                 args->flist);
+                                 args->flist, NULL);
                if (!error) {
                        error = xfs_bmap_finish(&args->trans, args->flist,
                                                *args->firstblock, &committed);
@@ -2039,7 +2138,8 @@ xfs_attr_rmtval_set(xfs_da_args_t *args)
                error = xfs_bmapi(NULL, dp, (xfs_fileoff_t)lblkno,
                                  args->rmtblkcnt,
                                  XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA,
-                                 args->firstblock, 0, &map, &nmap, NULL);
+                                 args->firstblock, 0, &map, &nmap,
+                                 NULL, NULL);
                if (error) {
                        return(error);
                }
@@ -2104,7 +2204,7 @@ xfs_attr_rmtval_remove(xfs_da_args_t *args)
                                        args->rmtblkcnt,
                                        XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA,
                                        args->firstblock, 0, &map, &nmap,
-                                       args->flist);
+                                       args->flist, NULL);
                if (error) {
                        return(error);
                }
@@ -2142,7 +2242,8 @@ xfs_attr_rmtval_remove(xfs_da_args_t *args)
                XFS_BMAP_INIT(args->flist, args->firstblock);
                error = xfs_bunmapi(args->trans, args->dp, lblkno, blkcnt,
                                    XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA,
-                                   1, args->firstblock, args->flist, &done);
+                                   1, args->firstblock, args->flist,
+                                   NULL, &done);
                if (!error) {
                        error = xfs_bmap_finish(&args->trans, args->flist,
                                                *args->firstblock, &committed);
@@ -2322,56 +2423,56 @@ xfs_attr_trace_enter(int type, char *where,
 
 STATIC int
 posix_acl_access_set(
-       vnode_t *vp, char *name, void *data, size_t size, int xflags)
+       bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags)
 {
        return xfs_acl_vset(vp, data, size, _ACL_TYPE_ACCESS);
 }
 
 STATIC int
 posix_acl_access_remove(
-       struct vnode *vp, char *name, int xflags)
+       bhv_vnode_t *vp, char *name, int xflags)
 {
        return xfs_acl_vremove(vp, _ACL_TYPE_ACCESS);
 }
 
 STATIC int
 posix_acl_access_get(
-       vnode_t *vp, char *name, void *data, size_t size, int xflags)
+       bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags)
 {
        return xfs_acl_vget(vp, data, size, _ACL_TYPE_ACCESS);
 }
 
 STATIC int
 posix_acl_access_exists(
-       vnode_t *vp)
+       bhv_vnode_t *vp)
 {
        return xfs_acl_vhasacl_access(vp);
 }
 
 STATIC int
 posix_acl_default_set(
-       vnode_t *vp, char *name, void *data, size_t size, int xflags)
+       bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags)
 {
        return xfs_acl_vset(vp, data, size, _ACL_TYPE_DEFAULT);
 }
 
 STATIC int
 posix_acl_default_get(
-       vnode_t *vp, char *name, void *data, size_t size, int xflags)
+       bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags)
 {
        return xfs_acl_vget(vp, data, size, _ACL_TYPE_DEFAULT);
 }
 
 STATIC int
 posix_acl_default_remove(
-       struct vnode *vp, char *name, int xflags)
+       bhv_vnode_t *vp, char *name, int xflags)
 {
        return xfs_acl_vremove(vp, _ACL_TYPE_DEFAULT);
 }
 
 STATIC int
 posix_acl_default_exists(
-       vnode_t *vp)
+       bhv_vnode_t *vp)
 {
        return xfs_acl_vhasacl_default(vp);
 }
@@ -2404,21 +2505,18 @@ STATIC struct attrnames *attr_system_names[] =
 
 STATIC int
 attr_generic_set(
-       struct vnode *vp, char *name, void *data, size_t size, int xflags)
+       bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags)
 {
-       int     error;
-
-       VOP_ATTR_SET(vp, name, data, size, xflags, NULL, error);
-       return -error;
+       return -bhv_vop_attr_set(vp, name, data, size, xflags, NULL);
 }
 
 STATIC int
 attr_generic_get(
-       struct vnode *vp, char *name, void *data, size_t size, int xflags)
+       bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags)
 {
        int     error, asize = size;
 
-       VOP_ATTR_GET(vp, name, data, &asize, xflags, NULL, error);
+       error = bhv_vop_attr_get(vp, name, data, &asize, xflags, NULL);
        if (!error)
                return asize;
        return -error;
@@ -2426,12 +2524,9 @@ attr_generic_get(
 
 STATIC int
 attr_generic_remove(
-       struct vnode *vp, char *name, int xflags)
+       bhv_vnode_t *vp, char *name, int xflags)
 {
-       int     error;
-
-       VOP_ATTR_REMOVE(vp, name, xflags, NULL, error);
-       return -error;
+       return -bhv_vop_attr_remove(vp, name, xflags, NULL);
 }
 
 STATIC int
@@ -2459,7 +2554,7 @@ attr_generic_listadd(
 
 STATIC int
 attr_system_list(
-       struct vnode            *vp,
+       bhv_vnode_t             *vp,
        void                    *data,
        size_t                  size,
        ssize_t                 *result)
@@ -2481,12 +2576,12 @@ attr_system_list(
 
 int
 attr_generic_list(
-       struct vnode *vp, void *data, size_t size, int xflags, ssize_t *result)
+       bhv_vnode_t *vp, void *data, size_t size, int xflags, ssize_t *result)
 {
        attrlist_cursor_kern_t  cursor = { 0 };
        int                     error;
 
-       VOP_ATTR_LIST(vp, data, size, xflags, &cursor, NULL, error);
+       error = bhv_vop_attr_list(vp, data, size, xflags, &cursor, NULL);
        if (error > 0)
                return -error;
        *result = -error;
@@ -2514,7 +2609,7 @@ attr_lookup_namespace(
  */
 STATIC int
 attr_user_capable(
-       struct vnode    *vp,
+       bhv_vnode_t     *vp,
        cred_t          *cred)
 {
        struct inode    *inode = vn_to_inode(vp);
@@ -2532,7 +2627,7 @@ attr_user_capable(
 
 STATIC int
 attr_trusted_capable(
-       struct vnode    *vp,
+       bhv_vnode_t     *vp,
        cred_t          *cred)
 {
        struct inode    *inode = vn_to_inode(vp);
@@ -2546,7 +2641,7 @@ attr_trusted_capable(
 
 STATIC int
 attr_secure_capable(
-       struct vnode    *vp,
+       bhv_vnode_t     *vp,
        cred_t          *cred)
 {
        return -ENOSECURITY;
@@ -2554,7 +2649,7 @@ attr_secure_capable(
 
 STATIC int
 attr_system_set(
-       struct vnode *vp, char *name, void *data, size_t size, int xflags)
+       bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags)
 {
        attrnames_t     *namesp;
        int             error;
@@ -2573,7 +2668,7 @@ attr_system_set(
 
 STATIC int
 attr_system_get(
-       struct vnode *vp, char *name, void *data, size_t size, int xflags)
+       bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags)
 {
        attrnames_t     *namesp;
 
@@ -2585,7 +2680,7 @@ attr_system_get(
 
 STATIC int
 attr_system_remove(
-       struct vnode *vp, char *name, int xflags)
+       bhv_vnode_t *vp, char *name, int xflags)
 {
        attrnames_t     *namesp;