On Thu, Sep 19, 2019 at 04:51:02PM -0700, Allison Collins wrote: > > > On 9/19/19 10:47 AM, Brian Foster wrote: > > On Thu, Sep 05, 2019 at 03:18:22PM -0700, Allison Collins wrote: > > > From: Allison Henderson <allison.henderson@xxxxxxxxxx> > > > > > > This patch adds a new functions to check for the existence of > > > an attribute. Subroutines are also added to handle the cases > > > of leaf blocks, nodes or shortform. Common code that appears > > > in existing attr add and remove functions have been factored > > > out to help reduce the appearence of duplicated code. We will > > > need these routines later for delayed attributes since delayed > > > operations cannot return error codes. > > > > > > Signed-off-by: Allison Henderson <allison.henderson@xxxxxxxxxx> > > > Signed-off-by: Allison Collins <allison.henderson@xxxxxxxxxx> > > > > Extra s-o-b tag? > Oops, I thought I had caught all the old names. Will clean out :-) > > > > > > --- > > > fs/xfs/libxfs/xfs_attr.c | 150 +++++++++++++++++++++++++++--------------- > > > fs/xfs/libxfs/xfs_attr.h | 1 + > > > fs/xfs/libxfs/xfs_attr_leaf.c | 92 +++++++++++++++++--------- > > > fs/xfs/libxfs/xfs_attr_leaf.h | 2 + > > > 4 files changed, 161 insertions(+), 84 deletions(-) > > > > > > diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c > > > index 50e099f..a297857 100644 > > > --- a/fs/xfs/libxfs/xfs_attr.c > > > +++ b/fs/xfs/libxfs/xfs_attr.c > > > @@ -46,6 +46,7 @@ STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args); > > > STATIC int xfs_attr_leaf_get(xfs_da_args_t *args); > > > STATIC int xfs_attr_leaf_addname(xfs_da_args_t *args); > > > STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args); > > > +STATIC int xfs_leaf_has_attr(struct xfs_da_args *args, struct xfs_buf **bp); > > > > The fact that this is not named xfs_attr_leaf_*() kind of stands out > > here, particularly since the node variant uses the xfs_attr_* prefix. > > Hm? (Same goes for xfs_shortform_has_attr() I suppose..). > Sure, I can flip the prefixes around to look a little more consistent > > > > > /* > > > * Internal routines when attribute list is more than one block. > > > @@ -53,6 +54,8 @@ STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args); > > > STATIC int xfs_attr_node_get(xfs_da_args_t *args); > > > STATIC int xfs_attr_node_addname(xfs_da_args_t *args); > > > STATIC int xfs_attr_node_removename(xfs_da_args_t *args); > > > +STATIC int xfs_attr_node_hasname(xfs_da_args_t *args, > > > + struct xfs_da_state **state); > > > STATIC int xfs_attr_fillstate(xfs_da_state_t *state); > > > STATIC int xfs_attr_refillstate(xfs_da_state_t *state); > > > @@ -309,6 +312,32 @@ xfs_attr_set_args( > > > } > > > /* > > > + * Return EEXIST if attr is found, or ENOATTR if not > > > + */ > > > +int > > > +xfs_has_attr( > > > + struct xfs_da_args *args) > > > +{ > > > + struct xfs_inode *dp = args->dp; > > > + struct xfs_buf *bp; > > > + int error; > > > + > > > + if (!xfs_inode_hasattr(dp)) { > > > + error = -ENOATTR; > > > + } else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) { > > > + ASSERT(dp->i_afp->if_flags & XFS_IFINLINE); > > > + error = xfs_shortform_has_attr(args, NULL, NULL); > > > + } else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) { > > > + error = xfs_leaf_has_attr(args, &bp); > > > + xfs_trans_brelse(args->trans, bp); > > > + } else { > > > + error = xfs_attr_node_hasname(args, NULL); > > > + } > > > + > > > + return error; > > > +} > > > + > > > > FWIW, I think it's preferable to include new functions like this with > > the first user. I'm a bit curious about the use of error codes here as > > opposed to returning a boolean. I could see being able to handle > > unexpected errors as a good reason for doing that, but taking a quick > > look ahead, it appears neither caller of xfs_has_attr() does so. ;) > > > > (To be clear, I think keeping the function as is and fixing up the > > eventual callers to handle unexpected errors is probably the right thing > > to do.). > > The new top level function actually doesnt get used until patch 18, but I > guess I try to keep the patch sizes small to make them easier for people to > review. Basically we use it to see if there is/isnt an attribute present, > and then return the appropriate error code right away. IE, trying to remove > an attribute that isnt there immediately return EENOATTR rather than trying > to start a delayed operation that isnt going to be successful. The is > because delayed operations are not supposed to return error codes. If they > do, they cause a shut down, which is not correct here. > Makes sense. It might be fine to leave the associated refactoring and just defer the new helper to the later patch, fwiw. > Initially I think I had it returning booleans, but it means the top level > function needs to do extra handling to translate the error codes, and I > thought it looked messy. So I decided to stick with the scheme that the > rest of the code was using. > Yeah, it's strange at first, but seems prevalent throughout the xattr code. Perhaps that's something we can clean up a bit down the road. > I skipped ahead about unexpected error codes and see what you mean, so I > will add some extra handlers there. > > > > > > +/* > > > * Remove the attribute specified in @args. > > > */ > > > int > > > @@ -574,26 +603,17 @@ STATIC int > > > xfs_attr_leaf_addname( > > > struct xfs_da_args *args) > > > { > > > - struct xfs_inode *dp; > > > struct xfs_buf *bp; > > > int retval, error, forkoff; > > > + struct xfs_inode *dp = args->dp; > > > trace_xfs_attr_leaf_addname(args); > > > /* > > > - * Read the (only) block in the attribute list in. > > > - */ > > > - dp = args->dp; > > > - args->blkno = 0; > > > - error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp); > > > - if (error) > > > - return error; > > > - > > > > It looks like we lose this unexpected error check here (i.e. suppose we > > got -ENOMEM or -EFSCORRUPTED or something that indicates we shouldn't > > continue). FWIW, this seems to repeat throughout this patch where we've > > invoked the new helpers.. > > Ok, I'll add in an explicit check for (retval != -ENOATTR && retval != > -EEXIST) > > > > > > > - /* > > > * Look up the given attribute in the leaf block. Figure out if > > > * the given flags produce an error or call for an atomic rename. > > > */ > > > - retval = xfs_attr3_leaf_lookup_int(bp, args); > > > + retval = xfs_leaf_has_attr(args, &bp); > > > if ((args->name.type & ATTR_REPLACE) && (retval == -ENOATTR)) { > > > xfs_trans_brelse(args->trans, bp); > > > return retval; > > > @@ -745,6 +765,25 @@ xfs_attr_leaf_addname( > > > } > > > /* > > > + * Return EEXIST if attr is found, or ENOATTR if not > > > + */ > > > +STATIC int > > > +xfs_leaf_has_attr( > > > + struct xfs_da_args *args, > > > + struct xfs_buf **bp) > > > +{ > > > + int error = 0; > > > + > > > + args->blkno = 0; > > > > This seems misplaced for a helper, but I could be missing context. Why > > not just pass zero directly and leave the args->blkno assignment to the > > caller? > I guess just I kept these two lines together since that's was how they > initially appeared before factoring them out, but it does look a bit off. > It should be ok leave the assignment to the caller. I can push it back up. > > > > > > + error = xfs_attr3_leaf_read(args->trans, args->dp, > > > + args->blkno, XFS_DABUF_MAP_NOMAPPING, bp); > > > + if (error) > > > + return error; > > > + > > > + return xfs_attr3_leaf_lookup_int(*bp, args); > > > +} > > > + > > > +/* > > > * Remove a name from the leaf attribute list structure > > > * > > > * This leaf block cannot have a "remote" value, we only call this routine > > > @@ -764,12 +803,8 @@ xfs_attr_leaf_removename( > > > * Remove the attribute. > > > */ > > > dp = args->dp; > > > - args->blkno = 0; > > > - error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp); > > > - if (error) > > > - return error; > > > > Lost error check. > > > > > - error = xfs_attr3_leaf_lookup_int(bp, args); > > > + error = xfs_leaf_has_attr(args, &bp); > > > if (error == -ENOATTR) { > > > xfs_trans_brelse(args->trans, bp); > > > return error; > > > @@ -808,12 +843,7 @@ xfs_attr_leaf_get(xfs_da_args_t *args) > > > trace_xfs_attr_leaf_get(args); > > > - args->blkno = 0; > > > - error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp); > > > - if (error) > > > - return error; > > > - > > > > ^ here too. Not sure if I caught them all, but you get the idea. ;) > Ok,I'll sweep through and find them :-) > > > > > > - error = xfs_attr3_leaf_lookup_int(bp, args); > > > + error = xfs_leaf_has_attr(args, &bp); > > > if (error != -EEXIST) { > > > xfs_trans_brelse(args->trans, bp); > > > return error; > > > @@ -823,6 +853,43 @@ xfs_attr_leaf_get(xfs_da_args_t *args) > > > return error; > > > } > > > +/* > > > + * Return EEXIST if attr is found, or ENOATTR if not > > > + * statep: If not null is set to point at the found state. Caller will > > > + * be responsible for freeing the state in this case. > > > + */ > > > +STATIC int > > > +xfs_attr_node_hasname( > > > + struct xfs_da_args *args, > > > + struct xfs_da_state **statep) > > > +{ > > > + struct xfs_da_state *state; > > > + struct xfs_inode *dp; > > > + int retval, error; > > > + > > > + /* > > > + * Tie a string around our finger to remind us where we are. > > > + */ > > > + dp = args->dp; > > > + state = xfs_da_state_alloc(); > > > + state->args = args; > > > + state->mp = dp->i_mount; > > > + > > > > No real need for the dp local variable here if it's just to reference > > ->i_mount. Also I know that comment isn't introduced by this patch, but > > any idea what it actually means? It doesn't make much sense to me at a > > glance. :P > > Ok, will clean out assignment. I'm actually not sure as to the comments > origins either, I assumed it was in reference the the state? I suppose > state is used to keep track of a lot of things going on in the calling > function. But even in that context, I don't find the comment particularly > descriptive. Should I clean it out? > Unless somebody can chime in and explain what it means (so perhaps we could reword it), I'd probably just remove it. Brian > > > > > + /* > > > + * Search to see if name exists, and get back a pointer to it. > > > + */ > > > + error = xfs_da3_node_lookup_int(state, &retval); > > > + if (error == 0) > > > + error = retval; > > > + > > > + if (statep != NULL) > > > + *statep = state; > > > + else > > > + xfs_da_state_free(state); > > > + > > > + return error; > > > +} > > > + > > > /*======================================================================== > > > * External routines when attribute list size > geo->blksize > > > *========================================================================*/ > > > @@ -855,17 +922,14 @@ xfs_attr_node_addname( > > > dp = args->dp; > > > mp = dp->i_mount; > > > restart: > > > - state = xfs_da_state_alloc(); > > > - state->args = args; > > > - state->mp = mp; > > > - > > > /* > > > * Search to see if name already exists, and get back a pointer > > > * to where it should go. > > > */ > > > - error = xfs_da3_node_lookup_int(state, &retval); > > > - if (error) > > > > Error check again. > > > > > + error = xfs_attr_node_hasname(args, &state); > > > + if (error == -EEXIST) > > > goto out; > > > + > > > blk = &state->path.blk[ state->path.active-1 ]; > > > ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC); > > > if ((args->name.type & ATTR_REPLACE) && (retval == -ENOATTR)) { > > > @@ -1070,29 +1134,15 @@ xfs_attr_node_removename( > > > { > > > struct xfs_da_state *state; > > > struct xfs_da_state_blk *blk; > > > - struct xfs_inode *dp; > > > struct xfs_buf *bp; > > > int retval, error, forkoff; > > > + struct xfs_inode *dp = args->dp; > > > trace_xfs_attr_node_removename(args); > > > - /* > > > - * Tie a string around our finger to remind us where we are. > > > - */ > > > - dp = args->dp; > > > - state = xfs_da_state_alloc(); > > > - state->args = args; > > > - state->mp = dp->i_mount; > > > - > > > - /* > > > - * Search to see if name exists, and get back a pointer to it. > > > - */ > > > - error = xfs_da3_node_lookup_int(state, &retval); > > > - if (error || (retval != -EEXIST)) { > > > - if (error == 0) > > > - error = retval; > > > + error = xfs_attr_node_hasname(args, &state); > > > + if (error != -EEXIST) > > > goto out; > > > - } > > > /* > > > * If there is an out-of-line value, de-allocate the blocks. > > > @@ -1314,20 +1364,14 @@ xfs_attr_node_get(xfs_da_args_t *args) > > > trace_xfs_attr_node_get(args); > > > - state = xfs_da_state_alloc(); > > > - state->args = args; > > > - state->mp = args->dp->i_mount; > > > - > > > /* > > > * Search to see if name exists, and get back a pointer to it. > > > */ > > > - error = xfs_da3_node_lookup_int(state, &retval); > > > - if (error) { > > > + error = xfs_attr_node_hasname(args, &state); > > > + if (error != -EEXIST) { > > > retval = error; > > > goto out_release; > > > } > > > - if (retval != -EEXIST) > > > - goto out_release; > > > /* > > > * Get the value, local or "remote" > > > diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h > > > index cedb4e2..fb56d81 100644 > > > --- a/fs/xfs/libxfs/xfs_attr.h > > > +++ b/fs/xfs/libxfs/xfs_attr.h > > > @@ -150,6 +150,7 @@ int xfs_attr_set(struct xfs_inode *dp, struct xfs_name *name, > > > unsigned char *value, int valuelen); > > > int xfs_attr_set_args(struct xfs_da_args *args); > > > int xfs_attr_remove(struct xfs_inode *dp, struct xfs_name *name); > > > +int xfs_has_attr(struct xfs_da_args *args); > > > int xfs_attr_remove_args(struct xfs_da_args *args); > > > int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize, > > > int flags, struct attrlist_cursor_kern *cursor); > > > diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c > > > index 07ce320..a501538 100644 > > > --- a/fs/xfs/libxfs/xfs_attr_leaf.c > > > +++ b/fs/xfs/libxfs/xfs_attr_leaf.c > > > @@ -590,6 +590,53 @@ xfs_attr_shortform_create(xfs_da_args_t *args) > > > } > > > /* > > > + * Return EEXIST if attr is found, or ENOATTR if not > > > + * args: args containing attribute name and namelen > > > + * sfep: If not null, pointer will be set to the last attr entry found > > > + * basep: If not null, pointer is set to the byte offset of the entry in the > > > + * list > > > + */ > > > +int > > > +xfs_shortform_has_attr( > > > + struct xfs_da_args *args, > > > + struct xfs_attr_sf_entry **sfep, > > > + int *basep) > > > +{ > > > + struct xfs_attr_shortform *sf; > > > + struct xfs_attr_sf_entry *sfe; > > > + int base = sizeof(struct xfs_attr_sf_hdr); > > > + int size = 0; > > > + int end; > > > + int i; > > > + > > > + base = sizeof(struct xfs_attr_sf_hdr); > > > + sf = (struct xfs_attr_shortform *)args->dp->i_afp->if_u1.if_data; > > > + sfe = &sf->list[0]; > > > + end = sf->hdr.count; > > > + for (i = 0; i < end; sfe = XFS_ATTR_SF_NEXTENTRY(sfe), > > > + base += size, i++) { > > > + size = XFS_ATTR_SF_ENTSIZE(sfe); > > > + if (sfe->namelen != args->name.len) > > > + continue; > > > + if (memcmp(sfe->nameval, args->name.name, args->name.len) != 0) > > > + continue; > > > + if (!xfs_attr_namesp_match(args->name.type, sfe->flags)) > > > + continue; > > > + break; > > > + } > > > + > > > + if (sfep != NULL) > > > + *sfep = sfe; > > > + > > > + if (basep != NULL) > > > + *basep = base; > > > + > > > + if (i == end) > > > + return -ENOATTR; > > > + return -EEXIST; > > > > This function seems like it could just return a bool. Eh, I suppose it's > > better to be consistent with the other variants if those ones can return > > unrelated errors. > Ok, I prefer the consistency as well. > > > > > > +} > > > + > > > +/* > > > * Add a name/value pair to the shortform attribute list. > > > * Overflow from the inode has already been checked for. > > > */ > > > @@ -598,7 +645,7 @@ xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff) > > > { > > > xfs_attr_shortform_t *sf; > > > xfs_attr_sf_entry_t *sfe; > > > - int i, offset, size; > > > + int offset, size, error; > > > xfs_mount_t *mp; > > > xfs_inode_t *dp; > > > > Nit: might be good to clean up the typedefs here since you do it in the > > remove function as well. > Sure, will do. > > > > > > struct xfs_ifork *ifp; > > > @@ -612,18 +659,10 @@ xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff) > > > ifp = dp->i_afp; > > > ASSERT(ifp->if_flags & XFS_IFINLINE); > > > sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data; > > > - sfe = &sf->list[0]; > > > - for (i = 0; i < sf->hdr.count; sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) { > > > + error = xfs_shortform_has_attr(args, &sfe, NULL); > > > #ifdef DEBUG > > > - if (sfe->namelen != args->name.len) > > > - continue; > > > - if (memcmp(args->name.name, sfe->nameval, args->name.len) != 0) > > > - continue; > > > - if (!xfs_attr_namesp_match(args->name.type, sfe->flags)) > > > - continue; > > > - ASSERT(0); > > > + ASSERT(error != -EEXIST); > > > #endif > > > > Hmm, interesting. So basically this code walks to the end of the list > > for the purpose of placement of the new attr and the debug code simply > > asserts that we don't find an existing attr. The only thing that > > concerns me is that nothing about xfs_shortform_has_attr() indicates > > that the output values are important when the lookup fails. The comment > > only explains what the values are when a lookup succeeds. Could we > > update the comment to elaborate on this use case to prevent somebody > > from unknowingly breaking it down the road? > > > > Also, there's no need for the #ifdef DEBUG any more with just the assert > > check in that block. > > Sure, I will clearify the comments and pull out the DEBUG > > > > > > - } > > > offset = (char *)sfe - (char *)sf; > > > size = XFS_ATTR_SF_ENTSIZE_BYNAME(args->name.len, args->valuelen); > > > @@ -668,33 +707,24 @@ xfs_attr_fork_remove( > > > int > > > xfs_attr_shortform_remove(xfs_da_args_t *args) > > > { > > > - xfs_attr_shortform_t *sf; > > > - xfs_attr_sf_entry_t *sfe; > > > - int base, size=0, end, totsize, i; > > > - xfs_mount_t *mp; > > > - xfs_inode_t *dp; > > > + struct xfs_attr_shortform *sf; > > > + struct xfs_attr_sf_entry *sfe; > > > + int base, size = 0, end, totsize; > > > + struct xfs_mount *mp; > > > + struct xfs_inode *dp; > > > + int error; > > > trace_xfs_attr_sf_remove(args); > > > dp = args->dp; > > > mp = dp->i_mount; > > > - base = sizeof(xfs_attr_sf_hdr_t); > > > sf = (xfs_attr_shortform_t *)dp->i_afp->if_u1.if_data; > > > - sfe = &sf->list[0]; > > > end = sf->hdr.count; > > > > This value of end is unused (end is immediately reassigned further down > > in the function). > > > > Brian > > Ok, I will pick that out. Thank you for the thorough reviews! > > Allison > > > > > > - for (i = 0; i < end; sfe = XFS_ATTR_SF_NEXTENTRY(sfe), > > > - base += size, i++) { > > > - size = XFS_ATTR_SF_ENTSIZE(sfe); > > > - if (sfe->namelen != args->name.len) > > > - continue; > > > - if (memcmp(sfe->nameval, args->name.name, args->name.len) != 0) > > > - continue; > > > - if (!xfs_attr_namesp_match(args->name.type, sfe->flags)) > > > - continue; > > > - break; > > > - } > > > - if (i == end) > > > - return -ENOATTR; > > > + > > > + error = xfs_shortform_has_attr(args, &sfe, &base); > > > + if (error == -ENOATTR) > > > + return error; > > > + size = XFS_ATTR_SF_ENTSIZE(sfe); > > > /* > > > * Fix up the attribute fork data, covering the hole > > > diff --git a/fs/xfs/libxfs/xfs_attr_leaf.h b/fs/xfs/libxfs/xfs_attr_leaf.h > > > index 536a290..58e9327 100644 > > > --- a/fs/xfs/libxfs/xfs_attr_leaf.h > > > +++ b/fs/xfs/libxfs/xfs_attr_leaf.h > > > @@ -42,6 +42,8 @@ int xfs_attr_shortform_getvalue(struct xfs_da_args *args); > > > int xfs_attr_shortform_to_leaf(struct xfs_da_args *args, > > > struct xfs_buf **leaf_bp); > > > int xfs_attr_shortform_remove(struct xfs_da_args *args); > > > +int xfs_shortform_has_attr(struct xfs_da_args *args, > > > + struct xfs_attr_sf_entry **sfep, int *basep); > > > int xfs_attr_shortform_allfit(struct xfs_buf *bp, struct xfs_inode *dp); > > > int xfs_attr_shortform_bytesfit(struct xfs_inode *dp, int bytes); > > > xfs_failaddr_t xfs_attr_shortform_verify(struct xfs_inode *ip); > > > -- > > > 2.7.4 > > >