/* * Writes a modified inode's changes out to the inode's on disk home. * Originally based on xfs_iflush_int() from xfs_inode.c in the kernel. */ int libxfs_iflush_int(xfs_inode_t *ip, xfs_buf_t *bp) { xfs_inode_log_item_t *iip; xfs_dinode_t *dip; xfs_mount_t *mp; ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL); ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_BTREE || ip->i_d.di_nextents > ip->i_df.if_ext_max); ASSERT(ip->i_d.di_version > 1); iip = ip->i_itemp; mp = ip->i_mount; /* set *dip = inode's place in the buffer */ dip = xfs_buf_offset(bp, ip->i_imap.im_boffset); ASSERT(ip->i_d.di_magic == XFS_DINODE_MAGIC); if ((ip->i_d.di_mode & S_IFMT) == S_IFREG) { ASSERT( (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS) || (ip->i_d.di_format == XFS_DINODE_FMT_BTREE) ); } else if ((ip->i_d.di_mode & S_IFMT) == S_IFDIR) { ASSERT( (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS) || (ip->i_d.di_format == XFS_DINODE_FMT_BTREE) || (ip->i_d.di_format == XFS_DINODE_FMT_LOCAL) ); } ASSERT(ip->i_d.di_nextents+ip->i_d.di_anextents <= ip->i_d.di_nblocks); ASSERT(ip->i_d.di_forkoff <= mp->m_sb.sb_inodesize); /* bump the change count on v3 inodes */ if (ip->i_d.di_version == 3) ip->i_d.di_changecount++; /* * Copy the dirty parts of the inode into the on-disk * inode. We always copy out the core of the inode, * because if the inode is dirty at all the core must * be. */ xfs_dinode_to_disk(dip, &ip->i_d); xfs_iflush_fork(ip, dip, iip, XFS_DATA_FORK); if (XFS_IFORK_Q(ip)) xfs_iflush_fork(ip, dip, iip, XFS_ATTR_FORK); /* update the lsn in the on disk inode if required */ if (ip->i_d.di_version == 3) dip->di_lsn = cpu_to_be64(iip->ili_item.li_lsn); /* generate the checksum. */ xfs_dinode_calc_crc(mp, dip); return 0; }
/* * Writes a modified inode's changes out to the inode's on disk home. * Originally based on xfs_iflush_int() from xfs_inode.c in the kernel. */ int libxfs_iflush_int(xfs_inode_t *ip, xfs_buf_t *bp) { xfs_inode_log_item_t *iip; xfs_dinode_t *dip; xfs_mount_t *mp; ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL); ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_BTREE || ip->i_d.di_nextents > ip->i_df.if_ext_max); iip = ip->i_itemp; mp = ip->i_mount; /* set *dip = inode's place in the buffer */ dip = (xfs_dinode_t *)xfs_buf_offset(bp, ip->i_boffset); #ifdef DEBUG ASSERT(ip->i_d.di_magic == XFS_DINODE_MAGIC); if ((ip->i_d.di_mode & IFMT) == IFREG) { ASSERT( (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS) || (ip->i_d.di_format == XFS_DINODE_FMT_BTREE) ); } else if ((ip->i_d.di_mode & IFMT) == IFDIR) { ASSERT( (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS) || (ip->i_d.di_format == XFS_DINODE_FMT_BTREE) || (ip->i_d.di_format == XFS_DINODE_FMT_LOCAL) ); } ASSERT(ip->i_d.di_nextents+ip->i_d.di_anextents <= ip->i_d.di_nblocks); ASSERT(ip->i_d.di_forkoff <= mp->m_sb.sb_inodesize); #endif /* * Copy the dirty parts of the inode into the on-disk * inode. We always copy out the core of the inode, * because if the inode is dirty at all the core must * be. */ xfs_xlate_dinode_core((xfs_caddr_t)&(dip->di_core), &(ip->i_d), -1, ARCH_CONVERT); /* * If this is really an old format inode and the superblock version * has not been updated to support only new format inodes, then * convert back to the old inode format. If the superblock version * has been updated, then make the conversion permanent. */ ASSERT(ip->i_d.di_version == XFS_DINODE_VERSION_1 || XFS_SB_VERSION_HASNLINK(&mp->m_sb)); if (ip->i_d.di_version == XFS_DINODE_VERSION_1) { if (!XFS_SB_VERSION_HASNLINK(&mp->m_sb)) { /* * Convert it back. */ ASSERT(ip->i_d.di_nlink <= XFS_MAXLINK_1); INT_SET(dip->di_core.di_onlink, ARCH_CONVERT, ip->i_d.di_nlink); } else { /* * The superblock version has already been bumped, * so just make the conversion to the new inode * format permanent. */ ip->i_d.di_version = XFS_DINODE_VERSION_2; INT_SET(dip->di_core.di_version, ARCH_CONVERT, XFS_DINODE_VERSION_2); ip->i_d.di_onlink = 0; INT_ZERO(dip->di_core.di_onlink, ARCH_CONVERT); bzero(&(ip->i_d.di_pad[0]), sizeof(ip->i_d.di_pad)); bzero(&(dip->di_core.di_pad[0]), sizeof(dip->di_core.di_pad)); ASSERT(ip->i_d.di_projid == 0); } } if (xfs_iflush_fork(ip, dip, iip, XFS_DATA_FORK, bp) == EFSCORRUPTED) return EFSCORRUPTED; if (XFS_IFORK_Q(ip)) { /* The only error from xfs_iflush_fork is on the data fork. */ xfs_iflush_fork(ip, dip, iip, XFS_ATTR_FORK, bp); } return 0; }