📄 xfs_attr.c
字号:
if ((error = xfs_trans_reserve(args.trans, XFS_ATTRRM_SPACE_RES(mp), XFS_ATTRRM_LOG_RES(mp), 0, XFS_TRANS_PERM_LOG_RES, XFS_ATTRRM_LOG_COUNT))) { xfs_trans_cancel(args.trans, 0); return(error); } xfs_ilock(dp, XFS_ILOCK_EXCL); /* * No need to make quota reservations here. We expect to release some * blocks not allocate in the common case. */ xfs_trans_ijoin(args.trans, dp, XFS_ILOCK_EXCL); xfs_trans_ihold(args.trans, 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 = XFS_ERROR(ENOATTR); goto out; } if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) { ASSERT(dp->i_afp->if_flags & XFS_IFINLINE); error = xfs_attr_shortform_remove(&args); if (error) { goto out; } } else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) { error = xfs_attr_leaf_removename(&args); } else { error = xfs_attr_node_removename(&args); } if (error) { goto out; } /* * If this is a synchronous mount, make sure that the * transaction goes to disk before returning to the user. */ if (mp->m_flags & XFS_MOUNT_WSYNC) { xfs_trans_set_sync(args.trans); } /* * Commit the last in the sequence of transactions. */ xfs_trans_log_inode(args.trans, dp, XFS_ILOG_CORE); error = xfs_trans_commit(args.trans, XFS_TRANS_RELEASE_LOG_RES); xfs_iunlock(dp, XFS_ILOCK_EXCL); /* * Hit the inode change time. */ if (!error && (flags & ATTR_KERNOTIME) == 0) { xfs_ichgtime(dp, XFS_ICHGTIME_CHG); } return(error);out: if (args.trans) xfs_trans_cancel(args.trans, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT); xfs_iunlock(dp, XFS_ILOCK_EXCL); return(error);}intxfs_attr_remove( xfs_inode_t *dp, const char *name, int flags){ int namelen; namelen = strlen(name); if (namelen >= MAXNAMELEN) return EFAULT; /* match IRIX behaviour */ XFS_STATS_INC(xs_attr_remove); if (XFS_FORCED_SHUTDOWN(dp->i_mount)) return (EIO); xfs_ilock(dp, XFS_ILOCK_SHARED); if (XFS_IFORK_Q(dp) == 0 || (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && dp->i_d.di_anextents == 0)) { xfs_iunlock(dp, XFS_ILOCK_SHARED); return(XFS_ERROR(ENOATTR)); } xfs_iunlock(dp, XFS_ILOCK_SHARED); 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 intxfs_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 intxfs_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 intxfs_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 * convention of being an error, zero or negative return code * is the length of the buffer returned (negated), indicating * success. */intxfs_attr_list( xfs_inode_t *dp, char *buffer, int bufsize, int flags, attrlist_cursor_kern_t *cursor){ xfs_attr_list_context_t context; int error; XFS_STATS_INC(xs_attr_list); /* * Validate the cursor. */ if (cursor->pad1 || cursor->pad2) return(XFS_ERROR(EINVAL)); if ((cursor->initted == 0) && (cursor->hashval || cursor->blkno || cursor->offset)) return XFS_ERROR(EINVAL); /* * Check for a properly aligned buffer. */ if (((long)buffer) & (sizeof(int)-1)) return XFS_ERROR(EFAULT); if (flags & ATTR_KERNOVAL) bufsize = 0; /* * Initialize the output buffer. */ context.dp = dp; context.cursor = cursor; context.count = 0; context.dupcnt = 0; context.resynch = 1; context.flags = flags; 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->al_count = 0; context.alist->al_more = 0; context.alist->al_offset[0] = context.bufsize; context.put_listent = xfs_attr_put_listent; } if (XFS_FORCED_SHUTDOWN(dp->i_mount)) return EIO; xfs_ilock(dp, XFS_ILOCK_SHARED); xfs_attr_trace_l_c("syscall start", &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)) { /* 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;}int /* error */xfs_attr_inactive(xfs_inode_t *dp){ xfs_trans_t *trans; xfs_mount_t *mp; int error; mp = dp->i_mount; ASSERT(! XFS_NOT_DQATTACHED(mp, dp)); xfs_ilock(dp, XFS_ILOCK_SHARED); if ((XFS_IFORK_Q(dp) == 0) || (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) || (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && dp->i_d.di_anextents == 0)) { xfs_iunlock(dp, XFS_ILOCK_SHARED); return(0); } xfs_iunlock(dp, XFS_ILOCK_SHARED); /* * Start our first transaction of the day. * * All future transactions during this code must be "chained" off * this one via the trans_dup() call. All transactions will contain * the inode, and the inode will always be marked with trans_ihold(). * Since the inode will be locked in all transactions, we must log * the inode in every transaction to let it float upward through * the log. */ trans = xfs_trans_alloc(mp, XFS_TRANS_ATTRINVAL); if ((error = xfs_trans_reserve(trans, 0, XFS_ATTRINVAL_LOG_RES(mp), 0, XFS_TRANS_PERM_LOG_RES, XFS_ATTRINVAL_LOG_COUNT))) { xfs_trans_cancel(trans, 0); return(error); } xfs_ilock(dp, XFS_ILOCK_EXCL); /* * No need to make quota reservations here. We expect to release some * blocks, not allocate, in the common case. */ xfs_trans_ijoin(trans, dp, XFS_ILOCK_EXCL); xfs_trans_ihold(trans, 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_LOCAL) || (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && dp->i_d.di_anextents == 0)) { error = 0; goto out; } error = xfs_attr_root_inactive(&trans, dp); if (error) goto out; /* * signal synchronous inactive transactions unless this * is a synchronous mount filesystem in which case we * know that we're here because we've been called out of * xfs_inactive which means that the last reference is gone * and the unlink transaction has already hit the disk so * async inactive transactions are safe. */ if ((error = xfs_itruncate_finish(&trans, dp, 0LL, XFS_ATTR_FORK, (!(mp->m_flags & XFS_MOUNT_WSYNC) ? 1 : 0)))) goto out; /* * Commit the last in the sequence of transactions. */ xfs_trans_log_inode(trans, dp, XFS_ILOG_CORE); error = xfs_trans_commit(trans, XFS_TRANS_RELEASE_LOG_RES); xfs_iunlock(dp, XFS_ILOCK_EXCL); return(error);out: xfs_trans_cancel(trans, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT); xfs_iunlock(dp, XFS_ILOCK_EXCL); return(error);}/*======================================================================== * External routines when attribute list is inside the inode *========================================================================*//* * Add a name to the shortform attribute list structure * This is the external routine. */STATIC intxfs_attr_shortform_addname(xfs_da_args_t *args){ int newsize, forkoff, retval; retval = xfs_attr_shortform_lookup(args); if ((args->flags & ATTR_REPLACE) && (retval == ENOATTR)) { return(retval); } else if (retval == EEXIST) { if (args->flags & ATTR_CREATE) return(retval); retval = xfs_attr_shortform_remove(args); ASSERT(retval == 0); } if (args->namelen >= XFS_ATTR_SF_ENTSIZE_MAX || args->valuelen >= XFS_ATTR_SF_ENTSIZE_MAX) return(XFS_ERROR(ENOSPC)); newsize = XFS_ATTR_SF_TOTSIZE(args->dp); newsize += XFS_ATTR_SF_ENTSIZE_BYNAME(args->namelen, args->valuelen); forkoff = xfs_attr_shortform_bytesfit(args->dp, newsize); if (!forkoff) return(XFS_ERROR(ENOSPC)); xfs_attr_shortform_add(args, forkoff); return(0);}/*======================================================================== * External routines when attribute list is one block *========================================================================*//* * Add a name to the leaf attribute list structure * * This leaf block cannot have a "remote" value, we only call this routine * if bmap_one_block() says there is only one block (ie: no remote blks). */intxfs_attr_leaf_addname(xfs_da_args_t *args){ xfs_inode_t *dp; xfs_dabuf_t *bp; int retval, error, committed, forkoff; /* * Read the (only) block in the attribute list in. */ dp = args->dp; args->blkno = 0; error = xfs_da_read_buf(args->trans, args->dp, args->blkno, -1, &bp, XFS_ATTR_FORK); if (error) return(error); ASSERT(bp != NULL); /* * 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_attr_leaf_lookup_int(bp, args); if ((args->flags & ATTR_REPLACE) && (retval == ENOATTR)) { xfs_da_brelse(args->trans, bp); return(retval); } else if (retval == EEXIST) { if (args->flags & ATTR_CREATE) { /* pure create op */ xfs_da_brelse(args->trans, bp); return(retval); } args->rename = 1; /* an atomic rename */ args->blkno2 = args->blkno; /* set 2nd entry info*/ args->index2 = args->index; args->rmtblkno2 = args->rmtblkno; args->rmtblkcnt2 = args->rmtblkcnt; } /* * Add the attribute to the leaf block, transitioning to a Btree * if required. */ retval = xfs_attr_leaf_add(bp, args); xfs_da_buf_done(bp); if (retval == ENOSPC) { /* * Promote the attribute list to the Btree format, then * Commit that transaction so that the node_addname() call * can manage its own transactions. */ XFS_BMAP_INIT(args->flist, args->firstblock); error = xfs_attr_leaf_to_node(args); if (!error) { error = xfs_bmap_finish(&args->trans, args->flist, &committed); } if (error) { ASSERT(committed); args->trans = NULL; xfs_bmap_cancel(args->flist); return(error); } /* * bmap_finish() may have committed the last trans and started
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -