xfs_dir2_block.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,249 行 · 第 1/3 页
C
1,249 行
/* * 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_dir2_block.c * XFS V2 directory implementation, single-block form. * See xfs_dir2_block.h for the format. */#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_dir.h"#include "xfs_dir2.h"#include "xfs_dmapi.h"#include "xfs_mount.h"#include "xfs_bmap_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_da_btree.h"#include "xfs_dir_leaf.h"#include "xfs_dir2_data.h"#include "xfs_dir2_leaf.h"#include "xfs_dir2_block.h"#include "xfs_dir2_trace.h"#include "xfs_error.h"/* * Local function prototypes. */static void xfs_dir2_block_log_leaf(xfs_trans_t *tp, xfs_dabuf_t *bp, int first, int last);static void xfs_dir2_block_log_tail(xfs_trans_t *tp, xfs_dabuf_t *bp);static int xfs_dir2_block_lookup_int(xfs_da_args_t *args, xfs_dabuf_t **bpp, int *entno);static int xfs_dir2_block_sort(const void *a, const void *b);/* * Add an entry to a block directory. */int /* error */xfs_dir2_block_addname( xfs_da_args_t *args) /* directory op arguments */{ xfs_dir2_data_free_t *bf; /* bestfree table in block */ xfs_dir2_block_t *block; /* directory block structure */ xfs_dir2_leaf_entry_t *blp; /* block leaf entries */ xfs_dabuf_t *bp; /* buffer for block */ xfs_dir2_block_tail_t *btp; /* block tail */ int compact; /* need to compact leaf ents */ xfs_dir2_data_entry_t *dep; /* block data entry */ xfs_inode_t *dp; /* directory inode */ xfs_dir2_data_unused_t *dup; /* block unused entry */ int error; /* error return value */ xfs_dir2_data_unused_t *enddup=NULL; /* unused at end of data */ xfs_dahash_t hash; /* hash value of found entry */ int high; /* high index for binary srch */ int highstale; /* high stale index */ int lfloghigh=0; /* last final leaf to log */ int lfloglow=0; /* first final leaf to log */ int len; /* length of the new entry */ int low; /* low index for binary srch */ int lowstale; /* low stale index */ int mid=0; /* midpoint for binary srch */ xfs_mount_t *mp; /* filesystem mount point */ int needlog; /* need to log header */ int needscan; /* need to rescan freespace */ xfs_dir2_data_off_t *tagp; /* pointer to tag value */ xfs_trans_t *tp; /* transaction structure */ xfs_dir2_trace_args("block_addname", args); dp = args->dp; tp = args->trans; mp = dp->i_mount; /* * Read the (one and only) directory block into dabuf bp. */ if ((error = xfs_da_read_buf(tp, dp, mp->m_dirdatablk, -1, &bp, XFS_DATA_FORK))) { return error; } ASSERT(bp != NULL); block = bp->data; /* * Check the magic number, corrupted if wrong. */ if (unlikely(INT_GET(block->hdr.magic, ARCH_CONVERT) != XFS_DIR2_BLOCK_MAGIC)) { XFS_CORRUPTION_ERROR("xfs_dir2_block_addname", XFS_ERRLEVEL_LOW, mp, block); xfs_da_brelse(tp, bp); return XFS_ERROR(EFSCORRUPTED); } len = XFS_DIR2_DATA_ENTSIZE(args->namelen); /* * Set up pointers to parts of the block. */ bf = block->hdr.bestfree; btp = XFS_DIR2_BLOCK_TAIL_P(mp, block); blp = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT); /* * No stale entries? Need space for entry and new leaf. */ if (INT_ISZERO(btp->stale, ARCH_CONVERT)) { /* * Tag just before the first leaf entry. */ tagp = (xfs_dir2_data_off_t *)blp - 1; /* * Data object just before the first leaf entry. */ enddup = (xfs_dir2_data_unused_t *)((char *)block + INT_GET(*tagp, ARCH_CONVERT)); /* * If it's not free then can't do this add without cleaning up: * the space before the first leaf entry needs to be free so it * can be expanded to hold the pointer to the new entry. */ if (INT_GET(enddup->freetag, ARCH_CONVERT) != XFS_DIR2_DATA_FREE_TAG) dup = enddup = NULL; /* * Check out the biggest freespace and see if it's the same one. */ else { dup = (xfs_dir2_data_unused_t *) ((char *)block + INT_GET(bf[0].offset, ARCH_CONVERT)); if (dup == enddup) { /* * It is the biggest freespace, is it too small * to hold the new leaf too? */ if (INT_GET(dup->length, ARCH_CONVERT) < len + (uint)sizeof(*blp)) { /* * Yes, we use the second-largest * entry instead if it works. */ if (INT_GET(bf[1].length, ARCH_CONVERT) >= len) dup = (xfs_dir2_data_unused_t *) ((char *)block + INT_GET(bf[1].offset, ARCH_CONVERT)); else dup = NULL; } } else { /* * Not the same free entry, * just check its length. */ if (INT_GET(dup->length, ARCH_CONVERT) < len) { dup = NULL; } } } compact = 0; } /* * If there are stale entries we'll use one for the leaf. * Is the biggest entry enough to avoid compaction? */ else if (INT_GET(bf[0].length, ARCH_CONVERT) >= len) { dup = (xfs_dir2_data_unused_t *) ((char *)block + INT_GET(bf[0].offset, ARCH_CONVERT)); compact = 0; } /* * Will need to compact to make this work. */ else { /* * Tag just before the first leaf entry. */ tagp = (xfs_dir2_data_off_t *)blp - 1; /* * Data object just before the first leaf entry. */ dup = (xfs_dir2_data_unused_t *)((char *)block + INT_GET(*tagp, ARCH_CONVERT)); /* * If it's not free then the data will go where the * leaf data starts now, if it works at all. */ if (INT_GET(dup->freetag, ARCH_CONVERT) == XFS_DIR2_DATA_FREE_TAG) { if (INT_GET(dup->length, ARCH_CONVERT) + (INT_GET(btp->stale, ARCH_CONVERT) - 1) * (uint)sizeof(*blp) < len) dup = NULL; } else if ((INT_GET(btp->stale, ARCH_CONVERT) - 1) * (uint)sizeof(*blp) < len) dup = NULL; else dup = (xfs_dir2_data_unused_t *)blp; compact = 1; } /* * If this isn't a real add, we're done with the buffer. */ if (args->justcheck) xfs_da_brelse(tp, bp); /* * If we don't have space for the new entry & leaf ... */ if (!dup) { /* * Not trying to actually do anything, or don't have * a space reservation: return no-space. */ if (args->justcheck || args->total == 0) return XFS_ERROR(ENOSPC); /* * Convert to the next larger format. * Then add the new entry in that format. */ error = xfs_dir2_block_to_leaf(args, bp); xfs_da_buf_done(bp); if (error) return error; return xfs_dir2_leaf_addname(args); } /* * Just checking, and it would work, so say so. */ if (args->justcheck) return 0; needlog = needscan = 0; /* * If need to compact the leaf entries, do it now. * Leave the highest-numbered stale entry stale. * XXX should be the one closest to mid but mid is not yet computed. */ if (compact) { int fromidx; /* source leaf index */ int toidx; /* target leaf index */ for (fromidx = toidx = INT_GET(btp->count, ARCH_CONVERT) - 1, highstale = lfloghigh = -1; fromidx >= 0; fromidx--) { if (INT_GET(blp[fromidx].address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR) { if (highstale == -1) highstale = toidx; else { if (lfloghigh == -1) lfloghigh = toidx; continue; } } if (fromidx < toidx) blp[toidx] = blp[fromidx]; toidx--; } lfloglow = toidx + 1 - (INT_GET(btp->stale, ARCH_CONVERT) - 1); lfloghigh -= INT_GET(btp->stale, ARCH_CONVERT) - 1; INT_MOD(btp->count, ARCH_CONVERT, -(INT_GET(btp->stale, ARCH_CONVERT) - 1)); xfs_dir2_data_make_free(tp, bp, (xfs_dir2_data_aoff_t)((char *)blp - (char *)block), (xfs_dir2_data_aoff_t)((INT_GET(btp->stale, ARCH_CONVERT) - 1) * sizeof(*blp)), &needlog, &needscan); blp += INT_GET(btp->stale, ARCH_CONVERT) - 1; INT_SET(btp->stale, ARCH_CONVERT, 1); /* * If we now need to rebuild the bestfree map, do so. * This needs to happen before the next call to use_free. */ if (needscan) { xfs_dir2_data_freescan(mp, (xfs_dir2_data_t *)block, &needlog, NULL); needscan = 0; } } /* * Set leaf logging boundaries to impossible state. * For the no-stale case they're set explicitly. */ else if (INT_GET(btp->stale, ARCH_CONVERT)) { lfloglow = INT_GET(btp->count, ARCH_CONVERT); lfloghigh = -1; } /* * Find the slot that's first lower than our hash value, -1 if none. */ for (low = 0, high = INT_GET(btp->count, ARCH_CONVERT) - 1; low <= high; ) { mid = (low + high) >> 1; if ((hash = INT_GET(blp[mid].hashval, ARCH_CONVERT)) == args->hashval) break; if (hash < args->hashval) low = mid + 1; else high = mid - 1; } while (mid >= 0 && INT_GET(blp[mid].hashval, ARCH_CONVERT) >= args->hashval) { mid--; } /* * No stale entries, will use enddup space to hold new leaf. */ if (INT_ISZERO(btp->stale, ARCH_CONVERT)) { /* * Mark the space needed for the new leaf entry, now in use. */ xfs_dir2_data_use_free(tp, bp, enddup, (xfs_dir2_data_aoff_t) ((char *)enddup - (char *)block + INT_GET(enddup->length, ARCH_CONVERT) - sizeof(*blp)), (xfs_dir2_data_aoff_t)sizeof(*blp), &needlog, &needscan); /* * Update the tail (entry count). */ INT_MOD(btp->count, ARCH_CONVERT, +1); /* * If we now need to rebuild the bestfree map, do so. * This needs to happen before the next call to use_free. */ if (needscan) { xfs_dir2_data_freescan(mp, (xfs_dir2_data_t *)block, &needlog, NULL); needscan = 0; } /* * Adjust pointer to the first leaf entry, we're about to move * the table up one to open up space for the new leaf entry. * Then adjust our index to match. */ blp--; mid++; if (mid) memmove(blp, &blp[1], mid * sizeof(*blp)); lfloglow = 0; lfloghigh = mid; } /* * Use a stale leaf for our new entry. */ else { for (lowstale = mid; lowstale >= 0 && INT_GET(blp[lowstale].address, ARCH_CONVERT) != XFS_DIR2_NULL_DATAPTR; lowstale--) continue; for (highstale = mid + 1; highstale < INT_GET(btp->count, ARCH_CONVERT) && INT_GET(blp[highstale].address, ARCH_CONVERT) != XFS_DIR2_NULL_DATAPTR && (lowstale < 0 || mid - lowstale > highstale - mid); highstale++) continue; /* * Move entries toward the low-numbered stale entry. */ if (lowstale >= 0 && (highstale == INT_GET(btp->count, ARCH_CONVERT) || mid - lowstale <= highstale - mid)) { if (mid - lowstale) memmove(&blp[lowstale], &blp[lowstale + 1], (mid - lowstale) * sizeof(*blp)); lfloglow = MIN(lowstale, lfloglow); lfloghigh = MAX(mid, lfloghigh); } /* * Move entries toward the high-numbered stale entry. */ else { ASSERT(highstale < INT_GET(btp->count, ARCH_CONVERT)); mid++; if (highstale - mid) memmove(&blp[mid + 1], &blp[mid], (highstale - mid) * sizeof(*blp)); lfloglow = MIN(mid, lfloglow); lfloghigh = MAX(highstale, lfloghigh); } INT_MOD(btp->stale, ARCH_CONVERT, -1); } /* * Point to the new data entry. */ dep = (xfs_dir2_data_entry_t *)dup; /* * Fill in the leaf entry. */ INT_SET(blp[mid].hashval, ARCH_CONVERT, args->hashval); INT_SET(blp[mid].address, ARCH_CONVERT, XFS_DIR2_BYTE_TO_DATAPTR(mp, (char *)dep - (char *)block)); xfs_dir2_block_log_leaf(tp, bp, lfloglow, lfloghigh); /* * Mark space for the data entry used.
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?