📄 xfs_inode.c
字号:
case S_IFIFO: case S_IFCHR: case S_IFBLK: case S_IFSOCK: if (unlikely(dip->di_core.di_format != XFS_DINODE_FMT_DEV)) { XFS_CORRUPTION_ERROR("xfs_iformat(3)", XFS_ERRLEVEL_LOW, ip->i_mount, dip); return XFS_ERROR(EFSCORRUPTED); } ip->i_d.di_size = 0; ip->i_size = 0; ip->i_df.if_u2.if_rdev = be32_to_cpu(dip->di_u.di_dev); break; case S_IFREG: case S_IFLNK: case S_IFDIR: switch (dip->di_core.di_format) { case XFS_DINODE_FMT_LOCAL: /* * no local regular files yet */ if (unlikely((be16_to_cpu(dip->di_core.di_mode) & S_IFMT) == S_IFREG)) { xfs_fs_repair_cmn_err(CE_WARN, ip->i_mount, "corrupt inode %Lu " "(local format for regular file).", (unsigned long long) ip->i_ino); XFS_CORRUPTION_ERROR("xfs_iformat(4)", XFS_ERRLEVEL_LOW, ip->i_mount, dip); return XFS_ERROR(EFSCORRUPTED); } di_size = be64_to_cpu(dip->di_core.di_size); if (unlikely(di_size > XFS_DFORK_DSIZE(dip, ip->i_mount))) { xfs_fs_repair_cmn_err(CE_WARN, ip->i_mount, "corrupt inode %Lu " "(bad size %Ld for local inode).", (unsigned long long) ip->i_ino, (long long) di_size); XFS_CORRUPTION_ERROR("xfs_iformat(5)", XFS_ERRLEVEL_LOW, ip->i_mount, dip); return XFS_ERROR(EFSCORRUPTED); } size = (int)di_size; error = xfs_iformat_local(ip, dip, XFS_DATA_FORK, size); break; case XFS_DINODE_FMT_EXTENTS: error = xfs_iformat_extents(ip, dip, XFS_DATA_FORK); break; case XFS_DINODE_FMT_BTREE: error = xfs_iformat_btree(ip, dip, XFS_DATA_FORK); break; default: XFS_ERROR_REPORT("xfs_iformat(6)", XFS_ERRLEVEL_LOW, ip->i_mount); return XFS_ERROR(EFSCORRUPTED); } break; default: XFS_ERROR_REPORT("xfs_iformat(7)", XFS_ERRLEVEL_LOW, ip->i_mount); return XFS_ERROR(EFSCORRUPTED); } if (error) { return error; } if (!XFS_DFORK_Q(dip)) return 0; ASSERT(ip->i_afp == NULL); ip->i_afp = kmem_zone_zalloc(xfs_ifork_zone, KM_SLEEP); ip->i_afp->if_ext_max = XFS_IFORK_ASIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t); switch (dip->di_core.di_aformat) { case XFS_DINODE_FMT_LOCAL: atp = (xfs_attr_shortform_t *)XFS_DFORK_APTR(dip); size = be16_to_cpu(atp->hdr.totsize); error = xfs_iformat_local(ip, dip, XFS_ATTR_FORK, size); break; case XFS_DINODE_FMT_EXTENTS: error = xfs_iformat_extents(ip, dip, XFS_ATTR_FORK); break; case XFS_DINODE_FMT_BTREE: error = xfs_iformat_btree(ip, dip, XFS_ATTR_FORK); break; default: error = XFS_ERROR(EFSCORRUPTED); break; } if (error) { kmem_zone_free(xfs_ifork_zone, ip->i_afp); ip->i_afp = NULL; xfs_idestroy_fork(ip, XFS_DATA_FORK); } return error;}/* * The file is in-lined in the on-disk inode. * If it fits into if_inline_data, then copy * it there, otherwise allocate a buffer for it * and copy the data there. Either way, set * if_data to point at the data. * If we allocate a buffer for the data, make * sure that its size is a multiple of 4 and * record the real size in i_real_bytes. */STATIC intxfs_iformat_local( xfs_inode_t *ip, xfs_dinode_t *dip, int whichfork, int size){ xfs_ifork_t *ifp; int real_size; /* * If the size is unreasonable, then something * is wrong and we just bail out rather than crash in * kmem_alloc() or memcpy() below. */ if (unlikely(size > XFS_DFORK_SIZE(dip, ip->i_mount, whichfork))) { xfs_fs_repair_cmn_err(CE_WARN, ip->i_mount, "corrupt inode %Lu " "(bad size %d for local fork, size = %d).", (unsigned long long) ip->i_ino, size, XFS_DFORK_SIZE(dip, ip->i_mount, whichfork)); XFS_CORRUPTION_ERROR("xfs_iformat_local", XFS_ERRLEVEL_LOW, ip->i_mount, dip); return XFS_ERROR(EFSCORRUPTED); } ifp = XFS_IFORK_PTR(ip, whichfork); real_size = 0; if (size == 0) ifp->if_u1.if_data = NULL; else if (size <= sizeof(ifp->if_u2.if_inline_data)) ifp->if_u1.if_data = ifp->if_u2.if_inline_data; else { real_size = roundup(size, 4); ifp->if_u1.if_data = kmem_alloc(real_size, KM_SLEEP); } ifp->if_bytes = size; ifp->if_real_bytes = real_size; if (size) memcpy(ifp->if_u1.if_data, XFS_DFORK_PTR(dip, whichfork), size); ifp->if_flags &= ~XFS_IFEXTENTS; ifp->if_flags |= XFS_IFINLINE; return 0;}/* * The file consists of a set of extents all * of which fit into the on-disk inode. * If there are few enough extents to fit into * the if_inline_ext, then copy them there. * Otherwise allocate a buffer for them and copy * them into it. Either way, set if_extents * to point at the extents. */STATIC intxfs_iformat_extents( xfs_inode_t *ip, xfs_dinode_t *dip, int whichfork){ xfs_bmbt_rec_t *dp; xfs_ifork_t *ifp; int nex; int size; int i; ifp = XFS_IFORK_PTR(ip, whichfork); nex = XFS_DFORK_NEXTENTS(dip, whichfork); size = nex * (uint)sizeof(xfs_bmbt_rec_t); /* * If the number of extents is unreasonable, then something * is wrong and we just bail out rather than crash in * kmem_alloc() or memcpy() below. */ if (unlikely(size < 0 || size > XFS_DFORK_SIZE(dip, ip->i_mount, whichfork))) { xfs_fs_repair_cmn_err(CE_WARN, ip->i_mount, "corrupt inode %Lu ((a)extents = %d).", (unsigned long long) ip->i_ino, nex); XFS_CORRUPTION_ERROR("xfs_iformat_extents(1)", XFS_ERRLEVEL_LOW, ip->i_mount, dip); return XFS_ERROR(EFSCORRUPTED); } ifp->if_real_bytes = 0; if (nex == 0) ifp->if_u1.if_extents = NULL; else if (nex <= XFS_INLINE_EXTS) ifp->if_u1.if_extents = ifp->if_u2.if_inline_ext; else xfs_iext_add(ifp, 0, nex); ifp->if_bytes = size; if (size) { dp = (xfs_bmbt_rec_t *) XFS_DFORK_PTR(dip, whichfork); xfs_validate_extents(ifp, nex, XFS_EXTFMT_INODE(ip)); for (i = 0; i < nex; i++, dp++) { xfs_bmbt_rec_host_t *ep = xfs_iext_get_ext(ifp, i); ep->l0 = be64_to_cpu(get_unaligned(&dp->l0)); ep->l1 = be64_to_cpu(get_unaligned(&dp->l1)); } XFS_BMAP_TRACE_EXLIST(ip, nex, whichfork); if (whichfork != XFS_DATA_FORK || XFS_EXTFMT_INODE(ip) == XFS_EXTFMT_NOSTATE) if (unlikely(xfs_check_nostate_extents( ifp, 0, nex))) { XFS_ERROR_REPORT("xfs_iformat_extents(2)", XFS_ERRLEVEL_LOW, ip->i_mount); return XFS_ERROR(EFSCORRUPTED); } } ifp->if_flags |= XFS_IFEXTENTS; return 0;}/* * The file has too many extents to fit into * the inode, so they are in B-tree format. * Allocate a buffer for the root of the B-tree * and copy the root into it. The i_extents * field will remain NULL until all of the * extents are read in (when they are needed). */STATIC intxfs_iformat_btree( xfs_inode_t *ip, xfs_dinode_t *dip, int whichfork){ xfs_bmdr_block_t *dfp; xfs_ifork_t *ifp; /* REFERENCED */ int nrecs; int size; ifp = XFS_IFORK_PTR(ip, whichfork); dfp = (xfs_bmdr_block_t *)XFS_DFORK_PTR(dip, whichfork); size = XFS_BMAP_BROOT_SPACE(dfp); nrecs = XFS_BMAP_BROOT_NUMRECS(dfp); /* * blow out if -- fork has less extents than can fit in * fork (fork shouldn't be a btree format), root btree * block has more records than can fit into the fork, * or the number of extents is greater than the number of * blocks. */ if (unlikely(XFS_IFORK_NEXTENTS(ip, whichfork) <= ifp->if_ext_max || XFS_BMDR_SPACE_CALC(nrecs) > XFS_DFORK_SIZE(dip, ip->i_mount, whichfork) || XFS_IFORK_NEXTENTS(ip, whichfork) > ip->i_d.di_nblocks)) { xfs_fs_repair_cmn_err(CE_WARN, ip->i_mount, "corrupt inode %Lu (btree).", (unsigned long long) ip->i_ino); XFS_ERROR_REPORT("xfs_iformat_btree", XFS_ERRLEVEL_LOW, ip->i_mount); return XFS_ERROR(EFSCORRUPTED); } ifp->if_broot_bytes = size; ifp->if_broot = kmem_alloc(size, KM_SLEEP); ASSERT(ifp->if_broot != NULL); /* * Copy and convert from the on-disk structure * to the in-memory structure. */ xfs_bmdr_to_bmbt(dfp, XFS_DFORK_SIZE(dip, ip->i_mount, whichfork), ifp->if_broot, size); ifp->if_flags &= ~XFS_IFEXTENTS; ifp->if_flags |= XFS_IFBROOT; return 0;}voidxfs_dinode_from_disk( xfs_icdinode_t *to, xfs_dinode_core_t *from){ to->di_magic = be16_to_cpu(from->di_magic); to->di_mode = be16_to_cpu(from->di_mode); to->di_version = from ->di_version; to->di_format = from->di_format; to->di_onlink = be16_to_cpu(from->di_onlink); to->di_uid = be32_to_cpu(from->di_uid); to->di_gid = be32_to_cpu(from->di_gid); to->di_nlink = be32_to_cpu(from->di_nlink); to->di_projid = be16_to_cpu(from->di_projid); memcpy(to->di_pad, from->di_pad, sizeof(to->di_pad)); to->di_flushiter = be16_to_cpu(from->di_flushiter); to->di_atime.t_sec = be32_to_cpu(from->di_atime.t_sec); to->di_atime.t_nsec = be32_to_cpu(from->di_atime.t_nsec); to->di_mtime.t_sec = be32_to_cpu(from->di_mtime.t_sec); to->di_mtime.t_nsec = be32_to_cpu(from->di_mtime.t_nsec); to->di_ctime.t_sec = be32_to_cpu(from->di_ctime.t_sec); to->di_ctime.t_nsec = be32_to_cpu(from->di_ctime.t_nsec); to->di_size = be64_to_cpu(from->di_size); to->di_nblocks = be64_to_cpu(from->di_nblocks); to->di_extsize = be32_to_cpu(from->di_extsize); to->di_nextents = be32_to_cpu(from->di_nextents); to->di_anextents = be16_to_cpu(from->di_anextents); to->di_forkoff = from->di_forkoff; to->di_aformat = from->di_aformat; to->di_dmevmask = be32_to_cpu(from->di_dmevmask); to->di_dmstate = be16_to_cpu(from->di_dmstate); to->di_flags = be16_to_cpu(from->di_flags); to->di_gen = be32_to_cpu(from->di_gen);}voidxfs_dinode_to_disk( xfs_dinode_core_t *to, xfs_icdinode_t *from){ to->di_magic = cpu_to_be16(from->di_magic); to->di_mode = cpu_to_be16(from->di_mode); to->di_version = from ->di_version; to->di_format = from->di_format; to->di_onlink = cpu_to_be16(from->di_onlink); to->di_uid = cpu_to_be32(from->di_uid); to->di_gid = cpu_to_be32(from->di_gid); to->di_nlink = cpu_to_be32(from->di_nlink); to->di_projid = cpu_to_be16(from->di_projid); memcpy(to->di_pad, from->di_pad, sizeof(to->di_pad)); to->di_flushiter = cpu_to_be16(from->di_flushiter); to->di_atime.t_sec = cpu_to_be32(from->di_atime.t_sec); to->di_atime.t_nsec = cpu_to_be32(from->di_atime.t_nsec); to->di_mtime.t_sec = cpu_to_be32(from->di_mtime.t_sec); to->di_mtime.t_nsec = cpu_to_be32(from->di_mtime.t_nsec); to->di_ctime.t_sec = cpu_to_be32(from->di_ctime.t_sec); to->di_ctime.t_nsec = cpu_to_be32(from->di_ctime.t_nsec); to->di_size = cpu_to_be64(from->di_size); to->di_nblocks = cpu_to_be64(from->di_nblocks); to->di_extsize = cpu_to_be32(from->di_extsize); to->di_nextents = cpu_to_be32(from->di_nextents); to->di_anextents = cpu_to_be16(from->di_anextents); to->di_forkoff = from->di_forkoff; to->di_aformat = from->di_aformat; to->di_dmevmask = cpu_to_be32(from->di_dmevmask); to->di_dmstate = cpu_to_be16(from->di_dmstate); to->di_flags = cpu_to_be16(from->di_flags); to->di_gen = cpu_to_be32(from->di_gen);}STATIC uint_xfs_dic2xflags( __uint16_t di_flags){ uint flags = 0; if (di_flags & XFS_DIFLAG_ANY) { if (di_flags & XFS_DIFLAG_REALTIME) flags |= XFS_XFLAG_REALTIME; if (di_flags & XFS_DIFLAG_PREALLOC) flags |= XFS_XFLAG_PREALLOC; if (di_flags & XFS_DIFLAG_IMMUTABLE) flags |= XFS_XFLAG_IMMUTABLE; if (di_flags & XFS_DIFLAG_APPEND) flags |= XFS_XFLAG_APPEND; if (di_flags & XFS_DIFLAG_SYNC) flags |= XFS_XFLAG_SYNC; if (di_flags & XFS_DIFLAG_NOATIME) flags |= XFS_XFLAG_NOATIME; if (di_flags & XFS_DIFLAG_NODUMP) flags |= XFS_XFLAG_NODUMP; if (di_flags & XFS_DIFLAG_RTINHERIT) flags |= XFS_XFLAG_RTINHERIT; if (di_flags & XFS_DIFLAG_PROJINHERIT) flags |= XFS_XFLAG_PROJINHERIT; if (di_flags & XFS_DIFLAG_NOSYMLINKS) flags |= XFS_XFLAG_NOSYMLINKS; if (di_flags & XFS_DIFLAG_EXTSIZE) flags |= XFS_XFLAG_EXTSIZE; if (di_flags & XFS_DIFLAG_EXTSZINHERIT) flags |= XFS_XFLAG_EXTSZINHERIT; if (di_flags & XFS_DIFLAG_NODEFRAG) flags |= XFS_XFLAG_NODEFRAG; if (di_flags & XFS_DIFLAG_FILESTREAM) flags |= XFS_XFLAG_FILESTREAM; } return flags;}uintxfs_ip2xflags( xfs_inode_t *ip){ xfs_icdinode_t *dic = &ip->i_d; return _xfs_dic2xflags(dic->di_flags) | (XFS_CFORK_Q(dic) ? XFS_XFLAG_HASATTR : 0);}uintxfs_dic2xflags( xfs_dinode_core_t *dic){ return _xfs_dic2xflags(be16_to_cpu(dic->di_flags)) | (XFS_CFORK_Q_DISK(dic) ? XFS_XFLAG_HASATTR : 0);}/* * Given a mount structure and an inode number, return a pointer * to a newly allocated in-core inode corresponding to the given * inode number. * * Initialize the inode's attributes and extent pointers if it * already has them (it will not if the inode has no links). */intxfs_iread( xfs_mount_t *mp, xfs_trans_t *tp, xfs_ino_t ino, xfs_inode_t **ipp, xfs_daddr_t bno, uint imap_flags){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -