xfs_inode.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,125 行 · 第 1/5 页
C
2,125 行
/* * 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/ */#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_trans_priv.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_btree.h"#include "xfs_imap.h"#include "xfs_alloc.h"#include "xfs_ialloc.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_buf_item.h"#include "xfs_rw.h"#include "xfs_error.h"#include "xfs_bit.h"#include "xfs_utils.h"#include "xfs_dir2_trace.h"#include "xfs_quota.h"#include "xfs_mac.h"#include "xfs_acl.h"kmem_zone_t *xfs_ifork_zone;kmem_zone_t *xfs_inode_zone;kmem_zone_t *xfs_chashlist_zone;/* * Used in xfs_itruncate(). This is the maximum number of extents * freed from a file in a single transaction. */#define XFS_ITRUNC_MAX_EXTENTS 2STATIC int xfs_iflush_int(xfs_inode_t *, xfs_buf_t *);STATIC int xfs_iformat_local(xfs_inode_t *, xfs_dinode_t *, int, int);STATIC int xfs_iformat_extents(xfs_inode_t *, xfs_dinode_t *, int);STATIC int xfs_iformat_btree(xfs_inode_t *, xfs_dinode_t *, int);#ifdef DEBUG/* * Make sure that the extents in the given memory buffer * are valid. */STATIC voidxfs_validate_extents( xfs_bmbt_rec_t *ep, int nrecs, int disk, xfs_exntfmt_t fmt){ xfs_bmbt_irec_t irec; xfs_bmbt_rec_t rec; int i; for (i = 0; i < nrecs; i++) { rec.l0 = get_unaligned((__uint64_t*)&ep->l0); rec.l1 = get_unaligned((__uint64_t*)&ep->l1); if (disk) xfs_bmbt_disk_get_all(&rec, &irec); else xfs_bmbt_get_all(&rec, &irec); if (fmt == XFS_EXTFMT_NOSTATE) ASSERT(irec.br_state == XFS_EXT_NORM); ep++; }}#else /* DEBUG */#define xfs_validate_extents(ep, nrecs, disk, fmt)#endif /* DEBUG *//* * Check that none of the inode's in the buffer have a next * unlinked field of 0. */#if defined(DEBUG)voidxfs_inobp_check( xfs_mount_t *mp, xfs_buf_t *bp){ int i; int j; xfs_dinode_t *dip; j = mp->m_inode_cluster_size >> mp->m_sb.sb_inodelog; for (i = 0; i < j; i++) { dip = (xfs_dinode_t *)xfs_buf_offset(bp, i * mp->m_sb.sb_inodesize); if (INT_ISZERO(dip->di_next_unlinked, ARCH_CONVERT)) { xfs_fs_cmn_err(CE_ALERT, mp, "Detected a bogus zero next_unlinked field in incore inode buffer 0x%p. About to pop an ASSERT.", bp); ASSERT(!INT_ISZERO(dip->di_next_unlinked, ARCH_CONVERT)); } }}#endif/* * called from bwrite on xfs inode buffers */voidxfs_inobp_bwcheck(xfs_buf_t *bp){ xfs_mount_t *mp; int i; int j; xfs_dinode_t *dip; ASSERT(XFS_BUF_FSPRIVATE3(bp, void *) != NULL); mp = XFS_BUF_FSPRIVATE3(bp, xfs_mount_t *); j = mp->m_inode_cluster_size >> mp->m_sb.sb_inodelog; for (i = 0; i < j; i++) { dip = (xfs_dinode_t *) xfs_buf_offset(bp, i * mp->m_sb.sb_inodesize); if (INT_GET(dip->di_core.di_magic, ARCH_CONVERT) != XFS_DINODE_MAGIC) { cmn_err(CE_WARN,"Bad magic # 0x%x in XFS inode buffer 0x%Lx, starting blockno %Ld, offset 0x%x", INT_GET(dip->di_core.di_magic, ARCH_CONVERT), (__uint64_t)(__psunsigned_t) bp, (__int64_t) XFS_BUF_ADDR(bp), xfs_buf_offset(bp, i * mp->m_sb.sb_inodesize)); xfs_fs_cmn_err(CE_WARN, mp, "corrupt, unmount and run xfs_repair"); } if (INT_ISZERO(dip->di_next_unlinked, ARCH_CONVERT)) { cmn_err(CE_WARN,"Bad next_unlinked field (0) in XFS inode buffer 0x%p, starting blockno %Ld, offset 0x%x", (__uint64_t)(__psunsigned_t) bp, (__int64_t) XFS_BUF_ADDR(bp), xfs_buf_offset(bp, i * mp->m_sb.sb_inodesize)); xfs_fs_cmn_err(CE_WARN, mp, "corrupt, unmount and run xfs_repair"); } } return;}/* * This routine is called to map an inode number within a file * system to the buffer containing the on-disk version of the * inode. It returns a pointer to the buffer containing the * on-disk inode in the bpp parameter, and in the dip parameter * it returns a pointer to the on-disk inode within that buffer. * * If a non-zero error is returned, then the contents of bpp and * dipp are undefined. * * Use xfs_imap() to determine the size and location of the * buffer to read from disk. */intxfs_inotobp( xfs_mount_t *mp, xfs_trans_t *tp, xfs_ino_t ino, xfs_dinode_t **dipp, xfs_buf_t **bpp, int *offset){ int di_ok; xfs_imap_t imap; xfs_buf_t *bp; int error; xfs_dinode_t *dip; /* * Call the space managment code to find the location of the * inode on disk. */ imap.im_blkno = 0; error = xfs_imap(mp, tp, ino, &imap, XFS_IMAP_LOOKUP); if (error != 0) { cmn_err(CE_WARN, "xfs_inotobp: xfs_imap() returned an " "error %d on %s. Returning error.", error, mp->m_fsname); return error; } /* * If the inode number maps to a block outside the bounds of the * file system then return NULL rather than calling read_buf * and panicing when we get an error from the driver. */ if ((imap.im_blkno + imap.im_len) > XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks)) { cmn_err(CE_WARN, "xfs_inotobp: inode number (%d + %d) maps to a block outside the bounds " "of the file system %s. Returning EINVAL.", imap.im_blkno, imap.im_len,mp->m_fsname); return XFS_ERROR(EINVAL); } /* * Read in the buffer. If tp is NULL, xfs_trans_read_buf() will * default to just a read_buf() call. */ error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, imap.im_blkno, (int)imap.im_len, XFS_BUF_LOCK, &bp); if (error) { cmn_err(CE_WARN, "xfs_inotobp: xfs_trans_read_buf() returned an " "error %d on %s. Returning error.", error, mp->m_fsname); return error; } dip = (xfs_dinode_t *)xfs_buf_offset(bp, 0); di_ok = INT_GET(dip->di_core.di_magic, ARCH_CONVERT) == XFS_DINODE_MAGIC && XFS_DINODE_GOOD_VERSION(INT_GET(dip->di_core.di_version, ARCH_CONVERT)); if (unlikely(XFS_TEST_ERROR(!di_ok, mp, XFS_ERRTAG_ITOBP_INOTOBP, XFS_RANDOM_ITOBP_INOTOBP))) { XFS_CORRUPTION_ERROR("xfs_inotobp", XFS_ERRLEVEL_LOW, mp, dip); xfs_trans_brelse(tp, bp); cmn_err(CE_WARN, "xfs_inotobp: XFS_TEST_ERROR() returned an " "error on %s. Returning EFSCORRUPTED.", mp->m_fsname); return XFS_ERROR(EFSCORRUPTED); } xfs_inobp_check(mp, bp); /* * Set *dipp to point to the on-disk inode in the buffer. */ *dipp = (xfs_dinode_t *)xfs_buf_offset(bp, imap.im_boffset); *bpp = bp; *offset = imap.im_boffset; return 0;}/* * This routine is called to map an inode to the buffer containing * the on-disk version of the inode. It returns a pointer to the * buffer containing the on-disk inode in the bpp parameter, and in * the dip parameter it returns a pointer to the on-disk inode within * that buffer. * * If a non-zero error is returned, then the contents of bpp and * dipp are undefined. * * If the inode is new and has not yet been initialized, use xfs_imap() * to determine the size and location of the buffer to read from disk. * If the inode has already been mapped to its buffer and read in once, * then use the mapping information stored in the inode rather than * calling xfs_imap(). This allows us to avoid the overhead of looking * at the inode btree for small block file systems (see xfs_dilocate()). * We can tell whether the inode has been mapped in before by comparing * its disk block address to 0. Only uninitialized inodes will have * 0 for the disk block address. */intxfs_itobp( xfs_mount_t *mp, xfs_trans_t *tp, xfs_inode_t *ip, xfs_dinode_t **dipp, xfs_buf_t **bpp, xfs_daddr_t bno){ xfs_buf_t *bp; int error; xfs_imap_t imap;#ifdef __KERNEL__ int i; int ni;#endif if (ip->i_blkno == (xfs_daddr_t)0) { /* * Call the space management code to find the location of the * inode on disk. */ imap.im_blkno = bno; error = xfs_imap(mp, tp, ip->i_ino, &imap, XFS_IMAP_LOOKUP); if (error != 0) { return error; } /* * If the inode number maps to a block outside the bounds * of the file system then return NULL rather than calling * read_buf and panicing when we get an error from the * driver. */ if ((imap.im_blkno + imap.im_len) > XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks)) {#ifdef DEBUG xfs_fs_cmn_err(CE_ALERT, mp, "xfs_itobp: " "(imap.im_blkno (0x%llx) " "+ imap.im_len (0x%llx)) > " " XFS_FSB_TO_BB(mp, " "mp->m_sb.sb_dblocks) (0x%llx)", (unsigned long long) imap.im_blkno, (unsigned long long) imap.im_len, XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks));#endif /* DEBUG */ return XFS_ERROR(EINVAL); } /* * Fill in the fields in the inode that will be used to * map the inode to its buffer from now on. */ ip->i_blkno = imap.im_blkno; ip->i_len = imap.im_len; ip->i_boffset = imap.im_boffset; } else { /* * We've already mapped the inode once, so just use the * mapping that we saved the first time. */ imap.im_blkno = ip->i_blkno; imap.im_len = ip->i_len; imap.im_boffset = ip->i_boffset; } ASSERT(bno == 0 || bno == imap.im_blkno); /* * Read in the buffer. If tp is NULL, xfs_trans_read_buf() will * default to just a read_buf() call. */ error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, imap.im_blkno, (int)imap.im_len, XFS_BUF_LOCK, &bp); if (error) {#ifdef DEBUG xfs_fs_cmn_err(CE_ALERT, mp, "xfs_itobp: " "xfs_trans_read_buf() returned error %d, " "imap.im_blkno 0x%llx, imap.im_len 0x%llx", error, (unsigned long long) imap.im_blkno, (unsigned long long) imap.im_len);#endif /* DEBUG */ return error; }#ifdef __KERNEL__ /* * Validate the magic number and version of every inode in the buffer * (if DEBUG kernel) or the first inode in the buffer, otherwise. */#ifdef DEBUG ni = BBTOB(imap.im_len) >> mp->m_sb.sb_inodelog;#else ni = 1;#endif for (i = 0; i < ni; i++) { int di_ok; xfs_dinode_t *dip; dip = (xfs_dinode_t *)xfs_buf_offset(bp, (i << mp->m_sb.sb_inodelog)); di_ok = INT_GET(dip->di_core.di_magic, ARCH_CONVERT) == XFS_DINODE_MAGIC && XFS_DINODE_GOOD_VERSION(INT_GET(dip->di_core.di_version, ARCH_CONVERT)); if (unlikely(XFS_TEST_ERROR(!di_ok, mp, XFS_ERRTAG_ITOBP_INOTOBP, XFS_RANDOM_ITOBP_INOTOBP))) {#ifdef DEBUG prdev("bad inode magic/vsn daddr %lld #%d (magic=%x)", mp->m_ddev_targp, (unsigned long long)imap.im_blkno, i, INT_GET(dip->di_core.di_magic, ARCH_CONVERT));#endif XFS_CORRUPTION_ERROR("xfs_itobp", XFS_ERRLEVEL_HIGH, mp, dip); xfs_trans_brelse(tp, bp); return XFS_ERROR(EFSCORRUPTED); } }#endif /* __KERNEL__ */ xfs_inobp_check(mp, bp);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?