📄 xfs_attr_leaf.c
字号:
/* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */#include "xfs.h"#include "xfs_fs.h"#include "xfs_types.h"#include "xfs_bit.h"#include "xfs_log.h"#include "xfs_inum.h"#include "xfs_trans.h"#include "xfs_sb.h"#include "xfs_ag.h"#include "xfs_dir2.h"#include "xfs_dmapi.h"#include "xfs_mount.h"#include "xfs_da_btree.h"#include "xfs_bmap_btree.h"#include "xfs_alloc_btree.h"#include "xfs_ialloc_btree.h"#include "xfs_alloc.h"#include "xfs_btree.h"#include "xfs_dir2_sf.h"#include "xfs_attr_sf.h"#include "xfs_dinode.h"#include "xfs_inode.h"#include "xfs_inode_item.h"#include "xfs_bmap.h"#include "xfs_attr.h"#include "xfs_attr_leaf.h"#include "xfs_error.h"/* * xfs_attr_leaf.c * * Routines to implement leaf blocks of attributes as Btrees of hashed names. *//*======================================================================== * Function prototypes for the kernel. *========================================================================*//* * Routines used for growing the Btree. */STATIC int xfs_attr_leaf_create(xfs_da_args_t *args, xfs_dablk_t which_block, xfs_dabuf_t **bpp);STATIC int xfs_attr_leaf_add_work(xfs_dabuf_t *leaf_buffer, xfs_da_args_t *args, int freemap_index);STATIC void xfs_attr_leaf_compact(xfs_trans_t *trans, xfs_dabuf_t *leaf_buffer);STATIC void xfs_attr_leaf_rebalance(xfs_da_state_t *state, xfs_da_state_blk_t *blk1, xfs_da_state_blk_t *blk2);STATIC int xfs_attr_leaf_figure_balance(xfs_da_state_t *state, xfs_da_state_blk_t *leaf_blk_1, xfs_da_state_blk_t *leaf_blk_2, int *number_entries_in_blk1, int *number_usedbytes_in_blk1);/* * Routines used for shrinking the Btree. */STATIC int xfs_attr_node_inactive(xfs_trans_t **trans, xfs_inode_t *dp, xfs_dabuf_t *bp, int level);STATIC int xfs_attr_leaf_inactive(xfs_trans_t **trans, xfs_inode_t *dp, xfs_dabuf_t *bp);STATIC int xfs_attr_leaf_freextent(xfs_trans_t **trans, xfs_inode_t *dp, xfs_dablk_t blkno, int blkcnt);/* * Utility routines. */STATIC void xfs_attr_leaf_moveents(xfs_attr_leafblock_t *src_leaf, int src_start, xfs_attr_leafblock_t *dst_leaf, int dst_start, int move_count, xfs_mount_t *mp);STATIC int xfs_attr_leaf_entsize(xfs_attr_leafblock_t *leaf, int index);/*======================================================================== * 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 intxfs_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 intxfs_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;}/*======================================================================== * External routines when attribute fork size < XFS_LITINO(mp). *========================================================================*//* * Query whether the requested number of additional bytes of extended * attribute space will be able to fit inline. * Returns zero if not, else the di_forkoff fork offset to be used in the * literal area for attribute data once the new bytes have been added. * * di_forkoff must be 8 byte aligned, hence is stored as a >>3 value; * special case for dev/uuid inodes, they have fixed size data forks. */intxfs_attr_shortform_bytesfit(xfs_inode_t *dp, int bytes){ int offset; int minforkoff; /* lower limit on valid forkoff locations */ int maxforkoff; /* upper limit on valid forkoff locations */ int dsize; xfs_mount_t *mp = dp->i_mount; offset = (XFS_LITINO(mp) - bytes) >> 3; /* rounded down */ switch (dp->i_d.di_format) { case XFS_DINODE_FMT_DEV: minforkoff = roundup(sizeof(xfs_dev_t), 8) >> 3; return (offset >= minforkoff) ? minforkoff : 0; case XFS_DINODE_FMT_UUID: minforkoff = roundup(sizeof(uuid_t), 8) >> 3; return (offset >= minforkoff) ? minforkoff : 0; } if (!(mp->m_flags & XFS_MOUNT_ATTR2)) { if (bytes <= XFS_IFORK_ASIZE(dp)) return mp->m_attroffset >> 3; return 0; } dsize = dp->i_df.if_bytes; switch (dp->i_d.di_format) { case XFS_DINODE_FMT_EXTENTS: /* * If there is no attr fork and the data fork is extents, * determine if creating the default attr fork will result * in the extents form migrating to btree. If so, the * minimum offset only needs to be the space required for * the btree root. */ if (!dp->i_d.di_forkoff && dp->i_df.if_bytes > mp->m_attroffset) dsize = XFS_BMDR_SPACE_CALC(MINDBTPTRS); break; case XFS_DINODE_FMT_BTREE: /* * If have data btree then keep forkoff if we have one, * otherwise we are adding a new attr, so then we set * minforkoff to where the btree root can finish so we have * plenty of room for attrs */ if (dp->i_d.di_forkoff) { if (offset < dp->i_d.di_forkoff) return 0; else return dp->i_d.di_forkoff; } else dsize = XFS_BMAP_BROOT_SPACE(dp->i_df.if_broot); break; } /* * A data fork btree root must have space for at least * MINDBTPTRS key/ptr pairs if the data fork is small or empty. */ minforkoff = MAX(dsize, XFS_BMDR_SPACE_CALC(MINDBTPTRS)); minforkoff = roundup(minforkoff, 8) >> 3; /* attr fork btree root can have at least this many key/ptr pairs */ maxforkoff = XFS_LITINO(mp) - XFS_BMDR_SPACE_CALC(MINABTPTRS); maxforkoff = maxforkoff >> 3; /* rounded down */ if (offset >= minforkoff && offset < maxforkoff) return offset; if (offset >= maxforkoff) return maxforkoff; return 0;}/* * Switch on the ATTR2 superblock bit (implies also FEATURES2) */STATIC voidxfs_sbversion_add_attr2(xfs_mount_t *mp, xfs_trans_t *tp){ unsigned long s; if ((mp->m_flags & XFS_MOUNT_ATTR2) && !(XFS_SB_VERSION_HASATTR2(&mp->m_sb))) { s = XFS_SB_LOCK(mp); if (!XFS_SB_VERSION_HASATTR2(&mp->m_sb)) { XFS_SB_VERSION_ADDATTR2(&mp->m_sb); XFS_SB_UNLOCK(mp, s); xfs_mod_sb(tp, XFS_SB_VERSIONNUM | XFS_SB_FEATURES2); } else XFS_SB_UNLOCK(mp, s); }}/* * Create the initial contents of a shortform attribute list. */voidxfs_attr_shortform_create(xfs_da_args_t *args){ xfs_attr_sf_hdr_t *hdr; xfs_inode_t *dp; xfs_ifork_t *ifp; dp = args->dp; ASSERT(dp != NULL); ifp = dp->i_afp; ASSERT(ifp != NULL); ASSERT(ifp->if_bytes == 0); if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS) { ifp->if_flags &= ~XFS_IFEXTENTS; /* just in case */ dp->i_d.di_aformat = XFS_DINODE_FMT_LOCAL; ifp->if_flags |= XFS_IFINLINE; } else { ASSERT(ifp->if_flags & XFS_IFINLINE); } xfs_idata_realloc(dp, sizeof(*hdr), XFS_ATTR_FORK); hdr = (xfs_attr_sf_hdr_t *)ifp->if_u1.if_data; hdr->count = 0; hdr->totsize = cpu_to_be16(sizeof(*hdr)); xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_ADATA);}/* * Add a name/value pair to the shortform attribute list. * Overflow from the inode has already been checked for. */voidxfs_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; xfs_mount_t *mp; xfs_inode_t *dp; xfs_ifork_t *ifp; dp = args->dp; mp = dp->i_mount; dp->i_d.di_forkoff = forkoff; dp->i_df.if_ext_max = XFS_IFORK_DSIZE(dp) / (uint)sizeof(xfs_bmbt_rec_t); dp->i_afp->if_ext_max = XFS_IFORK_ASIZE(dp) / (uint)sizeof(xfs_bmbt_rec_t); 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++) {#ifdef DEBUG if (sfe->namelen != args->namelen) continue; if (memcmp(args->name, sfe->nameval, args->namelen) != 0) continue; if (!xfs_attr_namesp_match(args->flags, sfe->flags)) continue; ASSERT(0);#endif } offset = (char *)sfe - (char *)sf; size = XFS_ATTR_SF_ENTSIZE_BYNAME(args->namelen, args->valuelen); xfs_idata_realloc(dp, size, XFS_ATTR_FORK); sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data; sfe = (xfs_attr_sf_entry_t *)((char *)sf + offset); sfe->namelen = args->namelen; sfe->valuelen = args->valuelen; 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++; be16_add(&sf->hdr.totsize, size); xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_ADATA); xfs_sbversion_add_attr2(mp, args->trans);}/* * Remove an attribute from the shortform attribute list structure. */intxfs_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; 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; for (i = 0; i < end; sfe = XFS_ATTR_SF_NEXTENTRY(sfe), base += size, i++) { size = XFS_ATTR_SF_ENTSIZE(sfe); if (sfe->namelen != args->namelen) continue; if (memcmp(sfe->nameval, args->name, args->namelen) != 0) continue; if (!xfs_attr_namesp_match(args->flags, sfe->flags)) continue; break; } if (i == end) return(XFS_ERROR(ENOATTR)); /* * Fix up the attribute fork data, covering the hole */ end = base + size; totsize = be16_to_cpu(sf->hdr.totsize); if (end != totsize) memmove(&((char *)sf)[base], &((char *)sf)[end], totsize - end); sf->hdr.count--; be16_add(&sf->hdr.totsize, -size); /* * Fix up the start offset of the attribute fork */ totsize -= size; if (totsize == sizeof(xfs_attr_sf_hdr_t) && !args->addname && (mp->m_flags & XFS_MOUNT_ATTR2) && (dp->i_d.di_format != XFS_DINODE_FMT_BTREE)) { /* * Last attribute now removed, revert to original * inode format making all literal area available * to the data fork once more. */ xfs_idestroy_fork(dp, XFS_ATTR_FORK); dp->i_d.di_forkoff = 0; dp->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS; ASSERT(dp->i_d.di_anextents == 0); ASSERT(dp->i_afp == NULL); dp->i_df.if_ext_max = XFS_IFORK_DSIZE(dp) / (uint)sizeof(xfs_bmbt_rec_t); xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE); } else { xfs_idata_realloc(dp, -size, XFS_ATTR_FORK); dp->i_d.di_forkoff = xfs_attr_shortform_bytesfit(dp, totsize); ASSERT(dp->i_d.di_forkoff); ASSERT(totsize > sizeof(xfs_attr_sf_hdr_t) || args->addname || !(mp->m_flags & XFS_MOUNT_ATTR2) || dp->i_d.di_format == XFS_DINODE_FMT_BTREE); dp->i_afp->if_ext_max = XFS_IFORK_ASIZE(dp) / (uint)sizeof(xfs_bmbt_rec_t); dp->i_df.if_ext_max = XFS_IFORK_DSIZE(dp) / (uint)sizeof(xfs_bmbt_rec_t); xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_ADATA); } xfs_sbversion_add_attr2(mp, args->trans); return(0);}/* * Look up a name in a shortform attribute list structure. *//*ARGSUSED*/intxfs_attr_shortform_lookup(xfs_da_args_t *args){ xfs_attr_shortform_t *sf; xfs_attr_sf_entry_t *sfe; int i; xfs_ifork_t *ifp; ifp = args->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++) { if (sfe->namelen != args->namelen) continue; if (memcmp(args->name, sfe->nameval, args->namelen) != 0) continue; if (!xfs_attr_namesp_match(args->flags, sfe->flags)) continue; return(XFS_ERROR(EEXIST)); } return(XFS_ERROR(ENOATTR));}/* * Look up a name in a shortform attribute list structure. *//*ARGSUSED*/int
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -