A preparatory patch; encapsulate i_count reading, modeled after d_count(). There are a few sites around the kernel that look at i_count and base decsions on it, some look OK, some really flaky: - spufs: i_count == 1, no i_lock - ext4_free_inode: i_count == 0, OK because super_operations::evict_inode - writeback_single_inode: i_count || I_WILL_FREE, seems OK - hpfs_write_inode: no clue - fsnotify_unmount_inodes: i_count == 0, seem OK, we hold i_lock. find_inode_fast() is serialized with i_lock futex uses inc_not_zero(). - btrfs_invalidate_inodes: checks for >1 i_count, while holding one, seems racy, nothing (obviously) stops another reference from happening. Might be fine in that any further reference cannot be an alias, definitely needs a comment. - check_conflicting_open: no clue - maybe_indirect_to_direct: no clue Signed-off-by: Peter Zijlstra (Intel) --- arch/powerpc/platforms/cell/spufs/file.c | 2 +- drivers/staging/lustre/lustre/llite/vvp_object.c | 2 +- fs/btrfs/inode.c | 2 +- fs/ceph/mds_client.c | 2 +- fs/cifs/inode.c | 2 +- fs/ext4/ialloc.c | 4 ++-- fs/fs-writeback.c | 2 +- fs/hpfs/inode.c | 2 +- fs/inode.c | 11 ++++++----- fs/locks.c | 2 +- fs/nfs/inode.c | 4 ++-- fs/notify/inode_mark.c | 2 +- fs/orangefs/namei.c | 4 ++-- fs/reiserfs/stree.c | 2 +- fs/ubifs/super.c | 2 +- fs/xfs/xfs_trace.h | 2 +- include/linux/fs.h | 5 +++++ include/trace/events/filelock.h | 2 +- 18 files changed, 30 insertions(+), 24 deletions(-) --- a/arch/powerpc/platforms/cell/spufs/file.c +++ b/arch/powerpc/platforms/cell/spufs/file.c @@ -1492,7 +1492,7 @@ static int spufs_mfc_open(struct inode * if (ctx->owner != current->mm) return -EINVAL; - if (atomic_read(&inode->i_count) != 1) + if (i_count(inode) != 1) /* XXX */ return -EBUSY; mutex_lock(&ctx->mapping_lock); --- a/drivers/staging/lustre/lustre/llite/vvp_object.c +++ b/drivers/staging/lustre/lustre/llite/vvp_object.c @@ -72,7 +72,7 @@ static int vvp_object_print(const struct lli = ll_i2info(inode); (*p)(env, cookie, "%lu/%u %o %u %d %p "DFID, inode->i_ino, inode->i_generation, inode->i_mode, - inode->i_nlink, atomic_read(&inode->i_count), + inode->i_nlink, i_count(inode), lli->lli_clob, PFID(&lli->lli_fid)); } return 0; --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -5616,7 +5616,7 @@ void btrfs_invalidate_inodes(struct btrf inode = igrab(&entry->vfs_inode); if (inode) { spin_unlock(&root->inode_lock); - if (atomic_read(&inode->i_count) > 1) + if (i_count(inode) > 1) d_prune_aliases(inode); /* * btrfs_drop_inode will have it removed from --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -1448,7 +1448,7 @@ static int trim_caps_cb(struct inode *in spin_unlock(&ci->i_ceph_lock); d_prune_aliases(inode); dout("trim_caps_cb %p cap %p pruned, count now %d\n", - inode, cap, atomic_read(&inode->i_count)); + inode, cap, i_count(inode)); return 0; } --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -1950,7 +1950,7 @@ int cifs_revalidate_dentry_attr(struct d } cifs_dbg(FYI, "Update attributes: %s inode 0x%p count %d dentry: 0x%p d_time %ld jiffies %ld\n", - full_path, inode, inode->i_count.counter, + full_path, inode, i_count(inode), dentry, cifs_get_time(dentry), jiffies); if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext) --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c @@ -270,10 +270,10 @@ void ext4_free_inode(handle_t *handle, s "nonexistent device\n", __func__, __LINE__); return; } - if (atomic_read(&inode->i_count) > 1) { + if (i_count(inode)) { ext4_msg(sb, KERN_ERR, "%s:%d: inode #%lu: count=%d", __func__, __LINE__, inode->i_ino, - atomic_read(&inode->i_count)); + i_count(inode)); return; } if (inode->i_nlink) { --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -1384,7 +1384,7 @@ static int writeback_single_inode(struct int ret = 0; spin_lock(&inode->i_lock); - if (!atomic_read(&inode->i_count)) + if (!i_count(inode)) WARN_ON(!(inode->i_state & (I_WILL_FREE|I_FREEING))); else WARN_ON(inode->i_state & I_WILL_FREE); --- a/fs/hpfs/inode.c +++ b/fs/hpfs/inode.c @@ -183,7 +183,7 @@ void hpfs_write_inode(struct inode *i) struct hpfs_inode_info *hpfs_inode = hpfs_i(i); struct inode *parent; if (i->i_ino == hpfs_sb(i->i_sb)->sb_root) return; - if (hpfs_inode->i_rddir_off && !atomic_read(&i->i_count)) { + if (hpfs_inode->i_rddir_off && !i_count(i)) { /* XXX */ if (*hpfs_inode->i_rddir_off) pr_err("write_inode: some position still there\n"); kfree(hpfs_inode->i_rddir_off); --- a/fs/inode.c +++ b/fs/inode.c @@ -411,9 +411,10 @@ static void inode_lru_list_add(struct in void inode_add_lru(struct inode *inode) { lockdep_assert_held(&inode->i_lock); + if (!(inode->i_state & (I_DIRTY_ALL | I_SYNC | I_FREEING | I_WILL_FREE)) && - !atomic_read(&inode->i_count) && inode->i_sb->s_flags & MS_ACTIVE) + !i_count(inode) && inode->i_sb->s_flags & MS_ACTIVE) inode_lru_list_add(inode); } @@ -605,7 +606,7 @@ void evict_inodes(struct super_block *sb spin_lock(&sb->s_inode_list_lock); list_for_each_entry_safe(inode, next, &sb->s_inodes, i_sb_list) { spin_lock(&inode->i_lock); - if (atomic_read(&inode->i_count)) { + if (i_count(inode)) { spin_unlock(&inode->i_lock); continue; } @@ -665,7 +666,7 @@ int invalidate_inodes(struct super_block busy = 1; continue; } - if (atomic_read(&inode->i_count)) { + if (i_count(inode)) { spin_unlock(&inode->i_lock); busy = 1; continue; @@ -713,9 +714,9 @@ static enum lru_status inode_lru_isolate /* * Referenced or dirty inodes are still in use. Give them another pass - * through the LRU as we canot reclaim them now. + * through the LRU as we cannot reclaim them now. */ - if (atomic_read(&inode->i_count) || + if (i_count(inode) || (inode->i_state & ~I_REFERENCED)) { list_lru_isolate(lru, &inode->i_lru); spin_unlock(&inode->i_lock); --- a/fs/locks.c +++ b/fs/locks.c @@ -1651,7 +1651,7 @@ check_conflicting_open(const struct dent return -EAGAIN; if ((arg == F_WRLCK) && ((d_count(dentry) > 1) || - (atomic_read(&inode->i_count) > 1))) + (i_count(inode) > 1))) ret = -EAGAIN; return ret; --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -531,7 +531,7 @@ nfs_fhget(struct super_block *sb, struct inode->i_sb->s_id, (unsigned long long)NFS_FILEID(inode), nfs_display_fhandle_hash(fh), - atomic_read(&inode->i_count)); + i_count(inode)); out: return inode; @@ -1696,7 +1696,7 @@ static int nfs_update_inode(struct inode dfprintk(VFS, "NFS: %s(%s/%lu fh_crc=0x%08x ct=%d info=0x%x)\n", __func__, inode->i_sb->s_id, inode->i_ino, nfs_display_fhandle_hash(NFS_FH(inode)), - atomic_read(&inode->i_count), fattr->valid); + i_count(inode), fattr->valid); if (!nfs_fileid_valid(nfsi, fattr)) { printk(KERN_ERR "NFS: server %s error: fileid changed\n" --- a/fs/notify/inode_mark.c +++ b/fs/notify/inode_mark.c @@ -171,7 +171,7 @@ void fsnotify_unmount_inodes(struct supe * evict all inodes with zero i_count from icache which is * unnecessarily violent and may in fact be illegal to do. */ - if (!atomic_read(&inode->i_count)) { + if (!i_count(inode)) { spin_unlock(&inode->i_lock); continue; } --- a/fs/orangefs/namei.c +++ b/fs/orangefs/namei.c @@ -202,14 +202,14 @@ static struct dentry *orangefs_lookup(st __func__, __LINE__, inode->i_ino, - (int)atomic_read(&inode->i_count)); + (int)i_count(inode)); /* update dentry/inode pair into dcache */ res = d_splice_alias(inode, dentry); gossip_debug(GOSSIP_NAME_DEBUG, "Lookup success (inode ct = %d)\n", - (int)atomic_read(&inode->i_count)); + (int)i_count(inode)); out: op_release(new_op); return res; --- a/fs/reiserfs/stree.c +++ b/fs/reiserfs/stree.c @@ -1555,7 +1555,7 @@ static int maybe_indirect_to_direct(stru * reading in the last block. The user will hit problems trying to * read the file, but for now we just skip the indirect2direct */ - if (atomic_read(&inode->i_count) > 1 || + if (i_count(inode) > 1 || /* XXX */ !tail_has_to_be_packed(inode) || !page || (REISERFS_I(inode)->i_flags & i_nopack_mask)) { /* leave tail in an unformatted node */ --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c @@ -349,7 +349,7 @@ static void ubifs_evict_inode(struct ino goto out; dbg_gen("inode %lu, mode %#x", inode->i_ino, (int)inode->i_mode); - ubifs_assert(!atomic_read(&inode->i_count)); + ubifs_assert(!i_count(inode)); truncate_inode_pages_final(&inode->i_data); --- a/fs/xfs/xfs_trace.h +++ b/fs/xfs/xfs_trace.h @@ -704,7 +704,7 @@ DECLARE_EVENT_CLASS(xfs_iref_class, TP_fast_assign( __entry->dev = VFS_I(ip)->i_sb->s_dev; __entry->ino = ip->i_ino; - __entry->count = atomic_read(&VFS_I(ip)->i_count); + __entry->count = i_count(VFS_I(ip)); __entry->pincount = atomic_read(&ip->i_pincount); __entry->caller_ip = caller_ip; ), --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2711,6 +2711,11 @@ static inline void lockdep_annotate_inod extern void unlock_new_inode(struct inode *); extern unsigned int get_next_ino(void); +static inline int i_count(struct inode *inode) +{ + return atomic_read(&inode->i_count); +} + extern void __iget(struct inode * inode); extern void iget_failed(struct inode *); extern void clear_inode(struct inode *); --- a/include/trace/events/filelock.h +++ b/include/trace/events/filelock.h @@ -185,7 +185,7 @@ TRACE_EVENT(generic_add_lease, __entry->i_ino = inode->i_ino; __entry->wcount = atomic_read(&inode->i_writecount); __entry->dcount = d_count(fl->fl_file->f_path.dentry); - __entry->icount = atomic_read(&inode->i_count); + __entry->icount = i_count(inode); __entry->fl_owner = fl ? fl->fl_owner : NULL; __entry->fl_flags = fl ? fl->fl_flags : 0; __entry->fl_type = fl ? fl->fl_type : 0;