diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-03-21 11:53:05 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-03-21 11:53:05 -0700 |
commit | 53d2e6976bd4042672ed7b90dfbf4b31635b7dcf (patch) | |
tree | 1d137e044c52433df6b4785fed1c7aafbb9333bc /fs/xfs/xfs_inode.c | |
parent | d407574e7948210223a7adca5ff26e3b0ec8143e (diff) | |
parent | 2cdb958aba6afbced5bc563167813b972b6acbfe (diff) |
Merge tag 'xfs-for-linus-4.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/dgc/linux-xfs
Pull xfs updates from Dave Chinner:
"There's quite a lot in this request, and there's some cross-over with
ext4, dax and quota code due to the nature of the changes being made.
As for the rest of the XFS changes, there are lots of little things
all over the place, which add up to a lot of changes in the end.
The major changes are that we've reduced the size of the struct
xfs_inode by ~100 bytes (gives an inode cache footprint reduction of
>10%), the writepage code now only does a single set of mapping tree
lockups so uses less CPU, delayed allocation reservations won't
overrun under random write loads anymore, and we added compile time
verification for on-disk structure sizes so we find out when a commit
or platform/compiler change breaks the on disk structure as early as
possible.
Change summary:
- error propagation for direct IO failures fixes for both XFS and
ext4
- new quota interfaces and XFS implementation for iterating all the
quota IDs in the filesystem
- locking fixes for real-time device extent allocation
- reduction of duplicate information in the xfs and vfs inode, saving
roughly 100 bytes of memory per cached inode.
- buffer flag cleanup
- rework of the writepage code to use the generic write clustering
mechanisms
- several fixes for inode flag based DAX enablement
- rework of remount option parsing
- compile time verification of on-disk format structure sizes
- delayed allocation reservation overrun fixes
- lots of little error handling fixes
- small memory leak fixes
- enable xfsaild freezing again"
* tag 'xfs-for-linus-4.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/dgc/linux-xfs: (66 commits)
xfs: always set rvalp in xfs_dir2_node_trim_free
xfs: ensure committed is initialized in xfs_trans_roll
xfs: borrow indirect blocks from freed extent when available
xfs: refactor delalloc indlen reservation split into helper
xfs: update freeblocks counter after extent deletion
xfs: debug mode forced buffered write failure
xfs: remove impossible condition
xfs: check sizes of XFS on-disk structures at compile time
xfs: ioends require logically contiguous file offsets
xfs: use named array initializers for log item dumping
xfs: fix computation of inode btree maxlevels
xfs: reinitialise per-AG structures if geometry changes during recovery
xfs: remove xfs_trans_get_block_res
xfs: fix up inode32/64 (re)mount handling
xfs: fix format specifier , should be %llx and not %llu
xfs: sanitize remount options
xfs: convert mount option parsing to tokens
xfs: fix two memory leaks in xfs_attr_list.c error paths
xfs: XFS_DIFLAG2_DAX limited by PAGE_SIZE
xfs: dynamically switch modes when XFS_DIFLAG2_DAX is set/cleared
...
Diffstat (limited to 'fs/xfs/xfs_inode.c')
-rw-r--r-- | fs/xfs/xfs_inode.c | 174 |
1 files changed, 71 insertions, 103 deletions
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index ceba1a83cacc..96f606deee31 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -57,9 +57,9 @@ kmem_zone_t *xfs_inode_zone; */ #define XFS_ITRUNC_MAX_EXTENTS 2 -STATIC int xfs_iflush_int(xfs_inode_t *, xfs_buf_t *); - -STATIC int xfs_iunlink_remove(xfs_trans_t *, xfs_inode_t *); +STATIC int xfs_iflush_int(struct xfs_inode *, struct xfs_buf *); +STATIC int xfs_iunlink(struct xfs_trans *, struct xfs_inode *); +STATIC int xfs_iunlink_remove(struct xfs_trans *, struct xfs_inode *); /* * helper function to extract extent size hint from inode @@ -766,6 +766,7 @@ xfs_ialloc( uint flags; int error; struct timespec tv; + struct inode *inode; /* * Call the space management code to pick @@ -791,6 +792,7 @@ xfs_ialloc( if (error) return error; ASSERT(ip != NULL); + inode = VFS_I(ip); /* * We always convert v1 inodes to v2 now - we only support filesystems @@ -800,20 +802,16 @@ xfs_ialloc( if (ip->i_d.di_version == 1) ip->i_d.di_version = 2; - ip->i_d.di_mode = mode; - ip->i_d.di_onlink = 0; - ip->i_d.di_nlink = nlink; - ASSERT(ip->i_d.di_nlink == nlink); + inode->i_mode = mode; + set_nlink(inode, nlink); ip->i_d.di_uid = xfs_kuid_to_uid(current_fsuid()); ip->i_d.di_gid = xfs_kgid_to_gid(current_fsgid()); xfs_set_projid(ip, prid); - memset(&(ip->i_d.di_pad[0]), 0, sizeof(ip->i_d.di_pad)); if (pip && XFS_INHERIT_GID(pip)) { ip->i_d.di_gid = pip->i_d.di_gid; - if ((pip->i_d.di_mode & S_ISGID) && S_ISDIR(mode)) { - ip->i_d.di_mode |= S_ISGID; - } + if ((VFS_I(pip)->i_mode & S_ISGID) && S_ISDIR(mode)) + inode->i_mode |= S_ISGID; } /* @@ -822,38 +820,29 @@ xfs_ialloc( * (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(xfs_gid_to_kgid(ip->i_d.di_gid)))) { - ip->i_d.di_mode &= ~S_ISGID; - } + (inode->i_mode & S_ISGID) && + (!in_group_p(xfs_gid_to_kgid(ip->i_d.di_gid)))) + inode->i_mode &= ~S_ISGID; ip->i_d.di_size = 0; ip->i_d.di_nextents = 0; ASSERT(ip->i_d.di_nblocks == 0); tv = current_fs_time(mp->m_super); - ip->i_d.di_mtime.t_sec = (__int32_t)tv.tv_sec; - ip->i_d.di_mtime.t_nsec = (__int32_t)tv.tv_nsec; - ip->i_d.di_atime = ip->i_d.di_mtime; - ip->i_d.di_ctime = ip->i_d.di_mtime; + inode->i_mtime = tv; + inode->i_atime = tv; + inode->i_ctime = tv; - /* - * 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; if (ip->i_d.di_version == 3) { - ASSERT(ip->i_d.di_ino == ino); - ASSERT(uuid_equal(&ip->i_d.di_uuid, &mp->m_sb.sb_meta_uuid)); - ip->i_d.di_crc = 0; - ip->i_d.di_changecount = 1; - ip->i_d.di_lsn = 0; + inode->i_version = 1; ip->i_d.di_flags2 = 0; - memset(&(ip->i_d.di_pad2[0]), 0, sizeof(ip->i_d.di_pad2)); - ip->i_d.di_crtime = ip->i_d.di_mtime; + ip->i_d.di_crtime.t_sec = (__int32_t)tv.tv_sec; + ip->i_d.di_crtime.t_nsec = (__int32_t)tv.tv_nsec; } @@ -1092,35 +1081,24 @@ xfs_dir_ialloc( } /* - * Decrement the link count on an inode & log the change. - * If this causes the link count to go to zero, initiate the - * logging activity required to truncate a file. + * Decrement the link count on an inode & log the change. If this causes the + * link count to go to zero, move the inode to AGI unlinked list so that it can + * be freed when the last active reference goes away via xfs_inactive(). */ int /* error */ xfs_droplink( xfs_trans_t *tp, xfs_inode_t *ip) { - int error; - xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_CHG); - ASSERT (ip->i_d.di_nlink > 0); - ip->i_d.di_nlink--; drop_nlink(VFS_I(ip)); xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); - error = 0; - if (ip->i_d.di_nlink == 0) { - /* - * We're dropping the last link to this file. - * Move the on-disk inode to the AGI unlinked list. - * From xfs_inactive() we will pull the inode from - * the list and free it. - */ - error = xfs_iunlink(tp, ip); - } - return error; + if (VFS_I(ip)->i_nlink) + return 0; + + return xfs_iunlink(tp, ip); } /* @@ -1134,8 +1112,6 @@ xfs_bumplink( xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_CHG); ASSERT(ip->i_d.di_version > 1); - ASSERT(ip->i_d.di_nlink > 0 || (VFS_I(ip)->i_state & I_LINKABLE)); - ip->i_d.di_nlink++; inc_nlink(VFS_I(ip)); xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); return 0; @@ -1393,7 +1369,6 @@ xfs_create_tmpfile( */ xfs_qm_vop_create_dqattach(tp, ip, udqp, gdqp, pdqp); - ip->i_d.di_nlink--; error = xfs_iunlink(tp, ip); if (error) goto out_trans_cancel; @@ -1444,7 +1419,7 @@ xfs_link( trace_xfs_link(tdp, target_name); - ASSERT(!S_ISDIR(sip->i_d.di_mode)); + ASSERT(!S_ISDIR(VFS_I(sip)->i_mode)); if (XFS_FORCED_SHUTDOWN(mp)) return -EIO; @@ -1492,7 +1467,10 @@ xfs_link( xfs_bmap_init(&free_list, &first_block); - if (sip->i_d.di_nlink == 0) { + /* + * Handle initial link state of O_TMPFILE inode + */ + if (VFS_I(sip)->i_nlink == 0) { error = xfs_iunlink_remove(tp, sip); if (error) goto error_return; @@ -1648,7 +1626,7 @@ xfs_release( xfs_mount_t *mp = ip->i_mount; int error; - if (!S_ISREG(ip->i_d.di_mode) || (ip->i_d.di_mode == 0)) + if (!S_ISREG(VFS_I(ip)->i_mode) || (VFS_I(ip)->i_mode == 0)) return 0; /* If this is a read-only mount, don't do this (would generate I/O) */ @@ -1679,7 +1657,7 @@ xfs_release( } } - if (ip->i_d.di_nlink == 0) + if (VFS_I(ip)->i_nlink == 0) return 0; if (xfs_can_free_eofblocks(ip, false)) { @@ -1883,7 +1861,7 @@ xfs_inactive( * If the inode is already free, then there can be nothing * to clean up here. */ - if (ip->i_d.di_mode == 0) { + if (VFS_I(ip)->i_mode == 0) { ASSERT(ip->i_df.if_real_bytes == 0); ASSERT(ip->i_df.if_broot_bytes == 0); return; @@ -1895,7 +1873,7 @@ xfs_inactive( if (mp->m_flags & XFS_MOUNT_RDONLY) return; - if (ip->i_d.di_nlink != 0) { + if (VFS_I(ip)->i_nlink != 0) { /* * force is true because we are evicting an inode from the * cache. Post-eof blocks must be freed, lest we end up with @@ -1907,7 +1885,7 @@ xfs_inactive( return; } - if (S_ISREG(ip->i_d.di_mode) && + if (S_ISREG(VFS_I(ip)->i_mode) && (ip->i_d.di_size != 0 || XFS_ISIZE(ip) != 0 || ip->i_d.di_nextents > 0 || ip->i_delayed_blks > 0)) truncate = 1; @@ -1916,7 +1894,7 @@ xfs_inactive( if (error) return; - if (S_ISLNK(ip->i_d.di_mode)) + if (S_ISLNK(VFS_I(ip)->i_mode)) error = xfs_inactive_symlink(ip); else if (truncate) error = xfs_inactive_truncate(ip); @@ -1952,16 +1930,21 @@ xfs_inactive( } /* - * This is called when the inode's link count goes to 0. - * We place the on-disk inode on a list in the AGI. It - * will be pulled from this list when the inode is freed. + * This is called when the inode's link count goes to 0 or we are creating a + * tmpfile via O_TMPFILE. In the case of a tmpfile, @ignore_linkcount will be + * set to true as the link count is dropped to zero by the VFS after we've + * created the file successfully, so we have to add it to the unlinked list + * while the link count is non-zero. + * + * We place the on-disk inode on a list in the AGI. It will be pulled from this + * list when the inode is freed. */ -int +STATIC int xfs_iunlink( - xfs_trans_t *tp, - xfs_inode_t *ip) + struct xfs_trans *tp, + struct xfs_inode *ip) { - xfs_mount_t *mp; + xfs_mount_t *mp = tp->t_mountp; xfs_agi_t *agi; xfs_dinode_t *dip; xfs_buf_t *agibp; @@ -1971,10 +1954,7 @@ xfs_iunlink( int offset; int error; - ASSERT(ip->i_d.di_nlink == 0); - ASSERT(ip->i_d.di_mode != 0); - - mp = tp->t_mountp; + ASSERT(VFS_I(ip)->i_mode != 0); /* * Get the agi buffer first. It ensures lock ordering @@ -2412,10 +2392,10 @@ xfs_ifree( struct xfs_icluster xic = { 0 }; ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); - ASSERT(ip->i_d.di_nlink == 0); + ASSERT(VFS_I(ip)->i_nlink == 0); ASSERT(ip->i_d.di_nextents == 0); ASSERT(ip->i_d.di_anextents == 0); - ASSERT(ip->i_d.di_size == 0 || !S_ISREG(ip->i_d.di_mode)); + ASSERT(ip->i_d.di_size == 0 || !S_ISREG(VFS_I(ip)->i_mode)); ASSERT(ip->i_d.di_nblocks == 0); /* @@ -2429,7 +2409,7 @@ xfs_ifree( if (error) return error; - ip->i_d.di_mode = 0; /* mark incore inode as free */ + VFS_I(ip)->i_mode = 0; /* mark incore inode as free */ ip->i_d.di_flags = 0; ip->i_d.di_dmevmask = 0; ip->i_d.di_forkoff = 0; /* mark the attr fork not in use */ @@ -2439,7 +2419,7 @@ xfs_ifree( * Bump the generation count so no one will be confused * by reincarnations of this inode. */ - ip->i_d.di_gen++; + VFS_I(ip)->i_generation++; xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); if (xic.deleted) @@ -2526,7 +2506,7 @@ xfs_remove( { xfs_mount_t *mp = dp->i_mount; xfs_trans_t *tp = NULL; - int is_dir = S_ISDIR(ip->i_d.di_mode); + int is_dir = S_ISDIR(VFS_I(ip)->i_mode); int error = 0; xfs_bmap_free_t free_list; xfs_fsblock_t first_block; @@ -2580,8 +2560,8 @@ xfs_remove( * If we're removing a directory perform some additional validation. */ if (is_dir) { - ASSERT(ip->i_d.di_nlink >= 2); - if (ip->i_d.di_nlink != 2) { + ASSERT(VFS_I(ip)->i_nlink >= 2); + if (VFS_I(ip)->i_nlink != 2) { error = -ENOTEMPTY; goto out_trans_cancel; } @@ -2771,7 +2751,7 @@ xfs_cross_rename( if (dp1 != dp2) { dp2_flags = XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG; - if (S_ISDIR(ip2->i_d.di_mode)) { + if (S_ISDIR(VFS_I(ip2)->i_mode)) { error = xfs_dir_replace(tp, ip2, &xfs_name_dotdot, dp1->i_ino, first_block, free_list, spaceres); @@ -2779,7 +2759,7 @@ xfs_cross_rename( goto out_trans_abort; /* transfer ip2 ".." reference to dp1 */ - if (!S_ISDIR(ip1->i_d.di_mode)) { + if (!S_ISDIR(VFS_I(ip1)->i_mode)) { error = xfs_droplink(tp, dp2); if (error) goto out_trans_abort; @@ -2798,7 +2778,7 @@ xfs_cross_rename( ip2_flags |= XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG; } - if (S_ISDIR(ip1->i_d.di_mode)) { + if (S_ISDIR(VFS_I(ip1)->i_mode)) { error = xfs_dir_replace(tp, ip1, &xfs_name_dotdot, dp2->i_ino, first_block, free_list, spaceres); @@ -2806,7 +2786,7 @@ xfs_cross_rename( goto out_trans_abort; /* transfer ip1 ".." reference to dp2 */ - if (!S_ISDIR(ip2->i_d.di_mode)) { + if (!S_ISDIR(VFS_I(ip2)->i_mode)) { error = xfs_droplink(tp, dp1); if (error) goto out_trans_abort; @@ -2903,7 +2883,7 @@ xfs_rename( struct xfs_inode *inodes[__XFS_SORT_INODES]; int num_inodes = __XFS_SORT_INODES; bool new_parent = (src_dp != target_dp); - bool src_is_directory = S_ISDIR(src_ip->i_d.di_mode); + bool src_is_directory = S_ISDIR(VFS_I(src_ip)->i_mode); int spaceres; int error; @@ -3032,12 +3012,12 @@ xfs_rename( * target and source are directories and that target can be * destroyed, or that neither is a directory. */ - if (S_ISDIR(target_ip->i_d.di_mode)) { + if (S_ISDIR(VFS_I(target_ip)->i_mode)) { /* * Make sure target dir is empty. */ if (!(xfs_dir_isempty(target_ip)) || - (target_ip->i_d.di_nlink > 2)) { + (VFS_I(target_ip)->i_nlink > 2)) { error = -EEXIST; goto out_trans_cancel; } @@ -3144,7 +3124,7 @@ xfs_rename( * intermediate state on disk. */ if (wip) { - ASSERT(VFS_I(wip)->i_nlink == 0 && wip->i_d.di_nlink == 0); + ASSERT(VFS_I(wip)->i_nlink == 0); error = xfs_bumplink(tp, wip); if (error) goto out_bmap_cancel; @@ -3313,7 +3293,7 @@ cluster_corrupt_out: * mark it as stale and brelse. */ if (bp->b_iodone) { - XFS_BUF_UNDONE(bp); + bp->b_flags &= ~XBF_DONE; xfs_buf_stale(bp); xfs_buf_ioerror(bp, -EIO); xfs_buf_ioend(bp); @@ -3462,14 +3442,7 @@ xfs_iflush_int( __func__, ip->i_ino, be16_to_cpu(dip->di_magic), dip); goto corrupt_out; } - if (XFS_TEST_ERROR(ip->i_d.di_magic != XFS_DINODE_MAGIC, - mp, XFS_ERRTAG_IFLUSH_2, XFS_RANDOM_IFLUSH_2)) { - xfs_alert_tag(mp, XFS_PTAG_IFLUSH, - "%s: Bad inode %Lu, ptr 0x%p, magic number 0x%x", - __func__, ip->i_ino, ip, ip->i_d.di_magic); - goto corrupt_out; - } - if (S_ISREG(ip->i_d.di_mode)) { + if (S_ISREG(VFS_I(ip)->i_mode)) { if (XFS_TEST_ERROR( (ip->i_d.di_format != XFS_DINODE_FMT_EXTENTS) && (ip->i_d.di_format != XFS_DINODE_FMT_BTREE), @@ -3479,7 +3452,7 @@ xfs_iflush_int( __func__, ip->i_ino, ip); goto corrupt_out; } - } else if (S_ISDIR(ip->i_d.di_mode)) { + } else if (S_ISDIR(VFS_I(ip)->i_mode)) { if (XFS_TEST_ERROR( (ip->i_d.di_format != XFS_DINODE_FMT_EXTENTS) && (ip->i_d.di_format != XFS_DINODE_FMT_BTREE) && @@ -3523,12 +3496,11 @@ xfs_iflush_int( ip->i_d.di_flushiter++; /* - * 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. + * 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_inode_to_disk(ip, dip, iip->ili_item.li_lsn); /* Wrap, we never let the log put out DI_MAX_FLUSH */ if (ip->i_d.di_flushiter == DI_MAX_FLUSH) @@ -3580,10 +3552,6 @@ xfs_iflush_int( */ xfs_buf_attach_iodone(bp, xfs_iflush_done, &iip->ili_item); - /* 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); |