xfs_attr.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,474 行 · 第 1/5 页
C
2,474 行
memset((char *)&args, 0, sizeof(args)); args.name = name; args.namelen = namelen; args.flags = flags; args.hashval = xfs_da_hashname(args.name, args.namelen); args.dp = dp; args.firstblock = &firstblock; args.flist = &flist; args.total = 0; args.whichfork = XFS_ATTR_FORK; /* * Attach the dquots to the inode. */ if ((error = XFS_QM_DQATTACH(mp, dp, 0))) return (error); /* * 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. */ args.trans = xfs_trans_alloc(mp, XFS_TRANS_ATTR_RM); /* * Root fork attributes can use reserved data blocks for this * operation if necessary */ if (flags & ATTR_ROOT) args.trans->t_flags |= XFS_TRANS_RESERVE; 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, NULL); 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);}/* * 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(bhv_desc_t *bdp, char *buffer, int bufsize, int flags, attrlist_cursor_kern_t *cursor, struct cred *cred){ xfs_attr_list_context_t context; xfs_inode_t *dp; 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 = XFS_BHVTOI(bdp); context.cursor = cursor; context.count = 0; context.dupcnt = 0; context.resynch = 1; context.flags = flags; if (!(flags & ATTR_KERNAMELS)) { 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; } if (XFS_FORCED_SHUTDOWN(dp->i_mount)) return (EIO); xfs_ilock(dp, XFS_ILOCK_SHARED); if (!(flags & ATTR_SECURE) && (error = xfs_iaccess(dp, S_IRUSR, cred))) { xfs_iunlock(dp, XFS_ILOCK_SHARED); return(XFS_ERROR(error)); } /* * 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); } 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.count < 0) error = XFS_ERROR(ERANGE); else error = -context.count; } 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, NULL); 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, 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); } newsize = XFS_ATTR_SF_TOTSIZE(args->dp); newsize += XFS_ATTR_SF_ENTSIZE_BYNAME(args->namelen, args->valuelen); if ((newsize <= XFS_IFORK_ASIZE(args->dp)) && (args->namelen < XFS_ATTR_SF_ENTSIZE_MAX) && (args->valuelen < XFS_ATTR_SF_ENTSIZE_MAX)) { retval = xfs_attr_shortform_add(args); ASSERT(retval == 0); } else { return(XFS_ERROR(ENOSPC)); } 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; /* * 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, *args->firstblock, &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 * a new one. We need the inode to be in all transactions. */ if (committed) { xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL); xfs_trans_ihold(args->trans, dp); } /* * Commit the current trans (including the inode) and start * a new one. */ if ((error = xfs_attr_rolltrans(&args->trans, dp))) return (error); /* * Fob the whole rest of the problem off on the Btree code. */ error = xfs_attr_node_addname(args); return(error); } /* * Commit the transaction that added the attr name so that * later routines can manage their own transactions. */ if ((error = xfs_attr_rolltrans(&args->trans, dp))) return (error); /* * If there was an out-of-line value, allocate the blocks we * identified for its storage and copy the value. This is done * after we create the attribute so that we don't overflow the * maximum size of a transaction and/or hit a deadlock. */ if (args->rmtblkno > 0) { error = xfs_attr_rmtval_set(args); if (error) return(error); } /* * If this is an atomic rename operation, we must "flip" the * incomplete flags on the "new" and "old" attribute/value pairs * so that one disappears and one appears atomically. Then we * must remove the "old" attribute/value pair. */ if (args->rename) { /* * In a separate transaction, set the incomplete flag on the * "old" attr and clear the incomplete flag on the "new" attr. */ error = xfs_attr_leaf_flipflags(args); if (error) return(error); /* * Dismantle the "old" attribute/value pair by removing * a "remote" value (if it exists). */ args->index = args->index2; args->blkno = args->blkno2; args->rmtblkno = args->rmtblkno2; args->rmtblkcnt = args->rmtblkcnt2; if (args->rmtblkno) { error = xfs_attr_rmtval_remove(args); if (error) return(error); } /* * Read in the block containing the "old" attr, then * remove the "old" attr from that block (neat, huh!) */ error = xfs_da_read_buf(args->trans, args->dp, args->blkno, -1, &bp, XFS_ATTR_FORK); if (error) return(error); ASSERT(bp != NULL); (void)xfs_attr_leaf_remove(bp, args); /* * If the result is small enough, shrink it all into the inode. */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?