xfs_attr_leaf.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,154 行 · 第 1/5 页
C
2,154 行
/* * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 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. * * Further, this software is distributed without any warranty that it is * free of the rightful claim of any third person regarding infringement * or the like. Any license provided herein, whether implied or * otherwise, applies only to this software file. Patent licenses, if * any, provided herein do not apply to combinations of this program with * other software, or any other product whatsoever. * * You should have received a copy of the GNU General Public License along * with this program; if not, write the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston MA 02111-1307, USA. * * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, * Mountain View, CA 94043, or: * * http://www.sgi.com * * For further information regarding this notice, see: * * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ *//* * xfs_attr_leaf.c * * GROT: figure out how to recover gracefully when bmap returns ENOSPC. */#include "xfs.h"#include "xfs_macros.h"#include "xfs_types.h"#include "xfs_inum.h"#include "xfs_log.h"#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"#include "xfs_alloc_btree.h"#include "xfs_bmap_btree.h"#include "xfs_ialloc_btree.h"#include "xfs_alloc.h"#include "xfs_btree.h"#include "xfs_attr_sf.h"#include "xfs_dir_sf.h"#include "xfs_dir2_sf.h"#include "xfs_dinode.h"#include "xfs_inode_item.h"#include "xfs_inode.h"#include "xfs_bmap.h"#include "xfs_da_btree.h"#include "xfs_attr.h"#include "xfs_attr_leaf.h"#include "xfs_error.h"#include "xfs_bit.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_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);/* * 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);/*======================================================================== * External routines when dirsize < XFS_LITINO(mp). *========================================================================*//* * Create the initial contents of a shortform attribute list. */intxfs_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; INT_ZERO(hdr->count, ARCH_CONVERT); INT_SET(hdr->totsize, ARCH_CONVERT, sizeof(*hdr)); xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_ADATA); return(0);}/* * Add a name/value pair to the shortform attribute list. * Overflow from the inode has already been checked for. */intxfs_attr_shortform_add(xfs_da_args_t *args){ xfs_attr_shortform_t *sf; xfs_attr_sf_entry_t *sfe; int i, offset, size; xfs_inode_t *dp; xfs_ifork_t *ifp; dp = args->dp; 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 < INT_GET(sf->hdr.count, ARCH_CONVERT); sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) { if (sfe->namelen != args->namelen) continue; if (memcmp(args->name, sfe->nameval, args->namelen) != 0) continue; if (((args->flags & ATTR_SECURE) != 0) != ((sfe->flags & XFS_ATTR_SECURE) != 0)) continue; if (((args->flags & ATTR_ROOT) != 0) != ((sfe->flags & XFS_ATTR_ROOT) != 0)) continue; return(XFS_ERROR(EEXIST)); } 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; INT_SET(sfe->valuelen, ARCH_CONVERT, args->valuelen); sfe->flags = (args->flags & ATTR_SECURE) ? XFS_ATTR_SECURE : ((args->flags & ATTR_ROOT) ? XFS_ATTR_ROOT : 0); memcpy(sfe->nameval, args->name, args->namelen); memcpy(&sfe->nameval[args->namelen], args->value, args->valuelen); INT_MOD(sf->hdr.count, ARCH_CONVERT, 1); INT_MOD(sf->hdr.totsize, ARCH_CONVERT, size); xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_ADATA); return(0);}/* * Remove a name 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_inode_t *dp; /* * Remove the attribute. */ dp = args->dp; base = sizeof(xfs_attr_sf_hdr_t); sf = (xfs_attr_shortform_t *)dp->i_afp->if_u1.if_data; sfe = &sf->list[0]; for (i = 0; i < INT_GET(sf->hdr.count, ARCH_CONVERT); 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 (((args->flags & ATTR_SECURE) != 0) != ((sfe->flags & XFS_ATTR_SECURE) != 0)) continue; if (((args->flags & ATTR_ROOT) != 0) != ((sfe->flags & XFS_ATTR_ROOT) != 0)) continue; break; } if (i == INT_GET(sf->hdr.count, ARCH_CONVERT)) return(XFS_ERROR(ENOATTR)); end = base + size; totsize = INT_GET(sf->hdr.totsize, ARCH_CONVERT); if (end != totsize) { memmove(&((char *)sf)[base], &((char *)sf)[end], totsize - end); } INT_MOD(sf->hdr.count, ARCH_CONVERT, -1); INT_MOD(sf->hdr.totsize, ARCH_CONVERT, -size); xfs_idata_realloc(dp, -size, XFS_ATTR_FORK); xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_ADATA); 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 < INT_GET(sf->hdr.count, ARCH_CONVERT); sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) { if (sfe->namelen != args->namelen) continue; if (memcmp(args->name, sfe->nameval, args->namelen) != 0) continue; if (((args->flags & ATTR_SECURE) != 0) != ((sfe->flags & XFS_ATTR_SECURE) != 0)) continue; if (((args->flags & ATTR_ROOT) != 0) != ((sfe->flags & XFS_ATTR_ROOT) != 0)) continue; return(XFS_ERROR(EEXIST)); } return(XFS_ERROR(ENOATTR));}/* * Look up a name in a shortform attribute list structure. *//*ARGSUSED*/intxfs_attr_shortform_getvalue(xfs_da_args_t *args){ xfs_attr_shortform_t *sf; xfs_attr_sf_entry_t *sfe; int i; ASSERT(args->dp->i_d.di_aformat == XFS_IFINLINE); sf = (xfs_attr_shortform_t *)args->dp->i_afp->if_u1.if_data; sfe = &sf->list[0]; for (i = 0; i < INT_GET(sf->hdr.count, ARCH_CONVERT); sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) { if (sfe->namelen != args->namelen) continue; if (memcmp(args->name, sfe->nameval, args->namelen) != 0) continue; if (((args->flags & ATTR_SECURE) != 0) != ((sfe->flags & XFS_ATTR_SECURE) != 0)) continue; if (((args->flags & ATTR_ROOT) != 0) != ((sfe->flags & XFS_ATTR_ROOT) != 0)) continue; if (args->flags & ATTR_KERNOVAL) { args->valuelen = INT_GET(sfe->valuelen, ARCH_CONVERT); return(XFS_ERROR(EEXIST)); } if (args->valuelen < INT_GET(sfe->valuelen, ARCH_CONVERT)) { args->valuelen = INT_GET(sfe->valuelen, ARCH_CONVERT); return(XFS_ERROR(ERANGE)); } args->valuelen = INT_GET(sfe->valuelen, ARCH_CONVERT); memcpy(args->value, &sfe->nameval[args->namelen], args->valuelen); return(XFS_ERROR(EEXIST)); } return(XFS_ERROR(ENOATTR));}/* * Convert from using the shortform to the leaf. */intxfs_attr_shortform_to_leaf(xfs_da_args_t *args){ xfs_inode_t *dp; xfs_attr_shortform_t *sf; xfs_attr_sf_entry_t *sfe; xfs_da_args_t nargs; char *tmpbuffer; int error, i, size; xfs_dablk_t blkno; xfs_dabuf_t *bp; xfs_ifork_t *ifp; dp = args->dp; ifp = dp->i_afp; sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data; size = INT_GET(sf->hdr.totsize, ARCH_CONVERT); tmpbuffer = kmem_alloc(size, KM_SLEEP); ASSERT(tmpbuffer != NULL); memcpy(tmpbuffer, ifp->if_u1.if_data, size); sf = (xfs_attr_shortform_t *)tmpbuffer; xfs_idata_realloc(dp, -size, XFS_ATTR_FORK); bp = NULL; error = xfs_da_grow_inode(args, &blkno); if (error) { /* * If we hit an IO error middle of the transaction inside * grow_inode(), we may have inconsistent data. Bail out. */ if (error == EIO) goto out; xfs_idata_realloc(dp, size, XFS_ATTR_FORK); /* try to put */ memcpy(ifp->if_u1.if_data, tmpbuffer, size); /* it back */ goto out; } ASSERT(blkno == 0); error = xfs_attr_leaf_create(args, blkno, &bp); if (error) { error = xfs_da_shrink_inode(args, 0, bp); bp = NULL; if (error) goto out; xfs_idata_realloc(dp, size, XFS_ATTR_FORK); /* try to put */ memcpy(ifp->if_u1.if_data, tmpbuffer, size); /* it back */ goto out; } memset((char *)&nargs, 0, sizeof(nargs)); nargs.dp = dp; nargs.firstblock = args->firstblock; nargs.flist = args->flist; nargs.total = args->total; nargs.whichfork = XFS_ATTR_FORK; nargs.trans = args->trans; nargs.oknoent = 1; sfe = &sf->list[0]; for (i = 0; i < INT_GET(sf->hdr.count, ARCH_CONVERT); i++) { nargs.name = (char *)sfe->nameval; nargs.namelen = sfe->namelen; nargs.value = (char *)&sfe->nameval[nargs.namelen]; nargs.valuelen = INT_GET(sfe->valuelen, ARCH_CONVERT); nargs.hashval = xfs_da_hashname((char *)sfe->nameval, sfe->namelen); nargs.flags = (sfe->flags & XFS_ATTR_SECURE) ? ATTR_SECURE : ((sfe->flags & XFS_ATTR_ROOT) ? ATTR_ROOT : 0); error = xfs_attr_leaf_lookup_int(bp, &nargs); /* set a->index */ ASSERT(error == ENOATTR); error = xfs_attr_leaf_add(bp, &nargs); ASSERT(error != ENOSPC); if (error) goto out; sfe = XFS_ATTR_SF_NEXTENTRY(sfe); } error = 0;out: if(bp) xfs_da_buf_done(bp); kmem_free(tmpbuffer, size); return(error);}STATIC intxfs_attr_shortform_compare(const void *a, const void *b){ xfs_attr_sf_sort_t *sa, *sb; sa = (xfs_attr_sf_sort_t *)a; sb = (xfs_attr_sf_sort_t *)b; if (INT_GET(sa->hash, ARCH_CONVERT) < INT_GET(sb->hash, ARCH_CONVERT)) { return(-1); } else if (INT_GET(sa->hash, ARCH_CONVERT) > INT_GET(sb->hash, ARCH_CONVERT)) { return(1); } else { return(sa->entno - sb->entno); }}/* * Copy out entries of shortform attribute lists for attr_list(). * Shortform atrtribute lists are not stored in hashval sorted order. * If the output buffer is not large enough to hold them all, then we * we have to calculate each entries' hashvalue and sort them before * we can begin returning them to the user. *//*ARGSUSED*/intxfs_attr_shortform_list(xfs_attr_list_context_t *context)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?