📄 xfs_inode.c
字号:
xfs_buf_t *bp; xfs_dinode_t *dip; xfs_inode_t *ip; int error; ASSERT(xfs_inode_zone != NULL); ip = kmem_zone_zalloc(xfs_inode_zone, KM_SLEEP); ip->i_ino = ino; ip->i_mount = mp; atomic_set(&ip->i_iocount, 0); spin_lock_init(&ip->i_flags_lock); /* * Get pointer's to the on-disk inode and the buffer containing it. * If the inode number refers to a block outside the file system * then xfs_itobp() will return NULL. In this case we should * return NULL as well. Set i_blkno to 0 so that xfs_itobp() will * know that this is a new incore inode. */ error = xfs_itobp(mp, tp, ip, &dip, &bp, bno, imap_flags); if (error) { kmem_zone_free(xfs_inode_zone, ip); return error; } /* * Initialize inode's trace buffers. * Do this before xfs_iformat in case it adds entries. */#ifdef XFS_VNODE_TRACE ip->i_trace = ktrace_alloc(VNODE_TRACE_SIZE, KM_SLEEP);#endif#ifdef XFS_BMAP_TRACE ip->i_xtrace = ktrace_alloc(XFS_BMAP_KTRACE_SIZE, KM_SLEEP);#endif#ifdef XFS_BMBT_TRACE ip->i_btrace = ktrace_alloc(XFS_BMBT_KTRACE_SIZE, KM_SLEEP);#endif#ifdef XFS_RW_TRACE ip->i_rwtrace = ktrace_alloc(XFS_RW_KTRACE_SIZE, KM_SLEEP);#endif#ifdef XFS_ILOCK_TRACE ip->i_lock_trace = ktrace_alloc(XFS_ILOCK_KTRACE_SIZE, KM_SLEEP);#endif#ifdef XFS_DIR2_TRACE ip->i_dir_trace = ktrace_alloc(XFS_DIR2_KTRACE_SIZE, KM_SLEEP);#endif /* * If we got something that isn't an inode it means someone * (nfs or dmi) has a stale handle. */ if (be16_to_cpu(dip->di_core.di_magic) != XFS_DINODE_MAGIC) { kmem_zone_free(xfs_inode_zone, ip); xfs_trans_brelse(tp, bp);#ifdef DEBUG xfs_fs_cmn_err(CE_ALERT, mp, "xfs_iread: " "dip->di_core.di_magic (0x%x) != " "XFS_DINODE_MAGIC (0x%x)", be16_to_cpu(dip->di_core.di_magic), XFS_DINODE_MAGIC);#endif /* DEBUG */ return XFS_ERROR(EINVAL); } /* * If the on-disk inode is already linked to a directory * entry, copy all of the inode into the in-core inode. * xfs_iformat() handles copying in the inode format * specific information. * Otherwise, just get the truly permanent information. */ if (dip->di_core.di_mode) { xfs_dinode_from_disk(&ip->i_d, &dip->di_core); error = xfs_iformat(ip, dip); if (error) { kmem_zone_free(xfs_inode_zone, ip); xfs_trans_brelse(tp, bp);#ifdef DEBUG xfs_fs_cmn_err(CE_ALERT, mp, "xfs_iread: " "xfs_iformat() returned error %d", error);#endif /* DEBUG */ return error; } } else { ip->i_d.di_magic = be16_to_cpu(dip->di_core.di_magic); ip->i_d.di_version = dip->di_core.di_version; ip->i_d.di_gen = be32_to_cpu(dip->di_core.di_gen); ip->i_d.di_flushiter = be16_to_cpu(dip->di_core.di_flushiter); /* * Make sure to pull in the mode here as well in * case the inode is released without being used. * This ensures that xfs_inactive() will see that * the inode is already free and not try to mess * with the uninitialized part of it. */ ip->i_d.di_mode = 0; /* * Initialize the per-fork minima and maxima for a new * inode here. xfs_iformat will do it for old inodes. */ ip->i_df.if_ext_max = XFS_IFORK_DSIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t); } INIT_LIST_HEAD(&ip->i_reclaim); /* * The inode format changed when we moved the link count and * made it 32 bits long. If this is an old format inode, * convert it in memory to look like a new one. If it gets * flushed to disk we will convert back before flushing or * logging it. We zero out the new projid field and the old link * count field. We'll handle clearing the pad field (the remains * of the old uuid field) when we actually convert the inode to * the new format. We don't change the version number so that we * can distinguish this from a real new format inode. */ if (ip->i_d.di_version == XFS_DINODE_VERSION_1) { ip->i_d.di_nlink = ip->i_d.di_onlink; ip->i_d.di_onlink = 0; ip->i_d.di_projid = 0; } ip->i_delayed_blks = 0; ip->i_size = ip->i_d.di_size; /* * Mark the buffer containing the inode as something to keep * around for a while. This helps to keep recently accessed * meta-data in-core longer. */ XFS_BUF_SET_REF(bp, XFS_INO_REF); /* * Use xfs_trans_brelse() to release the buffer containing the * on-disk inode, because it was acquired with xfs_trans_read_buf() * in xfs_itobp() above. If tp is NULL, this is just a normal * brelse(). If we're within a transaction, then xfs_trans_brelse() * will only release the buffer if it is not dirty within the * transaction. It will be OK to release the buffer in this case, * because inodes on disk are never destroyed and we will be * locking the new in-core inode before putting it in the hash * table where other processes can find it. Thus we don't have * to worry about the inode being changed just because we released * the buffer. */ xfs_trans_brelse(tp, bp); *ipp = ip; return 0;}/* * Read in extents from a btree-format inode. * Allocate and fill in if_extents. Real work is done in xfs_bmap.c. */intxfs_iread_extents( xfs_trans_t *tp, xfs_inode_t *ip, int whichfork){ int error; xfs_ifork_t *ifp; xfs_extnum_t nextents; size_t size; if (unlikely(XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE)) { XFS_ERROR_REPORT("xfs_iread_extents", XFS_ERRLEVEL_LOW, ip->i_mount); return XFS_ERROR(EFSCORRUPTED); } nextents = XFS_IFORK_NEXTENTS(ip, whichfork); size = nextents * sizeof(xfs_bmbt_rec_t); ifp = XFS_IFORK_PTR(ip, whichfork); /* * We know that the size is valid (it's checked in iformat_btree) */ ifp->if_lastex = NULLEXTNUM; ifp->if_bytes = ifp->if_real_bytes = 0; ifp->if_flags |= XFS_IFEXTENTS; xfs_iext_add(ifp, 0, nextents); error = xfs_bmap_read_extents(tp, ip, whichfork); if (error) { xfs_iext_destroy(ifp); ifp->if_flags &= ~XFS_IFEXTENTS; return error; } xfs_validate_extents(ifp, nextents, XFS_EXTFMT_INODE(ip)); return 0;}/* * Allocate an inode on disk and return a copy of its in-core version. * The in-core inode is locked exclusively. Set mode, nlink, and rdev * appropriately within the inode. The uid and gid for the inode are * set according to the contents of the given cred structure. * * Use xfs_dialloc() to allocate the on-disk inode. If xfs_dialloc() * has a free inode available, call xfs_iget() * to obtain the in-core version of the allocated inode. Finally, * fill in the inode and log its initial contents. In this case, * ialloc_context would be set to NULL and call_again set to false. * * If xfs_dialloc() does not have an available inode, * it will replenish its supply by doing an allocation. Since we can * only do one allocation within a transaction without deadlocks, we * must commit the current transaction before returning the inode itself. * In this case, therefore, we will set call_again to true and return. * The caller should then commit the current transaction, start a new * transaction, and call xfs_ialloc() again to actually get the inode. * * To ensure that some other process does not grab the inode that * was allocated during the first call to xfs_ialloc(), this routine * also returns the [locked] bp pointing to the head of the freelist * as ialloc_context. The caller should hold this buffer across * the commit and pass it back into this routine on the second call. * * If we are allocating quota inodes, we do not have a parent inode * to attach to or associate with (i.e. pip == NULL) because they * are not linked into the directory structure - they are attached * directly to the superblock - and so have no parent. */intxfs_ialloc( xfs_trans_t *tp, xfs_inode_t *pip, mode_t mode, xfs_nlink_t nlink, xfs_dev_t rdev, cred_t *cr, xfs_prid_t prid, int okalloc, xfs_buf_t **ialloc_context, boolean_t *call_again, xfs_inode_t **ipp){ xfs_ino_t ino; xfs_inode_t *ip; bhv_vnode_t *vp; uint flags; int error; /* * Call the space management code to pick * the on-disk inode to be allocated. */ error = xfs_dialloc(tp, pip ? pip->i_ino : 0, mode, okalloc, ialloc_context, call_again, &ino); if (error != 0) { return error; } if (*call_again || ino == NULLFSINO) { *ipp = NULL; return 0; } ASSERT(*ialloc_context == NULL); /* * Get the in-core inode with the lock held exclusively. * This is because we're setting fields here we need * to prevent others from looking at until we're done. */ error = xfs_trans_iget(tp->t_mountp, tp, ino, XFS_IGET_CREATE, XFS_ILOCK_EXCL, &ip); if (error != 0) { return error; } ASSERT(ip != NULL); vp = XFS_ITOV(ip); ip->i_d.di_mode = (__uint16_t)mode; ip->i_d.di_onlink = 0; ip->i_d.di_nlink = nlink; ASSERT(ip->i_d.di_nlink == nlink); ip->i_d.di_uid = current_fsuid(cr); ip->i_d.di_gid = current_fsgid(cr); ip->i_d.di_projid = prid; memset(&(ip->i_d.di_pad[0]), 0, sizeof(ip->i_d.di_pad)); /* * If the superblock version is up to where we support new format * inodes and this is currently an old format inode, then change * the inode version number now. This way we only do the conversion * here rather than here and in the flush/logging code. */ if (XFS_SB_VERSION_HASNLINK(&tp->t_mountp->m_sb) && ip->i_d.di_version == XFS_DINODE_VERSION_1) { ip->i_d.di_version = XFS_DINODE_VERSION_2; /* * We've already zeroed the old link count, the projid field, * and the pad field. */ } /* * Project ids won't be stored on disk if we are using a version 1 inode. */ if ((prid != 0) && (ip->i_d.di_version == XFS_DINODE_VERSION_1)) xfs_bump_ino_vers2(tp, ip); if (pip && XFS_INHERIT_GID(pip)) { ip->i_d.di_gid = pip->i_d.di_gid; if ((pip->i_d.di_mode & S_ISGID) && (mode & S_IFMT) == S_IFDIR) { ip->i_d.di_mode |= S_ISGID; } } /* * If the group ID of the new file does not match the effective group * ID or one of the supplementary group IDs, the S_ISGID bit is cleared * (and only if the irix_sgid_inherit compatibility variable is set). */ if ((irix_sgid_inherit) && (ip->i_d.di_mode & S_ISGID) && (!in_group_p((gid_t)ip->i_d.di_gid))) { ip->i_d.di_mode &= ~S_ISGID; } ip->i_d.di_size = 0; ip->i_size = 0; ip->i_d.di_nextents = 0; ASSERT(ip->i_d.di_nblocks == 0); xfs_ichgtime(ip, XFS_ICHGTIME_CHG|XFS_ICHGTIME_ACC|XFS_ICHGTIME_MOD); /* * di_gen will have been taken care of in xfs_iread. */ ip->i_d.di_extsize = 0; ip->i_d.di_dmevmask = 0; ip->i_d.di_dmstate = 0; ip->i_d.di_flags = 0; flags = XFS_ILOG_CORE; switch (mode & S_IFMT) { case S_IFIFO: case S_IFCHR: case S_IFBLK: case S_IFSOCK: ip->i_d.di_format = XFS_DINODE_FMT_DEV; ip->i_df.if_u2.if_rdev = rdev; ip->i_df.if_flags = 0; flags |= XFS_ILOG_DEV; break; case S_IFREG: if (pip && xfs_inode_is_filestream(pip)) { error = xfs_filestream_associate(pip, ip); if (error < 0) return -error; if (!error) xfs_iflags_set(ip, XFS_IFILESTREAM); } /* fall through */ case S_IFDIR: if (pip && (pip->i_d.di_flags & XFS_DIFLAG_ANY)) { uint di_flags = 0; if ((mode & S_IFMT) == S_IFDIR) { if (pip->i_d.di_flags & XFS_DIFLAG_RTINHERIT) di_flags |= XFS_DIFLAG_RTINHERIT; if (pip->i_d.di_flags & XFS_DIFLAG_EXTSZINHERIT) { di_flags |= XFS_DIFLAG_EXTSZINHERIT; ip->i_d.di_extsize = pip->i_d.di_extsize; } } else if ((mode & S_IFMT) == S_IFREG) { if (pip->i_d.di_flags & XFS_DIFLAG_RTINHERIT) { di_flags |= XFS_DIFLAG_REALTIME; ip->i_iocore.io_flags |= XFS_IOCORE_RT; } if (pip->i_d.di_flags & XFS_DIFLAG_EXTSZINHERIT) { di_flags |= XFS_DIFLAG_EXTSIZE; ip->i_d.di_extsize = pip->i_d.di_extsize; } } if ((pip->i_d.di_flags & XFS_DIFLAG_NOATIME) && xfs_inherit_noatime) di_flags |= XFS_DIFLAG_NOATIME; if ((pip->i_d.di_flags & XFS_DIFLAG_NODUMP) && xfs_inherit_nodump) di_flags |= XFS_DIFLAG_NODUMP; if ((pip->i_d.di_flags & XFS_DIFLAG_SYNC) && xfs_inherit_sync) di_flags |= XFS_DIFLAG_SYNC; if ((pip->i_d.di_flags & XFS_DIFLAG_NOSYMLINKS) && xfs_inherit_nosymlinks) di_flags |= XFS_DIFLAG_NOSYMLINKS; if (pip->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) di_flags |= XFS_DIFLAG_PROJINHERIT; if ((pip->i_d.di_flags & XFS_DIFLAG_NODEFRAG) && xfs_inherit_nodefrag) di_flags |= XFS_DIFLAG_NODEFRAG; if (pip->i_d.di_flags & XFS_DIFLAG_FILESTREAM) di_flags |= XFS_DIFLAG_FILESTREAM; ip->i_d.di_flags |= di_flags; } /* FALLTHROUGH */ case S_IFLNK: ip->i_d.di_format = XFS_DINODE_FMT_EXTENTS; ip->i_df.if_flags = XFS_IFEXTENTS; ip->i_df.if_bytes = ip->i_df.if_real_bytes = 0; ip->i_df.if_u1.if_extents = NULL; break; default: ASSERT(0); } /* * Attribute fork settings for new inode. */ ip->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS; ip->i_d.di_anextents = 0; /* * Log the new values stuffed into the inode. */ xfs_trans_log_inode(tp, ip, flags); /* now that we have an i_mode we can setup inode ops and unlock */ xfs_initialize_vnode(tp->t_mountp, vp, ip); *ipp = ip; return 0;}/* * Check to make sure that there are no blocks allocated to the * file beyond the size of the file. We don't check this for * files with fixed size extents or real time extents, but we
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -