linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/13] read-only remount race fix v7
@ 2011-10-12 14:48 Miklos Szeredi
  2011-10-12 14:48 ` [PATCH 01/13] vfs: ignore error on forced remount Miklos Szeredi
                   ` (14 more replies)
  0 siblings, 15 replies; 27+ messages in thread
From: Miklos Szeredi @ 2011-10-12 14:48 UTC (permalink / raw)
  To: viro; +Cc: linux-fsdevel, linux-kernel, jack, hch, akpm, toshi.okajima,
	mszeredi

Here's an update of the read-only remount race fixes.

It should now fix the races after unlink.  I haven't been able to
trigger the bad behavior with the test scripts provided by Toshiyuki
Okajima.

Toshiyuki-san, could you please test these patches too?

Thanks,
Miklos
---

Miklos Szeredi (13):
      vfs: ignore error on forced remount
      vfs: keep list of mounts for each superblock
      vfs: protect remounting superblock read-only
      vfs: fs_may_remount_ro: turn unnecessary check into a WARN_ON
      hypfs: remove unnecessary nlink setting
      jfs: remove unnecessary nlink setting
      ocfs2: remove unnecessary nlink setting
      logfs: remove unnecessary nlink setting
      filesystems: add missing nlink wrappers
      filesystems: add set_nlink()
      vfs: protect i_nlink
      vfs: count unlinked inodes
      vfs: prevent remount read-only if pending removes

---
 arch/s390/hypfs/inode.c          |    6 +--
 drivers/mtd/mtdchar.c            |    2 +-
 drivers/staging/pohmelfs/inode.c |    2 +-
 fs/9p/vfs_inode.c                |    4 +-
 fs/9p/vfs_inode_dotl.c           |    4 +-
 fs/adfs/inode.c                  |    2 +-
 fs/affs/amigaffs.c               |    4 +-
 fs/affs/inode.c                  |    8 ++--
 fs/affs/namei.c                  |    6 +-
 fs/afs/fsclient.c                |    2 +-
 fs/afs/inode.c                   |    4 +-
 fs/autofs4/inode.c               |    2 +-
 fs/befs/linuxvfs.c               |    2 +-
 fs/bfs/dir.c                     |    2 +-
 fs/bfs/inode.c                   |    2 +-
 fs/binfmt_misc.c                 |    2 +-
 fs/btrfs/delayed-inode.c         |    2 +-
 fs/btrfs/disk-io.c               |    2 +-
 fs/btrfs/inode.c                 |    4 +-
 fs/btrfs/tree-log.c              |    2 +-
 fs/ceph/caps.c                   |    2 +-
 fs/ceph/inode.c                  |    2 +-
 fs/cifs/inode.c                  |    6 +-
 fs/cifs/link.c                   |    2 +-
 fs/coda/coda_linux.c             |    2 +-
 fs/coda/dir.c                    |    2 +-
 fs/devpts/inode.c                |    4 +-
 fs/ecryptfs/inode.c              |   12 +++---
 fs/efs/inode.c                   |    2 +-
 fs/exofs/inode.c                 |    2 +-
 fs/ext2/ialloc.c                 |    2 +-
 fs/ext2/inode.c                  |    2 +-
 fs/ext3/ialloc.c                 |    2 +-
 fs/ext3/inode.c                  |    2 +-
 fs/ext3/namei.c                  |    6 +-
 fs/ext4/ialloc.c                 |    2 +-
 fs/ext4/inode.c                  |    2 +-
 fs/ext4/migrate.c                |    2 +-
 fs/ext4/namei.c                  |    8 ++--
 fs/fat/inode.c                   |    4 +-
 fs/fat/namei_msdos.c             |    2 +-
 fs/fat/namei_vfat.c              |    2 +-
 fs/file_table.c                  |   23 ----------
 fs/freevxfs/vxfs_inode.c         |    2 +-
 fs/fuse/control.c                |    2 +-
 fs/fuse/inode.c                  |    2 +-
 fs/gfs2/glops.c                  |    2 +-
 fs/hfs/dir.c                     |    4 +-
 fs/hfs/inode.c                   |    4 +-
 fs/hfsplus/dir.c                 |    4 +-
 fs/hfsplus/inode.c               |   10 ++--
 fs/hostfs/hostfs_kern.c          |    2 +-
 fs/hpfs/dir.c                    |    2 +-
 fs/hpfs/inode.c                  |   10 ++--
 fs/hpfs/namei.c                  |    8 ++--
 fs/hppfs/hppfs.c                 |    2 +-
 fs/hugetlbfs/inode.c             |    2 +-
 fs/inode.c                       |   83 +++++++++++++++++++++++++++++++++++++-
 fs/internal.h                    |    1 +
 fs/isofs/inode.c                 |    4 +-
 fs/isofs/rock.c                  |    4 +-
 fs/jffs2/dir.c                   |    6 +-
 fs/jffs2/fs.c                    |    6 +-
 fs/jfs/jfs_imap.c                |    6 +-
 fs/jfs/jfs_inode.c               |    2 +-
 fs/jfs/namei.c                   |   12 +++---
 fs/jfs/super.c                   |    1 -
 fs/libfs.c                       |    2 +-
 fs/logfs/dir.c                   |    8 ++--
 fs/logfs/inode.c                 |    3 +-
 fs/logfs/readwrite.c             |    2 +-
 fs/minix/inode.c                 |    4 +-
 fs/namespace.c                   |   57 +++++++++++++++++++++++++-
 fs/ncpfs/inode.c                 |    2 +-
 fs/nfs/inode.c                   |    6 +-
 fs/nilfs2/inode.c                |    4 +-
 fs/nilfs2/namei.c                |    2 +-
 fs/ntfs/inode.c                  |    8 ++--
 fs/ocfs2/dir.c                   |    4 +-
 fs/ocfs2/dlmglue.c               |    2 +-
 fs/ocfs2/inode.c                 |    4 +-
 fs/ocfs2/namei.c                 |   18 ++++-----
 fs/openpromfs/inode.c            |    4 +-
 fs/proc/base.c                   |   12 +++---
 fs/proc/generic.c                |    2 +-
 fs/proc/inode.c                  |    2 +-
 fs/proc/proc_sysctl.c            |    2 +-
 fs/qnx4/inode.c                  |    2 +-
 fs/reiserfs/inode.c              |   10 ++--
 fs/reiserfs/namei.c              |   16 ++++----
 fs/romfs/super.c                 |    2 +-
 fs/squashfs/inode.c              |   18 ++++----
 fs/stack.c                       |    2 +-
 fs/super.c                       |   27 ++++++++++--
 fs/sysfs/inode.c                 |    2 +-
 fs/sysv/inode.c                  |    2 +-
 fs/ubifs/super.c                 |    2 +-
 fs/ubifs/xattr.c                 |    4 +-
 fs/udf/inode.c                   |    8 ++-
 fs/udf/namei.c                   |   15 +++----
 fs/ufs/ialloc.c                  |    2 +-
 fs/ufs/inode.c                   |    4 +-
 fs/xfs/xfs_iops.c                |    2 +-
 include/linux/fs.h               |   66 ++++++++++--------------------
 include/linux/mount.h            |    1 +
 mm/shmem.c                       |    2 +-
 106 files changed, 389 insertions(+), 286 deletions(-)


^ permalink raw reply	[flat|nested] 27+ messages in thread

* [PATCH 01/13] vfs: ignore error on forced remount
  2011-10-12 14:48 [PATCH 0/13] read-only remount race fix v7 Miklos Szeredi
@ 2011-10-12 14:48 ` Miklos Szeredi
  2011-10-12 14:48 ` [PATCH 02/13] vfs: keep list of mounts for each superblock Miklos Szeredi
                   ` (13 subsequent siblings)
  14 siblings, 0 replies; 27+ messages in thread
From: Miklos Szeredi @ 2011-10-12 14:48 UTC (permalink / raw)
  To: viro; +Cc: linux-fsdevel, linux-kernel, jack, hch, akpm, toshi.okajima,
	mszeredi

From: Miklos Szeredi <mszeredi@suse.cz>

On emergency remount we want to force MS_RDONLY on the super block
even if ->remount_fs() failed for some reason.

Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
---
 fs/super.c |    9 +++++++--
 1 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/fs/super.c b/fs/super.c
index 3f56a26..363fde2 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -727,8 +727,13 @@ int do_remount_sb(struct super_block *sb, int flags, void *data, int force)
 
 	if (sb->s_op->remount_fs) {
 		retval = sb->s_op->remount_fs(sb, &flags, data);
-		if (retval)
-			return retval;
+		if (retval) {
+			if(!force)
+				return retval;
+			/* If forced remount, go ahead despite any errors */
+			WARN(1, "forced remount of a %s fs returned %i\n",
+			     sb->s_type->name, retval);
+		}
 	}
 	sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (flags & MS_RMT_MASK);
 
-- 
1.7.3.4

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 02/13] vfs: keep list of mounts for each superblock
  2011-10-12 14:48 [PATCH 0/13] read-only remount race fix v7 Miklos Szeredi
  2011-10-12 14:48 ` [PATCH 01/13] vfs: ignore error on forced remount Miklos Szeredi
@ 2011-10-12 14:48 ` Miklos Szeredi
  2011-10-12 14:48 ` [PATCH 03/13] vfs: protect remounting superblock read-only Miklos Szeredi
                   ` (12 subsequent siblings)
  14 siblings, 0 replies; 27+ messages in thread
From: Miklos Szeredi @ 2011-10-12 14:48 UTC (permalink / raw)
  To: viro; +Cc: linux-fsdevel, linux-kernel, jack, hch, akpm, toshi.okajima,
	mszeredi

From: Miklos Szeredi <mszeredi@suse.cz>

Keep track of vfsmounts belonging to a superblock.  List is protected
by vfsmount_lock.

Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
---
 fs/namespace.c        |   10 ++++++++++
 fs/super.c            |    2 ++
 include/linux/fs.h    |    1 +
 include/linux/mount.h |    1 +
 4 files changed, 14 insertions(+), 0 deletions(-)

diff --git a/fs/namespace.c b/fs/namespace.c
index b4febb2..ccbec4e 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -696,6 +696,11 @@ vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void
 	mnt->mnt_sb = root->d_sb;
 	mnt->mnt_mountpoint = mnt->mnt_root;
 	mnt->mnt_parent = mnt;
+
+	br_write_lock(vfsmount_lock);
+	list_add_tail(&mnt->mnt_instance, &mnt->mnt_sb->s_mounts);
+	br_write_unlock(vfsmount_lock);
+
 	return mnt;
 }
 EXPORT_SYMBOL_GPL(vfs_kern_mount);
@@ -745,6 +750,10 @@ static struct vfsmount *clone_mnt(struct vfsmount *old, struct dentry *root,
 			if (!list_empty(&old->mnt_expire))
 				list_add(&mnt->mnt_expire, &old->mnt_expire);
 		}
+
+		br_write_lock(vfsmount_lock);
+		list_add_tail(&mnt->mnt_instance, &mnt->mnt_sb->s_mounts);
+		br_write_unlock(vfsmount_lock);
 	}
 	return mnt;
 
@@ -805,6 +814,7 @@ put_again:
 		acct_auto_close_mnt(mnt);
 		goto put_again;
 	}
+	list_del(&mnt->mnt_instance);
 	br_write_unlock(vfsmount_lock);
 	mntfree(mnt);
 }
diff --git a/fs/super.c b/fs/super.c
index 363fde2..e8aad34 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -142,6 +142,7 @@ static struct super_block *alloc_super(struct file_system_type *type)
 		INIT_LIST_HEAD(&s->s_dentry_lru);
 		INIT_LIST_HEAD(&s->s_inode_lru);
 		spin_lock_init(&s->s_inode_lru_lock);
+		INIT_LIST_HEAD(&s->s_mounts);
 		init_rwsem(&s->s_umount);
 		mutex_init(&s->s_lock);
 		lockdep_set_class(&s->s_umount, &type->s_umount_key);
@@ -200,6 +201,7 @@ static inline void destroy_super(struct super_block *s)
 	free_percpu(s->s_files);
 #endif
 	security_sb_free(s);
+	WARN_ON(!list_empty(&s->s_mounts));
 	kfree(s->s_subtype);
 	kfree(s->s_options);
 	kfree(s);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 277f497..84e5df6 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1408,6 +1408,7 @@ struct super_block {
 #else
 	struct list_head	s_files;
 #endif
+	struct list_head	s_mounts;	/* list of mounts */
 	/* s_dentry_lru, s_nr_dentry_unused protected by dcache.c lru locks */
 	struct list_head	s_dentry_lru;	/* unused dentry lru */
 	int			s_nr_dentry_unused;	/* # of dentry on lru */
diff --git a/include/linux/mount.h b/include/linux/mount.h
index 33fe53d..f88c726 100644
--- a/include/linux/mount.h
+++ b/include/linux/mount.h
@@ -67,6 +67,7 @@ struct vfsmount {
 #endif
 	struct list_head mnt_mounts;	/* list of children, anchored here */
 	struct list_head mnt_child;	/* and going through their mnt_child */
+	struct list_head mnt_instance;	/* mount instance on sb->s_mounts */
 	int mnt_flags;
 	/* 4 bytes hole on 64bits arches without fsnotify */
 #ifdef CONFIG_FSNOTIFY
-- 
1.7.3.4

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 03/13] vfs: protect remounting superblock read-only
  2011-10-12 14:48 [PATCH 0/13] read-only remount race fix v7 Miklos Szeredi
  2011-10-12 14:48 ` [PATCH 01/13] vfs: ignore error on forced remount Miklos Szeredi
  2011-10-12 14:48 ` [PATCH 02/13] vfs: keep list of mounts for each superblock Miklos Szeredi
@ 2011-10-12 14:48 ` Miklos Szeredi
  2011-10-12 14:48 ` [PATCH 04/13] vfs: fs_may_remount_ro: turn unnecessary check into a WARN_ON Miklos Szeredi
                   ` (11 subsequent siblings)
  14 siblings, 0 replies; 27+ messages in thread
From: Miklos Szeredi @ 2011-10-12 14:48 UTC (permalink / raw)
  To: viro; +Cc: linux-fsdevel, linux-kernel, jack, hch, akpm, toshi.okajima,
	mszeredi

From: Miklos Szeredi <mszeredi@suse.cz>

Currently remouting superblock read-only is racy in a major way.

With the per mount read-only infrastructure it is now possible to
prevent most races, which this patch attempts.

Before starting the remount read-only, iterate through all mounts
belonging to the superblock and if none of them have any pending
writes, set sb->s_readonly_remount.  This indicates that remount is in
progress and no further write requests are allowed.  If the remount
succeeds set MS_RDONLY and reset s_readonly_remount.

If the remounting is unsuccessful just reset s_readonly_remount.
This can result in transient EROFS errors, despite the fact the
remount failed.  Unfortunately hodling off writes is difficult as
remount itself may touch the filesystem (e.g. through load_nls())
which would deadlock.

Small races still remain because delayed writes due to nlink going to
zero but inode still having a reference are not dealt with by this
patch.

Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
---
 fs/internal.h      |    1 +
 fs/namespace.c     |   40 +++++++++++++++++++++++++++++++++++++++-
 fs/super.c         |   22 ++++++++++++++++++----
 include/linux/fs.h |    3 +++
 4 files changed, 61 insertions(+), 5 deletions(-)

diff --git a/fs/internal.h b/fs/internal.h
index fe327c2..f925271 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -74,6 +74,7 @@ extern int finish_automount(struct vfsmount *, struct path *);
 
 extern void mnt_make_longterm(struct vfsmount *);
 extern void mnt_make_shortterm(struct vfsmount *);
+extern int sb_prepare_remount_readonly(struct super_block *);
 
 extern void __init mnt_init(void);
 
diff --git a/fs/namespace.c b/fs/namespace.c
index ccbec4e..85838f5 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -311,6 +311,15 @@ static unsigned int mnt_get_writers(struct vfsmount *mnt)
 #endif
 }
 
+static int mnt_is_readonly(struct vfsmount *mnt)
+{
+	if (mnt->mnt_sb->s_readonly_remount)
+		return 1;
+	/* Order wrt setting s_flags/s_readonly_remount in do_remount() */
+	smp_rmb();
+	return __mnt_is_readonly(mnt);
+}
+
 /*
  * Most r/o checks on a fs are for operations that take
  * discrete amounts of time, like a write() or unlink().
@@ -349,7 +358,7 @@ int mnt_want_write(struct vfsmount *mnt)
 	 * MNT_WRITE_HOLD is cleared.
 	 */
 	smp_rmb();
-	if (__mnt_is_readonly(mnt)) {
+	if (mnt_is_readonly(mnt)) {
 		mnt_dec_writers(mnt);
 		ret = -EROFS;
 		goto out;
@@ -466,6 +475,35 @@ static void __mnt_unmake_readonly(struct vfsmount *mnt)
 	br_write_unlock(vfsmount_lock);
 }
 
+int sb_prepare_remount_readonly(struct super_block *sb)
+{
+	struct vfsmount *mnt;
+	int err = 0;
+
+	br_write_lock(vfsmount_lock);
+	list_for_each_entry(mnt, &sb->s_mounts, mnt_instance) {
+		if (!(mnt->mnt_flags & MNT_READONLY)) {
+			mnt->mnt_flags |= MNT_WRITE_HOLD;
+			smp_mb();
+			if (mnt_get_writers(mnt) > 0) {
+				err = -EBUSY;
+				break;
+			}
+		}
+	}
+	if (!err) {
+		sb->s_readonly_remount = 1;
+		smp_wmb();
+	}
+	list_for_each_entry(mnt, &sb->s_mounts, mnt_instance) {
+		if (mnt->mnt_flags & MNT_WRITE_HOLD)
+			mnt->mnt_flags &= ~MNT_WRITE_HOLD;
+	}
+	br_write_unlock(vfsmount_lock);
+
+	return err;
+}
+
 static void free_vfsmnt(struct vfsmount *mnt)
 {
 	kfree(mnt->mnt_devname);
diff --git a/fs/super.c b/fs/super.c
index e8aad34..94c8ace 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -721,23 +721,33 @@ int do_remount_sb(struct super_block *sb, int flags, void *data, int force)
 	/* If we are remounting RDONLY and current sb is read/write,
 	   make sure there are no rw files opened */
 	if (remount_ro) {
-		if (force)
+		if (force) {
 			mark_files_ro(sb);
-		else if (!fs_may_remount_ro(sb))
-			return -EBUSY;
+		} else {
+			retval = sb_prepare_remount_readonly(sb);
+			if (retval)
+				return retval;
+
+			retval = -EBUSY;
+			if (!fs_may_remount_ro(sb))
+				goto cancel_readonly;
+		}
 	}
 
 	if (sb->s_op->remount_fs) {
 		retval = sb->s_op->remount_fs(sb, &flags, data);
 		if (retval) {
 			if(!force)
-				return retval;
+				goto cancel_readonly;
 			/* If forced remount, go ahead despite any errors */
 			WARN(1, "forced remount of a %s fs returned %i\n",
 			     sb->s_type->name, retval);
 		}
 	}
 	sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (flags & MS_RMT_MASK);
+	/* Needs to be ordered wrt mnt_is_readonly() */
+	smp_wmb();
+	sb->s_readonly_remount = 0;
 
 	/*
 	 * Some filesystems modify their metadata via some other path than the
@@ -750,6 +760,10 @@ int do_remount_sb(struct super_block *sb, int flags, void *data, int force)
 	if (remount_ro && sb->s_bdev)
 		invalidate_bdev(sb->s_bdev);
 	return 0;
+
+cancel_readonly:
+	sb->s_readonly_remount = 0;
+	return retval;
 }
 
 static void do_emergency_remount(struct work_struct *work)
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 84e5df6..0979638 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1462,6 +1462,9 @@ struct super_block {
 	int cleancache_poolid;
 
 	struct shrinker s_shrink;	/* per-sb shrinker handle */
+
+	/* Being remounted read-only */
+	int s_readonly_remount;
 };
 
 /* superblock cache pruning functions */
-- 
1.7.3.4

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 04/13] vfs: fs_may_remount_ro: turn unnecessary check into a WARN_ON
  2011-10-12 14:48 [PATCH 0/13] read-only remount race fix v7 Miklos Szeredi
                   ` (2 preceding siblings ...)
  2011-10-12 14:48 ` [PATCH 03/13] vfs: protect remounting superblock read-only Miklos Szeredi
@ 2011-10-12 14:48 ` Miklos Szeredi
  2011-10-12 14:48 ` [PATCH 05/13] hypfs: remove unnecessary nlink setting Miklos Szeredi
                   ` (10 subsequent siblings)
  14 siblings, 0 replies; 27+ messages in thread
From: Miklos Szeredi @ 2011-10-12 14:48 UTC (permalink / raw)
  To: viro; +Cc: linux-fsdevel, linux-kernel, jack, hch, akpm, toshi.okajima,
	mszeredi

From: Miklos Szeredi <mszeredi@suse.cz>

Now a successful sb_prepare_remount_readonly() should ensure that no
writable files remain for this superblock.  So turn this check into a
WARN_ON.

Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
---
 fs/file_table.c |    7 +++++--
 1 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/fs/file_table.c b/fs/file_table.c
index c322794..dc9f437 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -486,8 +486,11 @@ int fs_may_remount_ro(struct super_block *sb)
 		if (inode->i_nlink == 0)
 			goto too_bad;
 
-		/* Writeable file? */
-		if (S_ISREG(inode->i_mode) && (file->f_mode & FMODE_WRITE))
+		/*
+		 * Writable file?
+		 * Should be caught by sb_prepare_remount_readonly().
+		 */
+		if (WARN_ON(S_ISREG(inode->i_mode) && (file->f_mode & FMODE_WRITE)))
 			goto too_bad;
 	} while_file_list_for_each_entry;
 	lg_global_unlock(files_lglock);
-- 
1.7.3.4

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 05/13] hypfs: remove unnecessary nlink setting
  2011-10-12 14:48 [PATCH 0/13] read-only remount race fix v7 Miklos Szeredi
                   ` (3 preceding siblings ...)
  2011-10-12 14:48 ` [PATCH 04/13] vfs: fs_may_remount_ro: turn unnecessary check into a WARN_ON Miklos Szeredi
@ 2011-10-12 14:48 ` Miklos Szeredi
  2011-10-12 14:48 ` [PATCH 06/13] jfs: " Miklos Szeredi
                   ` (9 subsequent siblings)
  14 siblings, 0 replies; 27+ messages in thread
From: Miklos Szeredi @ 2011-10-12 14:48 UTC (permalink / raw)
  To: viro
  Cc: linux-fsdevel, linux-kernel, jack, hch, akpm, toshi.okajima,
	mszeredi, Martin Schwidefsky

From: Miklos Szeredi <mszeredi@suse.cz>

alloc_inode() initializes i_nlink to 1.  Remove unnecessary
re-initialization.

Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
CC: Martin Schwidefsky <schwidefsky@de.ibm.com>
---
 arch/s390/hypfs/inode.c |    2 --
 1 files changed, 0 insertions(+), 2 deletions(-)

diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c
index 6fe874f..7ae0d0d 100644
--- a/arch/s390/hypfs/inode.c
+++ b/arch/s390/hypfs/inode.c
@@ -109,8 +109,6 @@ static struct inode *hypfs_make_inode(struct super_block *sb, int mode)
 		ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME;
 		if (mode & S_IFDIR)
 			ret->i_nlink = 2;
-		else
-			ret->i_nlink = 1;
 	}
 	return ret;
 }
-- 
1.7.3.4

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 06/13] jfs: remove unnecessary nlink setting
  2011-10-12 14:48 [PATCH 0/13] read-only remount race fix v7 Miklos Szeredi
                   ` (4 preceding siblings ...)
  2011-10-12 14:48 ` [PATCH 05/13] hypfs: remove unnecessary nlink setting Miklos Szeredi
@ 2011-10-12 14:48 ` Miklos Szeredi
  2011-10-12 15:26   ` Dave Kleikamp
  2011-10-12 14:49 ` [PATCH 07/13] ocfs2: " Miklos Szeredi
                   ` (8 subsequent siblings)
  14 siblings, 1 reply; 27+ messages in thread
From: Miklos Szeredi @ 2011-10-12 14:48 UTC (permalink / raw)
  To: viro
  Cc: linux-fsdevel, linux-kernel, jack, hch, akpm, toshi.okajima,
	mszeredi, Dave Kleikamp

From: Miklos Szeredi <mszeredi@suse.cz>

alloc_inode() initializes i_nlink to 1.  Remove unnecessary
re-initialization.

Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
CC: Dave Kleikamp <dave.kleikamp@oracle.com>
---
 fs/jfs/super.c |    1 -
 1 files changed, 0 insertions(+), 1 deletions(-)

diff --git a/fs/jfs/super.c b/fs/jfs/super.c
index 06c8a67..a44eff0 100644
--- a/fs/jfs/super.c
+++ b/fs/jfs/super.c
@@ -485,7 +485,6 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent)
 		goto out_unload;
 	}
 	inode->i_ino = 0;
-	inode->i_nlink = 1;
 	inode->i_size = sb->s_bdev->bd_inode->i_size;
 	inode->i_mapping->a_ops = &jfs_metapage_aops;
 	insert_inode_hash(inode);
-- 
1.7.3.4

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 07/13] ocfs2: remove unnecessary nlink setting
  2011-10-12 14:48 [PATCH 0/13] read-only remount race fix v7 Miklos Szeredi
                   ` (5 preceding siblings ...)
  2011-10-12 14:48 ` [PATCH 06/13] jfs: " Miklos Szeredi
@ 2011-10-12 14:49 ` Miklos Szeredi
  2011-10-12 14:49 ` [PATCH 08/13] logfs: " Miklos Szeredi
                   ` (7 subsequent siblings)
  14 siblings, 0 replies; 27+ messages in thread
From: Miklos Szeredi @ 2011-10-12 14:49 UTC (permalink / raw)
  To: viro
  Cc: linux-fsdevel, linux-kernel, jack, hch, akpm, toshi.okajima,
	mszeredi, Joel Becker, Mark Fasheh

From: Miklos Szeredi <mszeredi@suse.cz>

alloc_inode() initializes i_nlink to 1.  Remove unnecessary
re-initialization.

Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
CC: Joel Becker <jlbec@evilplan.org>
CC: Mark Fasheh <mfasheh@suse.com>
---
 fs/ocfs2/namei.c |    2 --
 1 files changed, 0 insertions(+), 2 deletions(-)

diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c
index 53aa41e..0181f63 100644
--- a/fs/ocfs2/namei.c
+++ b/fs/ocfs2/namei.c
@@ -200,8 +200,6 @@ static struct inode *ocfs2_get_init_inode(struct inode *dir, int mode)
 	 * callers. */
 	if (S_ISDIR(mode))
 		inode->i_nlink = 2;
-	else
-		inode->i_nlink = 1;
 	inode_init_owner(inode, dir, mode);
 	dquot_initialize(inode);
 	return inode;
-- 
1.7.3.4

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 08/13] logfs: remove unnecessary nlink setting
  2011-10-12 14:48 [PATCH 0/13] read-only remount race fix v7 Miklos Szeredi
                   ` (6 preceding siblings ...)
  2011-10-12 14:49 ` [PATCH 07/13] ocfs2: " Miklos Szeredi
@ 2011-10-12 14:49 ` Miklos Szeredi
  2011-10-12 14:49 ` [PATCH 09/13] filesystems: add missing nlink wrappers Miklos Szeredi
                   ` (6 subsequent siblings)
  14 siblings, 0 replies; 27+ messages in thread
From: Miklos Szeredi @ 2011-10-12 14:49 UTC (permalink / raw)
  To: viro
  Cc: linux-fsdevel, linux-kernel, jack, hch, akpm, toshi.okajima,
	mszeredi, Joern Engel, Prasad Joshi

From: Miklos Szeredi <mszeredi@suse.cz>

alloc_inode() initializes i_nlink to 1.  Remove unnecessary
re-initialization.

Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
CC: Joern Engel <joern@logfs.org>
CC: Prasad Joshi <prasadjoshi.linux@gmail.com>
---
 fs/logfs/inode.c |    1 -
 1 files changed, 0 insertions(+), 1 deletions(-)

diff --git a/fs/logfs/inode.c b/fs/logfs/inode.c
index edfea7a..9abb048 100644
--- a/fs/logfs/inode.c
+++ b/fs/logfs/inode.c
@@ -199,7 +199,6 @@ static void logfs_init_inode(struct super_block *sb, struct inode *inode)
 	inode->i_blocks	= 0;
 	inode->i_ctime	= CURRENT_TIME;
 	inode->i_mtime	= CURRENT_TIME;
-	inode->i_nlink	= 1;
 	li->li_refcount = 1;
 	INIT_LIST_HEAD(&li->li_freeing_list);
 
-- 
1.7.3.4

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 09/13] filesystems: add missing nlink wrappers
  2011-10-12 14:48 [PATCH 0/13] read-only remount race fix v7 Miklos Szeredi
                   ` (7 preceding siblings ...)
  2011-10-12 14:49 ` [PATCH 08/13] logfs: " Miklos Szeredi
@ 2011-10-12 14:49 ` Miklos Szeredi
  2011-10-12 14:49 ` [PATCH 10/13] filesystems: add set_nlink() Miklos Szeredi
                   ` (5 subsequent siblings)
  14 siblings, 0 replies; 27+ messages in thread
From: Miklos Szeredi @ 2011-10-12 14:49 UTC (permalink / raw)
  To: viro; +Cc: linux-fsdevel, linux-kernel, jack, hch, akpm, toshi.okajima,
	mszeredi

From: Miklos Szeredi <mszeredi@suse.cz>

Replace direct i_nlink updates with the respective updater function
(inc_nlink, drop_nlink, clear_nlink, inode_dec_link_count).

Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
---
 arch/s390/hypfs/inode.c |    2 +-
 drivers/mtd/mtdchar.c   |    2 +-
 fs/affs/amigaffs.c      |    2 +-
 fs/affs/namei.c         |    6 +++---
 fs/binfmt_misc.c        |    2 +-
 fs/cifs/link.c          |    2 +-
 fs/coda/dir.c           |    2 +-
 fs/devpts/inode.c       |    2 +-
 fs/ext2/ialloc.c        |    2 +-
 fs/ext3/ialloc.c        |    2 +-
 fs/ext3/namei.c         |    2 +-
 fs/ext4/ialloc.c        |    2 +-
 fs/ext4/migrate.c       |    2 +-
 fs/ext4/namei.c         |    2 +-
 fs/hfs/dir.c            |    4 ++--
 fs/hfsplus/dir.c        |    4 ++--
 fs/hpfs/inode.c         |    2 +-
 fs/hugetlbfs/inode.c    |    2 +-
 fs/jfs/jfs_inode.c      |    2 +-
 fs/jfs/namei.c          |   10 +++++-----
 fs/logfs/dir.c          |    8 ++++----
 fs/logfs/inode.c        |    2 +-
 fs/nfs/inode.c          |    2 +-
 fs/nilfs2/inode.c       |    2 +-
 fs/ocfs2/namei.c        |    8 ++++----
 fs/proc/proc_sysctl.c   |    2 +-
 fs/reiserfs/inode.c     |    4 ++--
 fs/reiserfs/namei.c     |   12 ++++++------
 fs/ubifs/xattr.c        |    2 +-
 fs/udf/namei.c          |   11 ++++-------
 fs/ufs/ialloc.c         |    2 +-
 mm/shmem.c              |    2 +-
 32 files changed, 55 insertions(+), 58 deletions(-)

diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c
index 7ae0d0d..baa82f8 100644
--- a/arch/s390/hypfs/inode.c
+++ b/arch/s390/hypfs/inode.c
@@ -359,7 +359,7 @@ static struct dentry *hypfs_create_file(struct super_block *sb,
 	} else if (mode & S_IFDIR) {
 		inode->i_op = &simple_dir_inode_operations;
 		inode->i_fop = &simple_dir_operations;
-		parent->d_inode->i_nlink++;
+		inc_nlink(parent->d_inode);
 	} else
 		BUG();
 	inode->i_private = data;
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index f1af222..61086ea 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -1144,7 +1144,7 @@ static void mtdchar_notify_remove(struct mtd_info *mtd)
 
 	if (mtd_ino) {
 		/* Destroy the inode if it exists */
-		mtd_ino->i_nlink = 0;
+		clear_nlink(mtd_ino);
 		iput(mtd_ino);
 	}
 }
diff --git a/fs/affs/amigaffs.c b/fs/affs/amigaffs.c
index 3a4557e..8f12723 100644
--- a/fs/affs/amigaffs.c
+++ b/fs/affs/amigaffs.c
@@ -316,7 +316,7 @@ affs_remove_header(struct dentry *dentry)
 	if (inode->i_nlink > 1)
 		retval = affs_remove_link(dentry);
 	else
-		inode->i_nlink = 0;
+		clear_nlink(inode);
 	affs_unlock_link(inode);
 	inode->i_ctime = CURRENT_TIME_SEC;
 	mark_inode_dirty(inode);
diff --git a/fs/affs/namei.c b/fs/affs/namei.c
index e3e9efc..780a11d 100644
--- a/fs/affs/namei.c
+++ b/fs/affs/namei.c
@@ -277,7 +277,7 @@ affs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata
 	inode->i_mapping->a_ops = (AFFS_SB(sb)->s_flags & SF_OFS) ? &affs_aops_ofs : &affs_aops;
 	error = affs_add_entry(dir, inode, dentry, ST_FILE);
 	if (error) {
-		inode->i_nlink = 0;
+		clear_nlink(inode);
 		iput(inode);
 		return error;
 	}
@@ -305,7 +305,7 @@ affs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 
 	error = affs_add_entry(dir, inode, dentry, ST_USERDIR);
 	if (error) {
-		inode->i_nlink = 0;
+		clear_nlink(inode);
 		mark_inode_dirty(inode);
 		iput(inode);
 		return error;
@@ -392,7 +392,7 @@ affs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
 	return 0;
 
 err:
-	inode->i_nlink = 0;
+	clear_nlink(inode);
 	mark_inode_dirty(inode);
 	iput(inode);
 	return error;
diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c
index ba1a1ae..1e9edbd 100644
--- a/fs/binfmt_misc.c
+++ b/fs/binfmt_misc.c
@@ -521,7 +521,7 @@ static void kill_node(Node *e)
 	write_unlock(&entries_lock);
 
 	if (dentry) {
-		dentry->d_inode->i_nlink--;
+		drop_nlink(dentry->d_inode);
 		d_drop(dentry);
 		dput(dentry);
 		simple_release_fs(&bm_mnt, &entry_count);
diff --git a/fs/cifs/link.c b/fs/cifs/link.c
index db3f18c..d02e2ff 100644
--- a/fs/cifs/link.c
+++ b/fs/cifs/link.c
@@ -424,7 +424,7 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode,
 	if (old_file->d_inode) {
 		cifsInode = CIFS_I(old_file->d_inode);
 		if (rc == 0) {
-			old_file->d_inode->i_nlink++;
+			inc_nlink(old_file->d_inode);
 /* BB should we make this contingent on superblock flag NOATIME? */
 /*			old_file->d_inode->i_ctime = CURRENT_TIME;*/
 			/* parent dir timestamps will update from srv
diff --git a/fs/coda/dir.c b/fs/coda/dir.c
index 0239433..28e7e13 100644
--- a/fs/coda/dir.c
+++ b/fs/coda/dir.c
@@ -340,7 +340,7 @@ static int coda_rmdir(struct inode *dir, struct dentry *de)
 	if (!error) {
 		/* VFS may delete the child */
 		if (de->d_inode)
-		    de->d_inode->i_nlink = 0;
+			clear_nlink(de->d_inode);
 
 		/* fix the link count of the parent */
 		coda_dir_drop_nlink(dir);
diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
index 2f27e57..c196e54 100644
--- a/fs/devpts/inode.c
+++ b/fs/devpts/inode.c
@@ -549,7 +549,7 @@ void devpts_pty_kill(struct tty_struct *tty)
 
 	dentry = d_find_alias(inode);
 
-	inode->i_nlink--;
+	drop_nlink(inode);
 	d_delete(dentry);
 	dput(dentry);	/* d_alloc_name() in devpts_pty_new() */
 	dput(dentry);		/* d_find_alias above */
diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c
index ee9ed31..c4e81df 100644
--- a/fs/ext2/ialloc.c
+++ b/fs/ext2/ialloc.c
@@ -601,7 +601,7 @@ fail_free_drop:
 fail_drop:
 	dquot_drop(inode);
 	inode->i_flags |= S_NOQUOTA;
-	inode->i_nlink = 0;
+	clear_nlink(inode);
 	unlock_new_inode(inode);
 	iput(inode);
 	return ERR_PTR(err);
diff --git a/fs/ext3/ialloc.c b/fs/ext3/ialloc.c
index bf09cbf..835d4ea 100644
--- a/fs/ext3/ialloc.c
+++ b/fs/ext3/ialloc.c
@@ -621,7 +621,7 @@ fail_free_drop:
 fail_drop:
 	dquot_drop(inode);
 	inode->i_flags |= S_NOQUOTA;
-	inode->i_nlink = 0;
+	clear_nlink(inode);
 	unlock_new_inode(inode);
 	iput(inode);
 	brelse(bitmap_bh);
diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c
index 0629e09..8a60e33 100644
--- a/fs/ext3/namei.c
+++ b/fs/ext3/namei.c
@@ -1833,7 +1833,7 @@ retry:
 
 	if (err) {
 out_clear_inode:
-		inode->i_nlink = 0;
+		clear_nlink(inode);
 		unlock_new_inode(inode);
 		ext3_mark_inode_dirty(handle, inode);
 		iput (inode);
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
index 9c63f27..ecc55bd 100644
--- a/fs/ext4/ialloc.c
+++ b/fs/ext4/ialloc.c
@@ -1084,7 +1084,7 @@ fail_free_drop:
 fail_drop:
 	dquot_drop(inode);
 	inode->i_flags |= S_NOQUOTA;
-	inode->i_nlink = 0;
+	clear_nlink(inode);
 	unlock_new_inode(inode);
 	iput(inode);
 	brelse(inode_bitmap_bh);
diff --git a/fs/ext4/migrate.c b/fs/ext4/migrate.c
index b57b98f..667cc88 100644
--- a/fs/ext4/migrate.c
+++ b/fs/ext4/migrate.c
@@ -507,7 +507,7 @@ int ext4_ext_migrate(struct inode *inode)
 	 * Set the i_nlink to zero so it will be deleted later
 	 * when we drop inode reference.
 	 */
-	tmp_inode->i_nlink = 0;
+	clear_nlink(tmp_inode);
 
 	ext4_ext_tree_init(handle, tmp_inode);
 	ext4_orphan_add(handle, tmp_inode);
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index 1c924fa..4623c08 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -2539,7 +2539,7 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
 		if (new_inode) {
 			/* checked empty_dir above, can't have another parent,
 			 * ext4_dec_count() won't work for many-linked dirs */
-			new_inode->i_nlink = 0;
+			clear_nlink(new_inode);
 		} else {
 			ext4_inc_count(handle, new_dir);
 			ext4_update_dx_flag(new_dir);
diff --git a/fs/hfs/dir.c b/fs/hfs/dir.c
index b4d70b1..bce4eef 100644
--- a/fs/hfs/dir.c
+++ b/fs/hfs/dir.c
@@ -198,7 +198,7 @@ static int hfs_create(struct inode *dir, struct dentry *dentry, int mode,
 
 	res = hfs_cat_create(inode->i_ino, dir, &dentry->d_name, inode);
 	if (res) {
-		inode->i_nlink = 0;
+		clear_nlink(inode);
 		hfs_delete_inode(inode);
 		iput(inode);
 		return res;
@@ -227,7 +227,7 @@ static int hfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 
 	res = hfs_cat_create(inode->i_ino, dir, &dentry->d_name, inode);
 	if (res) {
-		inode->i_nlink = 0;
+		clear_nlink(inode);
 		hfs_delete_inode(inode);
 		iput(inode);
 		return res;
diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c
index 25b2443..4536cd3 100644
--- a/fs/hfsplus/dir.c
+++ b/fs/hfsplus/dir.c
@@ -415,7 +415,7 @@ static int hfsplus_symlink(struct inode *dir, struct dentry *dentry,
 	goto out;
 
 out_err:
-	inode->i_nlink = 0;
+	clear_nlink(inode);
 	hfsplus_delete_inode(inode);
 	iput(inode);
 out:
@@ -440,7 +440,7 @@ static int hfsplus_mknod(struct inode *dir, struct dentry *dentry,
 
 	res = hfsplus_create_cat(inode->i_ino, dir, &dentry->d_name, inode);
 	if (res) {
-		inode->i_nlink = 0;
+		clear_nlink(inode);
 		hfsplus_delete_inode(inode);
 		iput(inode);
 		goto out;
diff --git a/fs/hpfs/inode.c b/fs/hpfs/inode.c
index 338cd83..dfe800c 100644
--- a/fs/hpfs/inode.c
+++ b/fs/hpfs/inode.c
@@ -53,7 +53,7 @@ void hpfs_read_inode(struct inode *i)
 		i->i_mode &= ~0111;
 		i->i_op = &hpfs_file_iops;
 		i->i_fop = &hpfs_file_ops;
-		i->i_nlink = 0;*/
+		clear_nlink(i);*/
 		make_bad_inode(i);
 		return;
 	}
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index ec88953..0be5a78 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -970,7 +970,7 @@ struct file *hugetlb_file_setup(const char *name, size_t size,
 
 	d_instantiate(path.dentry, inode);
 	inode->i_size = size;
-	inode->i_nlink = 0;
+	clear_nlink(inode);
 
 	error = -ENFILE;
 	file = alloc_file(&path, FMODE_WRITE | FMODE_READ,
diff --git a/fs/jfs/jfs_inode.c b/fs/jfs/jfs_inode.c
index 2686531..c1a3e60 100644
--- a/fs/jfs/jfs_inode.c
+++ b/fs/jfs/jfs_inode.c
@@ -157,7 +157,7 @@ fail_drop:
 	dquot_drop(inode);
 	inode->i_flags |= S_NOQUOTA;
 fail_unlock:
-	inode->i_nlink = 0;
+	clear_nlink(inode);
 	unlock_new_inode(inode);
 fail_put:
 	iput(inode);
diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c
index e17545e..94b0a62 100644
--- a/fs/jfs/namei.c
+++ b/fs/jfs/namei.c
@@ -172,7 +172,7 @@ static int jfs_create(struct inode *dip, struct dentry *dentry, int mode,
 	mutex_unlock(&JFS_IP(dip)->commit_mutex);
 	if (rc) {
 		free_ea_wmap(ip);
-		ip->i_nlink = 0;
+		clear_nlink(ip);
 		unlock_new_inode(ip);
 		iput(ip);
 	} else {
@@ -311,7 +311,7 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode)
 	mutex_unlock(&JFS_IP(dip)->commit_mutex);
 	if (rc) {
 		free_ea_wmap(ip);
-		ip->i_nlink = 0;
+		clear_nlink(ip);
 		unlock_new_inode(ip);
 		iput(ip);
 	} else {
@@ -844,7 +844,7 @@ static int jfs_link(struct dentry *old_dentry,
 	rc = txCommit(tid, 2, &iplist[0], 0);
 
 	if (rc) {
-		ip->i_nlink--; /* never instantiated */
+		drop_nlink(ip); /* never instantiated */
 		iput(ip);
 	} else
 		d_instantiate(dentry, ip);
@@ -1048,7 +1048,7 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
 	mutex_unlock(&JFS_IP(dip)->commit_mutex);
 	if (rc) {
 		free_ea_wmap(ip);
-		ip->i_nlink = 0;
+		clear_nlink(ip);
 		unlock_new_inode(ip);
 		iput(ip);
 	} else {
@@ -1433,7 +1433,7 @@ static int jfs_mknod(struct inode *dir, struct dentry *dentry,
 	mutex_unlock(&JFS_IP(dir)->commit_mutex);
 	if (rc) {
 		free_ea_wmap(ip);
-		ip->i_nlink = 0;
+		clear_nlink(ip);
 		unlock_new_inode(ip);
 		iput(ip);
 	} else {
diff --git a/fs/logfs/dir.c b/fs/logfs/dir.c
index b3ff3d8..b7d7f67 100644
--- a/fs/logfs/dir.c
+++ b/fs/logfs/dir.c
@@ -197,7 +197,7 @@ static int logfs_remove_inode(struct inode *inode)
 {
 	int ret;
 
-	inode->i_nlink--;
+	drop_nlink(inode);
 	ret = write_inode(inode);
 	LOGFS_BUG_ON(ret, inode->i_sb);
 	return ret;
@@ -433,7 +433,7 @@ static int __logfs_create(struct inode *dir, struct dentry *dentry,
 
 	ta = kzalloc(sizeof(*ta), GFP_KERNEL);
 	if (!ta) {
-		inode->i_nlink--;
+		drop_nlink(inode);
 		iput(inode);
 		return -ENOMEM;
 	}
@@ -456,7 +456,7 @@ static int __logfs_create(struct inode *dir, struct dentry *dentry,
 		abort_transaction(inode, ta);
 		li->li_flags |= LOGFS_IF_STILLBORN;
 		/* FIXME: truncate symlink */
-		inode->i_nlink--;
+		drop_nlink(inode);
 		iput(inode);
 		goto out;
 	}
@@ -563,7 +563,7 @@ static int logfs_link(struct dentry *old_dentry, struct inode *dir,
 
 	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
 	ihold(inode);
-	inode->i_nlink++;
+	inc_nlink(inode);
 	mark_inode_dirty_sync(inode);
 
 	return __logfs_create(dir, dentry, inode, NULL, 0);
diff --git a/fs/logfs/inode.c b/fs/logfs/inode.c
index 9abb048..7e441ad 100644
--- a/fs/logfs/inode.c
+++ b/fs/logfs/inode.c
@@ -93,7 +93,7 @@ static struct inode *__logfs_iget(struct super_block *sb, ino_t ino)
 		/* inode->i_nlink == 0 can be true when called from
 		 * block validator */
 		/* set i_nlink to 0 to prevent caching */
-		inode->i_nlink = 0;
+		clear_nlink(inode);
 		logfs_inode(inode)->li_flags |= LOGFS_IF_ZOMBIE;
 		iget_failed(inode);
 		if (!err)
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index fe12037..53e10ff 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -320,7 +320,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
 		memset(&inode->i_ctime, 0, sizeof(inode->i_ctime));
 		nfsi->change_attr = 0;
 		inode->i_size = 0;
-		inode->i_nlink = 0;
+		clear_nlink(inode);
 		inode->i_uid = -2;
 		inode->i_gid = -2;
 		inode->i_blocks = 0;
diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c
index 666628b..08ac272 100644
--- a/fs/nilfs2/inode.c
+++ b/fs/nilfs2/inode.c
@@ -354,7 +354,7 @@ struct inode *nilfs_new_inode(struct inode *dir, int mode)
 
  failed_acl:
  failed_bmap:
-	inode->i_nlink = 0;
+	clear_nlink(inode);
 	iput(inode);  /* raw_inode will be deleted through
 			 generic_delete_inode() */
 	goto failed;
diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c
index 0181f63..ea0ecbd 100644
--- a/fs/ocfs2/namei.c
+++ b/fs/ocfs2/namei.c
@@ -1377,7 +1377,7 @@ static int ocfs2_rename(struct inode *old_dir,
 	}
 
 	if (new_inode) {
-		new_inode->i_nlink--;
+		drop_nlink(new_inode);
 		new_inode->i_ctime = CURRENT_TIME;
 	}
 	old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
@@ -1385,9 +1385,9 @@ static int ocfs2_rename(struct inode *old_dir,
 	if (update_dot_dot) {
 		status = ocfs2_update_entry(old_inode, handle,
 					    &old_inode_dot_dot_res, new_dir);
-		old_dir->i_nlink--;
+		drop_nlink(old_dir);
 		if (new_inode) {
-			new_inode->i_nlink--;
+			drop_nlink(new_inode);
 		} else {
 			inc_nlink(new_dir);
 			mark_inode_dirty(new_dir);
@@ -2280,7 +2280,7 @@ int ocfs2_create_inode_in_orphan(struct inode *dir,
 		goto leave;
 	}
 
-	inode->i_nlink = 0;
+	clear_nlink(inode);
 	/* do the real work now. */
 	status = __ocfs2_mknod_locked(dir, inode,
 				      0, &new_di_bh, parent_di_bh, handle,
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c
index 1a77dbe..b441132 100644
--- a/fs/proc/proc_sysctl.c
+++ b/fs/proc/proc_sysctl.c
@@ -39,7 +39,7 @@ static struct inode *proc_sys_make_inode(struct super_block *sb,
 		inode->i_fop = &proc_sys_file_operations;
 	} else {
 		inode->i_mode |= S_IFDIR;
-		inode->i_nlink = 0;
+		clear_nlink(inode);
 		inode->i_op = &proc_sys_dir_operations;
 		inode->i_fop = &proc_sys_dir_file_operations;
 	}
diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c
index 9b0d4b7..c425441 100644
--- a/fs/reiserfs/inode.c
+++ b/fs/reiserfs/inode.c
@@ -1444,7 +1444,7 @@ void reiserfs_read_locked_inode(struct inode *inode,
 		/* a stale NFS handle can trigger this without it being an error */
 		pathrelse(&path_to_sd);
 		reiserfs_make_bad_inode(inode);
-		inode->i_nlink = 0;
+		clear_nlink(inode);
 		return;
 	}
 
@@ -1987,7 +1987,7 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th,
 	make_bad_inode(inode);
 
       out_inserted_sd:
-	inode->i_nlink = 0;
+	clear_nlink(inode);
 	th->t_trans_id = 0;	/* so the caller can't use this handle later */
 	unlock_new_inode(inode); /* OK to do even if we hadn't locked it */
 	iput(inode);
diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c
index ef39232..6ce3328 100644
--- a/fs/reiserfs/namei.c
+++ b/fs/reiserfs/namei.c
@@ -622,7 +622,7 @@ static int reiserfs_create(struct inode *dir, struct dentry *dentry, int mode,
 			       dentry->d_name.len, inode, 1 /*visible */ );
 	if (retval) {
 		int err;
-		inode->i_nlink--;
+		drop_nlink(inode);
 		reiserfs_update_sd(&th, inode);
 		err = journal_end(&th, dir->i_sb, jbegin_count);
 		if (err)
@@ -702,7 +702,7 @@ static int reiserfs_mknod(struct inode *dir, struct dentry *dentry, int mode,
 			       dentry->d_name.len, inode, 1 /*visible */ );
 	if (retval) {
 		int err;
-		inode->i_nlink--;
+		drop_nlink(inode);
 		reiserfs_update_sd(&th, inode);
 		err = journal_end(&th, dir->i_sb, jbegin_count);
 		if (err)
@@ -787,7 +787,7 @@ static int reiserfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 			       dentry->d_name.len, inode, 1 /*visible */ );
 	if (retval) {
 		int err;
-		inode->i_nlink = 0;
+		clear_nlink(inode);
 		DEC_DIR_INODE_NLINK(dir);
 		reiserfs_update_sd(&th, inode);
 		err = journal_end(&th, dir->i_sb, jbegin_count);
@@ -1086,7 +1086,7 @@ static int reiserfs_symlink(struct inode *parent_dir,
 				    dentry->d_name.len, inode, 1 /*visible */ );
 	if (retval) {
 		int err;
-		inode->i_nlink--;
+		drop_nlink(inode);
 		reiserfs_update_sd(&th, inode);
 		err = journal_end(&th, parent_dir->i_sb, jbegin_count);
 		if (err)
@@ -1129,7 +1129,7 @@ static int reiserfs_link(struct dentry *old_dentry, struct inode *dir,
 
 	retval = journal_begin(&th, dir->i_sb, jbegin_count);
 	if (retval) {
-		inode->i_nlink--;
+		drop_nlink(inode);
 		reiserfs_write_unlock(dir->i_sb);
 		return retval;
 	}
@@ -1144,7 +1144,7 @@ static int reiserfs_link(struct dentry *old_dentry, struct inode *dir,
 
 	if (retval) {
 		int err;
-		inode->i_nlink--;
+		drop_nlink(inode);
 		err = journal_end(&th, dir->i_sb, jbegin_count);
 		reiserfs_write_unlock(dir->i_sb);
 		return err ? err : retval;
diff --git a/fs/ubifs/xattr.c b/fs/ubifs/xattr.c
index 16f19f5..993adc8 100644
--- a/fs/ubifs/xattr.c
+++ b/fs/ubifs/xattr.c
@@ -558,7 +558,7 @@ int ubifs_removexattr(struct dentry *dentry, const char *name)
 	}
 
 	ubifs_assert(inode->i_nlink == 1);
-	inode->i_nlink = 0;
+	clear_nlink(inode);
 	err = remove_xattr(c, host, inode, &nm);
 	if (err)
 		inode->i_nlink = 1;
diff --git a/fs/udf/namei.c b/fs/udf/namei.c
index f1dce84..e8d61b1 100644
--- a/fs/udf/namei.c
+++ b/fs/udf/namei.c
@@ -577,8 +577,7 @@ static int udf_create(struct inode *dir, struct dentry *dentry, int mode,
 
 	fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err);
 	if (!fi) {
-		inode->i_nlink--;
-		mark_inode_dirty(inode);
+		inode_dec_link_count(inode);
 		iput(inode);
 		return err;
 	}
@@ -618,8 +617,7 @@ static int udf_mknod(struct inode *dir, struct dentry *dentry, int mode,
 	init_special_inode(inode, mode, rdev);
 	fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err);
 	if (!fi) {
-		inode->i_nlink--;
-		mark_inode_dirty(inode);
+		inode_dec_link_count(inode);
 		iput(inode);
 		return err;
 	}
@@ -665,8 +663,7 @@ static int udf_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 	inode->i_fop = &udf_dir_operations;
 	fi = udf_add_entry(inode, NULL, &fibh, &cfi, &err);
 	if (!fi) {
-		inode->i_nlink--;
-		mark_inode_dirty(inode);
+		inode_dec_link_count(inode);
 		iput(inode);
 		goto out;
 	}
@@ -683,7 +680,7 @@ static int udf_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 
 	fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err);
 	if (!fi) {
-		inode->i_nlink = 0;
+		clear_nlink(inode);
 		mark_inode_dirty(inode);
 		iput(inode);
 		goto out;
diff --git a/fs/ufs/ialloc.c b/fs/ufs/ialloc.c
index 2eabf04..78a4c70 100644
--- a/fs/ufs/ialloc.c
+++ b/fs/ufs/ialloc.c
@@ -341,7 +341,7 @@ cg_found:
 
 fail_remove_inode:
 	unlock_super(sb);
-	inode->i_nlink = 0;
+	clear_nlink(inode);
 	iput(inode);
 	UFSD("EXIT (FAILED): err %d\n", err);
 	return ERR_PTR(err);
diff --git a/mm/shmem.c b/mm/shmem.c
index 32f6763..d06eb8c 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -2497,7 +2497,7 @@ struct file *shmem_file_setup(const char *name, loff_t size, unsigned long flags
 
 	d_instantiate(path.dentry, inode);
 	inode->i_size = size;
-	inode->i_nlink = 0;	/* It is unlinked */
+	clear_nlink(inode);	/* It is unlinked */
 #ifndef CONFIG_MMU
 	error = ramfs_nommu_expand_for_mapping(inode, size);
 	if (error)
-- 
1.7.3.4

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 10/13] filesystems: add set_nlink()
  2011-10-12 14:48 [PATCH 0/13] read-only remount race fix v7 Miklos Szeredi
                   ` (8 preceding siblings ...)
  2011-10-12 14:49 ` [PATCH 09/13] filesystems: add missing nlink wrappers Miklos Szeredi
@ 2011-10-12 14:49 ` Miklos Szeredi
  2011-10-13 16:33   ` Steven Whitehouse
  2011-10-12 14:49 ` [PATCH 11/13] vfs: protect i_nlink Miklos Szeredi
                   ` (4 subsequent siblings)
  14 siblings, 1 reply; 27+ messages in thread
From: Miklos Szeredi @ 2011-10-12 14:49 UTC (permalink / raw)
  To: viro; +Cc: linux-fsdevel, linux-kernel, jack, hch, akpm, toshi.okajima,
	mszeredi

From: Miklos Szeredi <mszeredi@suse.cz>

Replace remaining direct i_nlink updates with a new set_nlink()
updater function.

Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
---
 arch/s390/hypfs/inode.c          |    2 +-
 drivers/staging/pohmelfs/inode.c |    2 +-
 fs/9p/vfs_inode.c                |    4 ++--
 fs/9p/vfs_inode_dotl.c           |    4 ++--
 fs/adfs/inode.c                  |    2 +-
 fs/affs/amigaffs.c               |    2 +-
 fs/affs/inode.c                  |    8 ++++----
 fs/afs/fsclient.c                |    2 +-
 fs/afs/inode.c                   |    4 ++--
 fs/autofs4/inode.c               |    2 +-
 fs/befs/linuxvfs.c               |    2 +-
 fs/bfs/dir.c                     |    2 +-
 fs/bfs/inode.c                   |    2 +-
 fs/btrfs/delayed-inode.c         |    2 +-
 fs/btrfs/disk-io.c               |    2 +-
 fs/btrfs/inode.c                 |    4 ++--
 fs/btrfs/tree-log.c              |    2 +-
 fs/ceph/caps.c                   |    2 +-
 fs/ceph/inode.c                  |    2 +-
 fs/cifs/inode.c                  |    6 +++---
 fs/coda/coda_linux.c             |    2 +-
 fs/devpts/inode.c                |    2 +-
 fs/ecryptfs/inode.c              |   12 ++++++------
 fs/efs/inode.c                   |    2 +-
 fs/exofs/inode.c                 |    2 +-
 fs/ext2/inode.c                  |    2 +-
 fs/ext3/inode.c                  |    2 +-
 fs/ext3/namei.c                  |    4 ++--
 fs/ext4/inode.c                  |    2 +-
 fs/ext4/namei.c                  |    6 +++---
 fs/fat/inode.c                   |    4 ++--
 fs/fat/namei_msdos.c             |    2 +-
 fs/fat/namei_vfat.c              |    2 +-
 fs/freevxfs/vxfs_inode.c         |    2 +-
 fs/fuse/control.c                |    2 +-
 fs/fuse/inode.c                  |    2 +-
 fs/gfs2/glops.c                  |    2 +-
 fs/hfs/inode.c                   |    4 ++--
 fs/hfsplus/inode.c               |   10 +++++-----
 fs/hostfs/hostfs_kern.c          |    2 +-
 fs/hpfs/dir.c                    |    2 +-
 fs/hpfs/inode.c                  |    8 ++++----
 fs/hpfs/namei.c                  |    8 ++++----
 fs/hppfs/hppfs.c                 |    2 +-
 fs/isofs/inode.c                 |    4 ++--
 fs/isofs/rock.c                  |    4 ++--
 fs/jffs2/dir.c                   |    6 +++---
 fs/jffs2/fs.c                    |    6 +++---
 fs/jfs/jfs_imap.c                |    6 +++---
 fs/jfs/namei.c                   |    2 +-
 fs/libfs.c                       |    2 +-
 fs/logfs/readwrite.c             |    2 +-
 fs/minix/inode.c                 |    4 ++--
 fs/ncpfs/inode.c                 |    2 +-
 fs/nfs/inode.c                   |    4 ++--
 fs/nilfs2/inode.c                |    2 +-
 fs/nilfs2/namei.c                |    2 +-
 fs/ntfs/inode.c                  |    8 ++++----
 fs/ocfs2/dir.c                   |    4 ++--
 fs/ocfs2/dlmglue.c               |    2 +-
 fs/ocfs2/inode.c                 |    4 ++--
 fs/ocfs2/namei.c                 |    8 ++++----
 fs/openpromfs/inode.c            |    4 ++--
 fs/proc/base.c                   |   12 ++++++------
 fs/proc/generic.c                |    2 +-
 fs/proc/inode.c                  |    2 +-
 fs/qnx4/inode.c                  |    2 +-
 fs/reiserfs/inode.c              |    6 +++---
 fs/reiserfs/namei.c              |    4 ++--
 fs/romfs/super.c                 |    2 +-
 fs/squashfs/inode.c              |   18 +++++++++---------
 fs/stack.c                       |    2 +-
 fs/sysfs/inode.c                 |    2 +-
 fs/sysv/inode.c                  |    2 +-
 fs/ubifs/super.c                 |    2 +-
 fs/ubifs/xattr.c                 |    2 +-
 fs/udf/inode.c                   |    8 +++++---
 fs/udf/namei.c                   |    4 ++--
 fs/ufs/inode.c                   |    4 ++--
 fs/xfs/xfs_iops.c                |    2 +-
 include/linux/fs.h               |   13 +++++++++++++
 81 files changed, 163 insertions(+), 148 deletions(-)

diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c
index baa82f8..481f4f7 100644
--- a/arch/s390/hypfs/inode.c
+++ b/arch/s390/hypfs/inode.c
@@ -108,7 +108,7 @@ static struct inode *hypfs_make_inode(struct super_block *sb, int mode)
 		ret->i_gid = hypfs_info->gid;
 		ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME;
 		if (mode & S_IFDIR)
-			ret->i_nlink = 2;
+			set_nlink(ret, 2);
 	}
 	return ret;
 }
diff --git a/drivers/staging/pohmelfs/inode.c b/drivers/staging/pohmelfs/inode.c
index f3c6060..7a19555 100644
--- a/drivers/staging/pohmelfs/inode.c
+++ b/drivers/staging/pohmelfs/inode.c
@@ -1197,7 +1197,7 @@ const struct inode_operations pohmelfs_file_inode_operations = {
 void pohmelfs_fill_inode(struct inode *inode, struct netfs_inode_info *info)
 {
 	inode->i_mode = info->mode;
-	inode->i_nlink = info->nlink;
+	set_nlink(inode, info->nlink);
 	inode->i_uid = info->uid;
 	inode->i_gid = info->gid;
 	inode->i_blocks = info->blocks;
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index e3c03db..5aaaec7 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -1140,7 +1140,7 @@ v9fs_stat2inode(struct p9_wstat *stat, struct inode *inode,
 	struct v9fs_session_info *v9ses = sb->s_fs_info;
 	struct v9fs_inode *v9inode = V9FS_I(inode);
 
-	inode->i_nlink = 1;
+	set_nlink(inode, 1);
 
 	inode->i_atime.tv_sec = stat->atime;
 	inode->i_mtime.tv_sec = stat->mtime;
@@ -1166,7 +1166,7 @@ v9fs_stat2inode(struct p9_wstat *stat, struct inode *inode,
 			/* HARDLINKCOUNT %u */
 			sscanf(ext, "%13s %u", tag_name, &i_nlink);
 			if (!strncmp(tag_name, "HARDLINKCOUNT", 13))
-				inode->i_nlink = i_nlink;
+				set_nlink(inode, i_nlink);
 		}
 	}
 	mode = stat->mode & S_IALLUGO;
diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c
index aded79f..0b5745e 100644
--- a/fs/9p/vfs_inode_dotl.c
+++ b/fs/9p/vfs_inode_dotl.c
@@ -606,7 +606,7 @@ v9fs_stat2inode_dotl(struct p9_stat_dotl *stat, struct inode *inode)
 		inode->i_ctime.tv_nsec = stat->st_ctime_nsec;
 		inode->i_uid = stat->st_uid;
 		inode->i_gid = stat->st_gid;
-		inode->i_nlink = stat->st_nlink;
+		set_nlink(inode, stat->st_nlink);
 
 		mode = stat->st_mode & S_IALLUGO;
 		mode |= inode->i_mode & ~S_IALLUGO;
@@ -632,7 +632,7 @@ v9fs_stat2inode_dotl(struct p9_stat_dotl *stat, struct inode *inode)
 		if (stat->st_result_mask & P9_STATS_GID)
 			inode->i_gid = stat->st_gid;
 		if (stat->st_result_mask & P9_STATS_NLINK)
-			inode->i_nlink = stat->st_nlink;
+			set_nlink(inode, stat->st_nlink);
 		if (stat->st_result_mask & P9_STATS_MODE) {
 			inode->i_mode = stat->st_mode;
 			if ((S_ISBLK(inode->i_mode)) ||
diff --git a/fs/adfs/inode.c b/fs/adfs/inode.c
index d5250c5..1dab6a1 100644
--- a/fs/adfs/inode.c
+++ b/fs/adfs/inode.c
@@ -247,7 +247,7 @@ adfs_iget(struct super_block *sb, struct object_info *obj)
 	inode->i_gid	 = ADFS_SB(sb)->s_gid;
 	inode->i_ino	 = obj->file_id;
 	inode->i_size	 = obj->size;
-	inode->i_nlink	 = 2;
+	set_nlink(inode, 2);
 	inode->i_blocks	 = (inode->i_size + sb->s_blocksize - 1) >>
 			    sb->s_blocksize_bits;
 
diff --git a/fs/affs/amigaffs.c b/fs/affs/amigaffs.c
index 8f12723..de37ec8 100644
--- a/fs/affs/amigaffs.c
+++ b/fs/affs/amigaffs.c
@@ -215,7 +215,7 @@ affs_remove_link(struct dentry *dentry)
 				break;
 			default:
 				if (!AFFS_TAIL(sb, bh)->link_chain)
-					inode->i_nlink = 1;
+					set_nlink(inode, 1);
 			}
 			affs_free_block(sb, link_ino);
 			goto done;
diff --git a/fs/affs/inode.c b/fs/affs/inode.c
index 5d82890..88a4b0b 100644
--- a/fs/affs/inode.c
+++ b/fs/affs/inode.c
@@ -54,7 +54,7 @@ struct inode *affs_iget(struct super_block *sb, unsigned long ino)
 	prot = be32_to_cpu(tail->protect);
 
 	inode->i_size = 0;
-	inode->i_nlink = 1;
+	set_nlink(inode, 1);
 	inode->i_mode = 0;
 	AFFS_I(inode)->i_extcnt = 1;
 	AFFS_I(inode)->i_ext_last = ~1;
@@ -137,7 +137,7 @@ struct inode *affs_iget(struct super_block *sb, unsigned long ino)
 					       sbi->s_hashsize + 1;
 		}
 		if (tail->link_chain)
-			inode->i_nlink = 2;
+			set_nlink(inode, 2);
 		inode->i_mapping->a_ops = (sbi->s_flags & SF_OFS) ? &affs_aops_ofs : &affs_aops;
 		inode->i_op = &affs_file_inode_operations;
 		inode->i_fop = &affs_file_operations;
@@ -304,7 +304,7 @@ affs_new_inode(struct inode *dir)
 	inode->i_uid     = current_fsuid();
 	inode->i_gid     = current_fsgid();
 	inode->i_ino     = block;
-	inode->i_nlink   = 1;
+	set_nlink(inode, 1);
 	inode->i_mtime   = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
 	atomic_set(&AFFS_I(inode)->i_opencnt, 0);
 	AFFS_I(inode)->i_blkcnt = 0;
@@ -387,7 +387,7 @@ affs_add_entry(struct inode *dir, struct inode *inode, struct dentry *dentry, s3
 		AFFS_TAIL(sb, inode_bh)->link_chain = cpu_to_be32(block);
 		affs_adjust_checksum(inode_bh, block - be32_to_cpu(chain));
 		mark_buffer_dirty_inode(inode_bh, inode);
-		inode->i_nlink = 2;
+		set_nlink(inode, 2);
 		ihold(inode);
 	}
 	affs_fix_checksum(sb, bh);
diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c
index 346e328..2f213d1 100644
--- a/fs/afs/fsclient.c
+++ b/fs/afs/fsclient.c
@@ -90,7 +90,7 @@ static void xdr_decode_AFSFetchStatus(const __be32 **_bp,
 			vnode->vfs_inode.i_uid = status->owner;
 			vnode->vfs_inode.i_gid = status->group;
 			vnode->vfs_inode.i_generation = vnode->fid.unique;
-			vnode->vfs_inode.i_nlink = status->nlink;
+			set_nlink(&vnode->vfs_inode, status->nlink);
 
 			mode = vnode->vfs_inode.i_mode;
 			mode &= ~S_IALLUGO;
diff --git a/fs/afs/inode.c b/fs/afs/inode.c
index 0fdab6e..d890ae3 100644
--- a/fs/afs/inode.c
+++ b/fs/afs/inode.c
@@ -67,7 +67,7 @@ static int afs_inode_map_status(struct afs_vnode *vnode, struct key *key)
 		fscache_attr_changed(vnode->cache);
 #endif
 
-	inode->i_nlink		= vnode->status.nlink;
+	set_nlink(inode, vnode->status.nlink);
 	inode->i_uid		= vnode->status.owner;
 	inode->i_gid		= 0;
 	inode->i_size		= vnode->status.size;
@@ -174,7 +174,7 @@ struct inode *afs_iget_autocell(struct inode *dir, const char *dev_name,
 	inode->i_size		= 0;
 	inode->i_mode		= S_IFDIR | S_IRUGO | S_IXUGO;
 	inode->i_op		= &afs_autocell_inode_operations;
-	inode->i_nlink		= 2;
+	set_nlink(inode, 2);
 	inode->i_uid		= 0;
 	inode->i_gid		= 0;
 	inode->i_ctime.tv_sec	= get_seconds();
diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c
index 180fa24..8179f1a 100644
--- a/fs/autofs4/inode.c
+++ b/fs/autofs4/inode.c
@@ -342,7 +342,7 @@ struct inode *autofs4_get_inode(struct super_block *sb, mode_t mode)
 	inode->i_ino = get_next_ino();
 
 	if (S_ISDIR(mode)) {
-		inode->i_nlink = 2;
+		set_nlink(inode, 2);
 		inode->i_op = &autofs4_dir_inode_operations;
 		inode->i_fop = &autofs4_dir_operations;
 	} else if (S_ISLNK(mode)) {
diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c
index 720d885..8342ca6 100644
--- a/fs/befs/linuxvfs.c
+++ b/fs/befs/linuxvfs.c
@@ -357,7 +357,7 @@ static struct inode *befs_iget(struct super_block *sb, unsigned long ino)
 	inode->i_gid = befs_sb->mount_opts.use_gid ?
 	    befs_sb->mount_opts.gid : (gid_t) fs32_to_cpu(sb, raw_inode->gid);
 
-	inode->i_nlink = 1;
+	set_nlink(inode, 1);
 
 	/*
 	 * BEFS's time is 64 bits, but current VFS is 32 bits...
diff --git a/fs/bfs/dir.c b/fs/bfs/dir.c
index b14cebf..9cc0740 100644
--- a/fs/bfs/dir.c
+++ b/fs/bfs/dir.c
@@ -199,7 +199,7 @@ static int bfs_unlink(struct inode *dir, struct dentry *dentry)
 		printf("unlinking non-existent file %s:%lu (nlink=%d)\n",
 					inode->i_sb->s_id, inode->i_ino,
 					inode->i_nlink);
-		inode->i_nlink = 1;
+		set_nlink(inode, 1);
 	}
 	de->ino = 0;
 	mark_buffer_dirty_inode(bh, dir);
diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c
index a8e37f8..697af5b 100644
--- a/fs/bfs/inode.c
+++ b/fs/bfs/inode.c
@@ -78,7 +78,7 @@ struct inode *bfs_iget(struct super_block *sb, unsigned long ino)
 	BFS_I(inode)->i_dsk_ino = le16_to_cpu(di->i_ino);
 	inode->i_uid =  le32_to_cpu(di->i_uid);
 	inode->i_gid =  le32_to_cpu(di->i_gid);
-	inode->i_nlink =  le32_to_cpu(di->i_nlink);
+	set_nlink(inode, le32_to_cpu(di->i_nlink));
 	inode->i_size = BFS_FILESIZE(di);
 	inode->i_blocks = BFS_FILEBLOCKS(di);
 	inode->i_atime.tv_sec =  le32_to_cpu(di->i_atime);
diff --git a/fs/btrfs/delayed-inode.c b/fs/btrfs/delayed-inode.c
index b52c672..ae4d9cd 100644
--- a/fs/btrfs/delayed-inode.c
+++ b/fs/btrfs/delayed-inode.c
@@ -1641,7 +1641,7 @@ int btrfs_fill_inode(struct inode *inode, u32 *rdev)
 	inode->i_gid = btrfs_stack_inode_gid(inode_item);
 	btrfs_i_size_write(inode, btrfs_stack_inode_size(inode_item));
 	inode->i_mode = btrfs_stack_inode_mode(inode_item);
-	inode->i_nlink = btrfs_stack_inode_nlink(inode_item);
+	set_nlink(inode, btrfs_stack_inode_nlink(inode_item));
 	inode_set_bytes(inode, btrfs_stack_inode_nbytes(inode_item));
 	BTRFS_I(inode)->generation = btrfs_stack_inode_generation(inode_item);
 	BTRFS_I(inode)->sequence = btrfs_stack_inode_sequence(inode_item);
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 07b3ac6..07ea918 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -1705,7 +1705,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
 	sb->s_bdi = &fs_info->bdi;
 
 	fs_info->btree_inode->i_ino = BTRFS_BTREE_INODE_OBJECTID;
-	fs_info->btree_inode->i_nlink = 1;
+	set_nlink(fs_info->btree_inode, 1);
 	/*
 	 * we set the i_size on the btree inode to the max possible int.
 	 * the real end of the address space is determined by all of
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index b2d004a..75686a6 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -2534,7 +2534,7 @@ static void btrfs_read_locked_inode(struct inode *inode)
 	inode_item = btrfs_item_ptr(leaf, path->slots[0],
 				    struct btrfs_inode_item);
 	inode->i_mode = btrfs_inode_mode(leaf, inode_item);
-	inode->i_nlink = btrfs_inode_nlink(leaf, inode_item);
+	set_nlink(inode, btrfs_inode_nlink(leaf, inode_item));
 	inode->i_uid = btrfs_inode_uid(leaf, inode_item);
 	inode->i_gid = btrfs_inode_gid(leaf, inode_item);
 	btrfs_i_size_write(inode, btrfs_inode_size(leaf, inode_item));
@@ -6728,7 +6728,7 @@ int btrfs_create_subvol_root(struct btrfs_trans_handle *trans,
 	inode->i_op = &btrfs_dir_inode_operations;
 	inode->i_fop = &btrfs_dir_file_operations;
 
-	inode->i_nlink = 1;
+	set_nlink(inode, 1);
 	btrfs_i_size_write(inode, 0);
 
 	err = btrfs_update_inode(trans, new_root, inode);
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index 786639f..0618aa3 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -1030,7 +1030,7 @@ static noinline int fixup_inode_link_count(struct btrfs_trans_handle *trans,
 	}
 	btrfs_release_path(path);
 	if (nlink != inode->i_nlink) {
-		inode->i_nlink = nlink;
+		set_nlink(inode, nlink);
 		btrfs_update_inode(trans, root, inode);
 	}
 	BTRFS_I(inode)->index_cnt = (u64)-1;
diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c
index 8d74ad7..8c00ada 100644
--- a/fs/ceph/caps.c
+++ b/fs/ceph/caps.c
@@ -2363,7 +2363,7 @@ static void handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant,
 	}
 
 	if ((issued & CEPH_CAP_LINK_EXCL) == 0)
-		inode->i_nlink = le32_to_cpu(grant->nlink);
+		set_nlink(inode, le32_to_cpu(grant->nlink));
 
 	if ((issued & CEPH_CAP_XATTR_EXCL) == 0 && grant->xattr_len) {
 		int len = le32_to_cpu(grant->xattr_len);
diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c
index 095799b..2dfbcee 100644
--- a/fs/ceph/inode.c
+++ b/fs/ceph/inode.c
@@ -619,7 +619,7 @@ static int fill_inode(struct inode *inode,
 	}
 
 	if ((issued & CEPH_CAP_LINK_EXCL) == 0)
-		inode->i_nlink = le32_to_cpu(info->nlink);
+		set_nlink(inode, le32_to_cpu(info->nlink));
 
 	/* be careful with mtime, atime, size */
 	ceph_decode_timespec(&atime, &info->atime);
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index a7b2dcd..7989118 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -132,7 +132,7 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
 	inode->i_mtime = fattr->cf_mtime;
 	inode->i_ctime = fattr->cf_ctime;
 	inode->i_rdev = fattr->cf_rdev;
-	inode->i_nlink = fattr->cf_nlink;
+	set_nlink(inode, fattr->cf_nlink);
 	inode->i_uid = fattr->cf_uid;
 	inode->i_gid = fattr->cf_gid;
 
@@ -900,7 +900,7 @@ struct inode *cifs_root_iget(struct super_block *sb)
 	if (rc && tcon->ipc) {
 		cFYI(1, "ipc connection - fake read inode");
 		inode->i_mode |= S_IFDIR;
-		inode->i_nlink = 2;
+		set_nlink(inode, 2);
 		inode->i_op = &cifs_ipc_inode_ops;
 		inode->i_fop = &simple_dir_operations;
 		inode->i_uid = cifs_sb->mnt_uid;
@@ -1362,7 +1362,7 @@ mkdir_get_info:
 		 /* setting nlink not necessary except in cases where we
 		  * failed to get it from the server or was set bogus */
 		if ((direntry->d_inode) && (direntry->d_inode->i_nlink < 2))
-				direntry->d_inode->i_nlink = 2;
+			set_nlink(direntry->d_inode, 2);
 
 		mode &= ~current_umask();
 		/* must turn on setgid bit if parent dir has it */
diff --git a/fs/coda/coda_linux.c b/fs/coda/coda_linux.c
index 2bdbcc1..854ace7 100644
--- a/fs/coda/coda_linux.c
+++ b/fs/coda/coda_linux.c
@@ -104,7 +104,7 @@ void coda_vattr_to_iattr(struct inode *inode, struct coda_vattr *attr)
         if (attr->va_gid != -1)
 	        inode->i_gid = (gid_t) attr->va_gid;
 	if (attr->va_nlink != -1)
-	        inode->i_nlink = attr->va_nlink;
+		set_nlink(inode, attr->va_nlink);
 	if (attr->va_size != -1)
 	        inode->i_size = attr->va_size;
 	if (attr->va_size != -1)
diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
index c196e54..d5d5297 100644
--- a/fs/devpts/inode.c
+++ b/fs/devpts/inode.c
@@ -307,7 +307,7 @@ devpts_fill_super(struct super_block *s, void *data, int silent)
 	inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR;
 	inode->i_op = &simple_dir_inode_operations;
 	inode->i_fop = &simple_dir_operations;
-	inode->i_nlink = 2;
+	set_nlink(inode, 2);
 
 	s->s_root = d_alloc_root(inode);
 	if (s->s_root)
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
index 11f8582..a36d327 100644
--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -474,8 +474,8 @@ static int ecryptfs_link(struct dentry *old_dentry, struct inode *dir,
 		goto out_lock;
 	fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode);
 	fsstack_copy_inode_size(dir, lower_dir_dentry->d_inode);
-	old_dentry->d_inode->i_nlink =
-		ecryptfs_inode_to_lower(old_dentry->d_inode)->i_nlink;
+	set_nlink(old_dentry->d_inode,
+		  ecryptfs_inode_to_lower(old_dentry->d_inode)->i_nlink);
 	i_size_write(new_dentry->d_inode, file_size_save);
 out_lock:
 	unlock_dir(lower_dir_dentry);
@@ -499,8 +499,8 @@ static int ecryptfs_unlink(struct inode *dir, struct dentry *dentry)
 		goto out_unlock;
 	}
 	fsstack_copy_attr_times(dir, lower_dir_inode);
-	dentry->d_inode->i_nlink =
-		ecryptfs_inode_to_lower(dentry->d_inode)->i_nlink;
+	set_nlink(dentry->d_inode,
+		  ecryptfs_inode_to_lower(dentry->d_inode)->i_nlink);
 	dentry->d_inode->i_ctime = dir->i_ctime;
 	d_drop(dentry);
 out_unlock:
@@ -565,7 +565,7 @@ static int ecryptfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 		goto out;
 	fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode);
 	fsstack_copy_inode_size(dir, lower_dir_dentry->d_inode);
-	dir->i_nlink = lower_dir_dentry->d_inode->i_nlink;
+	set_nlink(dir, lower_dir_dentry->d_inode->i_nlink);
 out:
 	unlock_dir(lower_dir_dentry);
 	if (!dentry->d_inode)
@@ -588,7 +588,7 @@ static int ecryptfs_rmdir(struct inode *dir, struct dentry *dentry)
 	if (!rc && dentry->d_inode)
 		clear_nlink(dentry->d_inode);
 	fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode);
-	dir->i_nlink = lower_dir_dentry->d_inode->i_nlink;
+	set_nlink(dir, lower_dir_dentry->d_inode->i_nlink);
 	unlock_dir(lower_dir_dentry);
 	if (!rc)
 		d_drop(dentry);
diff --git a/fs/efs/inode.c b/fs/efs/inode.c
index 9c13412..bc84f36 100644
--- a/fs/efs/inode.c
+++ b/fs/efs/inode.c
@@ -96,7 +96,7 @@ struct inode *efs_iget(struct super_block *super, unsigned long ino)
 	efs_inode = (struct efs_dinode *) (bh->b_data + offset);
     
 	inode->i_mode  = be16_to_cpu(efs_inode->di_mode);
-	inode->i_nlink = be16_to_cpu(efs_inode->di_nlink);
+	set_nlink(inode, be16_to_cpu(efs_inode->di_nlink));
 	inode->i_uid   = (uid_t)be16_to_cpu(efs_inode->di_uid);
 	inode->i_gid   = (gid_t)be16_to_cpu(efs_inode->di_gid);
 	inode->i_size  = be32_to_cpu(efs_inode->di_size);
diff --git a/fs/exofs/inode.c b/fs/exofs/inode.c
index f39a38f..a81976f 100644
--- a/fs/exofs/inode.c
+++ b/fs/exofs/inode.c
@@ -1032,7 +1032,7 @@ struct inode *exofs_iget(struct super_block *sb, unsigned long ino)
 	inode->i_mode = le16_to_cpu(fcb.i_mode);
 	inode->i_uid = le32_to_cpu(fcb.i_uid);
 	inode->i_gid = le32_to_cpu(fcb.i_gid);
-	inode->i_nlink = le16_to_cpu(fcb.i_links_count);
+	set_nlink(inode, le16_to_cpu(fcb.i_links_count));
 	inode->i_ctime.tv_sec = (signed)le32_to_cpu(fcb.i_ctime);
 	inode->i_atime.tv_sec = (signed)le32_to_cpu(fcb.i_atime);
 	inode->i_mtime.tv_sec = (signed)le32_to_cpu(fcb.i_mtime);
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index a8a58f6..91a6945 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -1321,7 +1321,7 @@ struct inode *ext2_iget (struct super_block *sb, unsigned long ino)
 		inode->i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16;
 		inode->i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16;
 	}
-	inode->i_nlink = le16_to_cpu(raw_inode->i_links_count);
+	set_nlink(inode, le16_to_cpu(raw_inode->i_links_count));
 	inode->i_size = le32_to_cpu(raw_inode->i_size);
 	inode->i_atime.tv_sec = (signed)le32_to_cpu(raw_inode->i_atime);
 	inode->i_ctime.tv_sec = (signed)le32_to_cpu(raw_inode->i_ctime);
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c
index 12661e1..85fe655 100644
--- a/fs/ext3/inode.c
+++ b/fs/ext3/inode.c
@@ -2899,7 +2899,7 @@ struct inode *ext3_iget(struct super_block *sb, unsigned long ino)
 		inode->i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16;
 		inode->i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16;
 	}
-	inode->i_nlink = le16_to_cpu(raw_inode->i_links_count);
+	set_nlink(inode, le16_to_cpu(raw_inode->i_links_count));
 	inode->i_size = le32_to_cpu(raw_inode->i_size);
 	inode->i_atime.tv_sec = (signed)le32_to_cpu(raw_inode->i_atime);
 	inode->i_ctime.tv_sec = (signed)le32_to_cpu(raw_inode->i_ctime);
diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c
index 8a60e33..642dc6d 100644
--- a/fs/ext3/namei.c
+++ b/fs/ext3/namei.c
@@ -1821,7 +1821,7 @@ retry:
 	de->name_len = 2;
 	strcpy (de->name, "..");
 	ext3_set_de_type(dir->i_sb, de, S_IFDIR);
-	inode->i_nlink = 2;
+	set_nlink(inode, 2);
 	BUFFER_TRACE(dir_block, "call ext3_journal_dirty_metadata");
 	err = ext3_journal_dirty_metadata(handle, dir_block);
 	if (err)
@@ -2170,7 +2170,7 @@ static int ext3_unlink(struct inode * dir, struct dentry *dentry)
 		ext3_warning (inode->i_sb, "ext3_unlink",
 			      "Deleting nonexistent file (%lu), %d",
 			      inode->i_ino, inode->i_nlink);
-		inode->i_nlink = 1;
+		set_nlink(inode, 1);
 	}
 	retval = ext3_delete_entry(handle, dir, de, bh);
 	if (retval)
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 986e238..989440e 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -3414,7 +3414,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
 		inode->i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16;
 		inode->i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16;
 	}
-	inode->i_nlink = le16_to_cpu(raw_inode->i_links_count);
+	set_nlink(inode, le16_to_cpu(raw_inode->i_links_count));
 
 	ext4_clear_state_flags(ei);	/* Only relevant on 32-bit archs */
 	ei->i_dir_start_lookup = 0;
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index 4623c08..5f7fb46 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -1694,7 +1694,7 @@ static void ext4_inc_count(handle_t *handle, struct inode *inode)
 	if (is_dx(inode) && inode->i_nlink > 1) {
 		/* limit is 16-bit i_links_count */
 		if (inode->i_nlink >= EXT4_LINK_MAX || inode->i_nlink == 2) {
-			inode->i_nlink = 1;
+			set_nlink(inode, 1);
 			EXT4_SET_RO_COMPAT_FEATURE(inode->i_sb,
 					      EXT4_FEATURE_RO_COMPAT_DIR_NLINK);
 		}
@@ -1861,7 +1861,7 @@ retry:
 	de->name_len = 2;
 	strcpy(de->name, "..");
 	ext4_set_de_type(dir->i_sb, de, S_IFDIR);
-	inode->i_nlink = 2;
+	set_nlink(inode, 2);
 	BUFFER_TRACE(dir_block, "call ext4_handle_dirty_metadata");
 	err = ext4_handle_dirty_metadata(handle, dir, dir_block);
 	if (err)
@@ -2214,7 +2214,7 @@ static int ext4_unlink(struct inode *dir, struct dentry *dentry)
 		ext4_warning(inode->i_sb,
 			     "Deleting nonexistent file (%lu), %d",
 			     inode->i_ino, inode->i_nlink);
-		inode->i_nlink = 1;
+		set_nlink(inode, 1);
 	}
 	retval = ext4_delete_entry(handle, dir, de, bh);
 	if (retval)
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index 1726d73..808cac7 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -379,7 +379,7 @@ static int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
 			return error;
 		MSDOS_I(inode)->mmu_private = inode->i_size;
 
-		inode->i_nlink = fat_subdirs(inode);
+		set_nlink(inode, fat_subdirs(inode));
 	} else { /* not a directory */
 		inode->i_generation |= 1;
 		inode->i_mode = fat_make_mode(sbi, de->attr,
@@ -1233,7 +1233,7 @@ static int fat_read_root(struct inode *inode)
 	fat_save_attrs(inode, ATTR_DIR);
 	inode->i_mtime.tv_sec = inode->i_atime.tv_sec = inode->i_ctime.tv_sec = 0;
 	inode->i_mtime.tv_nsec = inode->i_atime.tv_nsec = inode->i_ctime.tv_nsec = 0;
-	inode->i_nlink = fat_subdirs(inode)+2;
+	set_nlink(inode, fat_subdirs(inode)+2);
 
 	return 0;
 }
diff --git a/fs/fat/namei_msdos.c b/fs/fat/namei_msdos.c
index 66e83b8..216b419 100644
--- a/fs/fat/namei_msdos.c
+++ b/fs/fat/namei_msdos.c
@@ -387,7 +387,7 @@ static int msdos_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 		/* the directory was completed, just return a error */
 		goto out;
 	}
-	inode->i_nlink = 2;
+	set_nlink(inode, 2);
 	inode->i_mtime = inode->i_atime = inode->i_ctime = ts;
 	/* timestamp is already written, so mark_inode_dirty() is unneeded. */
 
diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c
index bb3f29c..a87a656 100644
--- a/fs/fat/namei_vfat.c
+++ b/fs/fat/namei_vfat.c
@@ -900,7 +900,7 @@ static int vfat_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 		goto out;
 	}
 	inode->i_version++;
-	inode->i_nlink = 2;
+	set_nlink(inode, 2);
 	inode->i_mtime = inode->i_atime = inode->i_ctime = ts;
 	/* timestamp is already written, so mark_inode_dirty() is unneeded. */
 
diff --git a/fs/freevxfs/vxfs_inode.c b/fs/freevxfs/vxfs_inode.c
index 1a43114..7b2af5a 100644
--- a/fs/freevxfs/vxfs_inode.c
+++ b/fs/freevxfs/vxfs_inode.c
@@ -227,7 +227,7 @@ vxfs_iinit(struct inode *ip, struct vxfs_inode_info *vip)
 	ip->i_uid = (uid_t)vip->vii_uid;
 	ip->i_gid = (gid_t)vip->vii_gid;
 
-	ip->i_nlink = vip->vii_nlink;
+	set_nlink(ip, vip->vii_nlink);
 	ip->i_size = vip->vii_size;
 
 	ip->i_atime.tv_sec = vip->vii_atime;
diff --git a/fs/fuse/control.c b/fs/fuse/control.c
index 85542a7..42593c5 100644
--- a/fs/fuse/control.c
+++ b/fs/fuse/control.c
@@ -231,7 +231,7 @@ static struct dentry *fuse_ctl_add_dentry(struct dentry *parent,
 	if (iop)
 		inode->i_op = iop;
 	inode->i_fop = fop;
-	inode->i_nlink = nlink;
+	set_nlink(inode, nlink);
 	inode->i_private = fc;
 	d_add(dentry, inode);
 	return dentry;
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index add96f6..3e6d727 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -151,7 +151,7 @@ void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr,
 
 	inode->i_ino     = attr->ino;
 	inode->i_mode    = (inode->i_mode & S_IFMT) | (attr->mode & 07777);
-	inode->i_nlink   = attr->nlink;
+	set_nlink(inode, attr->nlink);
 	inode->i_uid     = attr->uid;
 	inode->i_gid     = attr->gid;
 	inode->i_blocks  = attr->blocks;
diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c
index da21eca..102cf5e 100644
--- a/fs/gfs2/glops.c
+++ b/fs/gfs2/glops.c
@@ -277,7 +277,7 @@ static void gfs2_set_nlink(struct inode *inode, u32 nlink)
 		if (nlink == 0)
 			clear_nlink(inode);
 		else
-			inode->i_nlink = nlink;
+			set_nlink(inode, nlink);
 	}
 }
 
diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c
index 96a1b62..a1a9fdc 100644
--- a/fs/hfs/inode.c
+++ b/fs/hfs/inode.c
@@ -183,7 +183,7 @@ struct inode *hfs_new_inode(struct inode *dir, struct qstr *name, int mode)
 	inode->i_mode = mode;
 	inode->i_uid = current_fsuid();
 	inode->i_gid = current_fsgid();
-	inode->i_nlink = 1;
+	set_nlink(inode, 1);
 	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
 	HFS_I(inode)->flags = 0;
 	HFS_I(inode)->rsrc_inode = NULL;
@@ -313,7 +313,7 @@ static int hfs_read_inode(struct inode *inode, void *data)
 	/* Initialize the inode */
 	inode->i_uid = hsb->s_uid;
 	inode->i_gid = hsb->s_gid;
-	inode->i_nlink = 1;
+	set_nlink(inode, 1);
 
 	if (idata->key)
 		HFS_I(inode)->cat_key = *idata->key;
diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c
index 4cc1e3a..40e1413 100644
--- a/fs/hfsplus/inode.c
+++ b/fs/hfsplus/inode.c
@@ -391,7 +391,7 @@ struct inode *hfsplus_new_inode(struct super_block *sb, int mode)
 	inode->i_mode = mode;
 	inode->i_uid = current_fsuid();
 	inode->i_gid = current_fsgid();
-	inode->i_nlink = 1;
+	set_nlink(inode, 1);
 	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
 
 	hip = HFSPLUS_I(inode);
@@ -512,7 +512,7 @@ int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd)
 		hfs_bnode_read(fd->bnode, &entry, fd->entryoffset,
 					sizeof(struct hfsplus_cat_folder));
 		hfsplus_get_perms(inode, &folder->permissions, 1);
-		inode->i_nlink = 1;
+		set_nlink(inode, 1);
 		inode->i_size = 2 + be32_to_cpu(folder->valence);
 		inode->i_atime = hfsp_mt2ut(folder->access_date);
 		inode->i_mtime = hfsp_mt2ut(folder->content_mod_date);
@@ -532,11 +532,11 @@ int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd)
 		hfsplus_inode_read_fork(inode, HFSPLUS_IS_RSRC(inode) ?
 					&file->rsrc_fork : &file->data_fork);
 		hfsplus_get_perms(inode, &file->permissions, 0);
-		inode->i_nlink = 1;
+		set_nlink(inode, 1);
 		if (S_ISREG(inode->i_mode)) {
 			if (file->permissions.dev)
-				inode->i_nlink =
-					be32_to_cpu(file->permissions.dev);
+				set_nlink(inode,
+					  be32_to_cpu(file->permissions.dev));
 			inode->i_op = &hfsplus_file_inode_operations;
 			inode->i_fop = &hfsplus_file_operations;
 			inode->i_mapping->a_ops = &hfsplus_aops;
diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c
index 0d22afd..2f72da5 100644
--- a/fs/hostfs/hostfs_kern.c
+++ b/fs/hostfs/hostfs_kern.c
@@ -541,7 +541,7 @@ static int read_name(struct inode *ino, char *name)
 
 	ino->i_ino = st.ino;
 	ino->i_mode = st.mode;
-	ino->i_nlink = st.nlink;
+	set_nlink(ino, st.nlink);
 	ino->i_uid = st.uid;
 	ino->i_gid = st.gid;
 	ino->i_atime = st.atime;
diff --git a/fs/hpfs/dir.c b/fs/hpfs/dir.c
index 96a8ed9..2fa0089 100644
--- a/fs/hpfs/dir.c
+++ b/fs/hpfs/dir.c
@@ -247,7 +247,7 @@ struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry, struct name
 			result->i_mode &= ~0111;
 			result->i_op = &hpfs_file_iops;
 			result->i_fop = &hpfs_file_ops;
-			result->i_nlink = 1;
+			set_nlink(result, 1);
 		}
 		unlock_new_inode(result);
 	}
diff --git a/fs/hpfs/inode.c b/fs/hpfs/inode.c
index dfe800c..3b2cec2 100644
--- a/fs/hpfs/inode.c
+++ b/fs/hpfs/inode.c
@@ -77,7 +77,7 @@ void hpfs_read_inode(struct inode *i)
 			i->i_mode = S_IFLNK | 0777;
 			i->i_op = &page_symlink_inode_operations;
 			i->i_data.a_ops = &hpfs_symlink_aops;
-			i->i_nlink = 1;
+			set_nlink(i, 1);
 			i->i_size = ea_size;
 			i->i_blocks = 1;
 			brelse(bh);
@@ -101,7 +101,7 @@ void hpfs_read_inode(struct inode *i)
 			}
 			if (S_ISBLK(mode) || S_ISCHR(mode) || S_ISFIFO(mode) || S_ISSOCK(mode)) {
 				brelse(bh);
-				i->i_nlink = 1;
+				set_nlink(i, 1);
 				i->i_size = 0;
 				i->i_blocks = 1;
 				init_special_inode(i, mode,
@@ -125,13 +125,13 @@ void hpfs_read_inode(struct inode *i)
 		hpfs_count_dnodes(i->i_sb, hpfs_inode->i_dno, &n_dnodes, &n_subdirs, NULL);
 		i->i_blocks = 4 * n_dnodes;
 		i->i_size = 2048 * n_dnodes;
-		i->i_nlink = 2 + n_subdirs;
+		set_nlink(i, 2 + n_subdirs);
 	} else {
 		i->i_mode |= S_IFREG;
 		if (!hpfs_inode->i_ea_mode) i->i_mode &= ~0111;
 		i->i_op = &hpfs_file_iops;
 		i->i_fop = &hpfs_file_ops;
-		i->i_nlink = 1;
+		set_nlink(i, 1);
 		i->i_size = le32_to_cpu(fnode->file_size);
 		i->i_blocks = ((i->i_size + 511) >> 9) + 1;
 		i->i_data.a_ops = &hpfs_aops;
diff --git a/fs/hpfs/namei.c b/fs/hpfs/namei.c
index 2df69e2..ea91fcb 100644
--- a/fs/hpfs/namei.c
+++ b/fs/hpfs/namei.c
@@ -56,7 +56,7 @@ static int hpfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 	result->i_fop = &hpfs_dir_ops;
 	result->i_blocks = 4;
 	result->i_size = 2048;
-	result->i_nlink = 2;
+	set_nlink(result, 2);
 	if (dee.read_only)
 		result->i_mode &= ~0222;
 
@@ -150,7 +150,7 @@ static int hpfs_create(struct inode *dir, struct dentry *dentry, int mode, struc
 	result->i_mode &= ~0111;
 	result->i_op = &hpfs_file_iops;
 	result->i_fop = &hpfs_file_ops;
-	result->i_nlink = 1;
+	set_nlink(result, 1);
 	hpfs_i(result)->i_parent_dir = dir->i_ino;
 	result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, le32_to_cpu(dee.creation_date));
 	result->i_ctime.tv_nsec = 0;
@@ -242,7 +242,7 @@ static int hpfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t
 	hpfs_i(result)->i_ea_size = 0;
 	result->i_uid = current_fsuid();
 	result->i_gid = current_fsgid();
-	result->i_nlink = 1;
+	set_nlink(result, 1);
 	result->i_size = 0;
 	result->i_blocks = 1;
 	init_special_inode(result, mode, rdev);
@@ -318,7 +318,7 @@ static int hpfs_symlink(struct inode *dir, struct dentry *dentry, const char *sy
 	result->i_uid = current_fsuid();
 	result->i_gid = current_fsgid();
 	result->i_blocks = 1;
-	result->i_nlink = 1;
+	set_nlink(result, 1);
 	result->i_size = strlen(symlink);
 	result->i_op = &page_symlink_inode_operations;
 	result->i_data.a_ops = &hpfs_symlink_aops;
diff --git a/fs/hppfs/hppfs.c b/fs/hppfs/hppfs.c
index 970ea98..f590b11 100644
--- a/fs/hppfs/hppfs.c
+++ b/fs/hppfs/hppfs.c
@@ -702,7 +702,7 @@ static struct inode *get_inode(struct super_block *sb, struct dentry *dentry)
 	inode->i_ctime = proc_ino->i_ctime;
 	inode->i_ino = proc_ino->i_ino;
 	inode->i_mode = proc_ino->i_mode;
-	inode->i_nlink = proc_ino->i_nlink;
+	set_nlink(inode, proc_ino->i_nlink);
 	inode->i_size = proc_ino->i_size;
 	inode->i_blocks = proc_ino->i_blocks;
 
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
index a5d0367..562adab 100644
--- a/fs/isofs/inode.c
+++ b/fs/isofs/inode.c
@@ -1319,7 +1319,7 @@ static int isofs_read_inode(struct inode *inode)
 			inode->i_mode = S_IFDIR | sbi->s_dmode;
 		else
 			inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
-		inode->i_nlink = 1;	/*
+		set_nlink(inode, 1);	/*
 					 * Set to 1.  We know there are 2, but
 					 * the find utility tries to optimize
 					 * if it is 2, and it screws up.  It is
@@ -1337,7 +1337,7 @@ static int isofs_read_inode(struct inode *inode)
 			 */
 			inode->i_mode = S_IFREG | S_IRUGO | S_IXUGO;
 		}
-		inode->i_nlink = 1;
+		set_nlink(inode, 1);
 	}
 	inode->i_uid = sbi->s_uid;
 	inode->i_gid = sbi->s_gid;
diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c
index 1fbc7de..70e79d0 100644
--- a/fs/isofs/rock.c
+++ b/fs/isofs/rock.c
@@ -363,7 +363,7 @@ repeat:
 			break;
 		case SIG('P', 'X'):
 			inode->i_mode = isonum_733(rr->u.PX.mode);
-			inode->i_nlink = isonum_733(rr->u.PX.n_links);
+			set_nlink(inode, isonum_733(rr->u.PX.n_links));
 			inode->i_uid = isonum_733(rr->u.PX.uid);
 			inode->i_gid = isonum_733(rr->u.PX.gid);
 			break;
@@ -496,7 +496,7 @@ repeat:
 				goto out;
 			}
 			inode->i_mode = reloc->i_mode;
-			inode->i_nlink = reloc->i_nlink;
+			set_nlink(inode, reloc->i_nlink);
 			inode->i_uid = reloc->i_uid;
 			inode->i_gid = reloc->i_gid;
 			inode->i_rdev = reloc->i_rdev;
diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c
index 9659b7c..be6169b 100644
--- a/fs/jffs2/dir.c
+++ b/fs/jffs2/dir.c
@@ -245,7 +245,7 @@ static int jffs2_unlink(struct inode *dir_i, struct dentry *dentry)
 	ret = jffs2_do_unlink(c, dir_f, dentry->d_name.name,
 			      dentry->d_name.len, dead_f, now);
 	if (dead_f->inocache)
-		dentry->d_inode->i_nlink = dead_f->inocache->pino_nlink;
+		set_nlink(dentry->d_inode, dead_f->inocache->pino_nlink);
 	if (!ret)
 		dir_i->i_mtime = dir_i->i_ctime = ITIME(now);
 	return ret;
@@ -278,7 +278,7 @@ static int jffs2_link (struct dentry *old_dentry, struct inode *dir_i, struct de
 
 	if (!ret) {
 		mutex_lock(&f->sem);
-		old_dentry->d_inode->i_nlink = ++f->inocache->pino_nlink;
+		set_nlink(old_dentry->d_inode, ++f->inocache->pino_nlink);
 		mutex_unlock(&f->sem);
 		d_instantiate(dentry, old_dentry->d_inode);
 		dir_i->i_mtime = dir_i->i_ctime = ITIME(now);
@@ -497,7 +497,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
 	f = JFFS2_INODE_INFO(inode);
 
 	/* Directories get nlink 2 at start */
-	inode->i_nlink = 2;
+	set_nlink(inode, 2);
 	/* but ic->pino_nlink is the parent ino# */
 	f->inocache->pino_nlink = dir_i->i_ino;
 
diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c
index bbcb975..7286e44 100644
--- a/fs/jffs2/fs.c
+++ b/fs/jffs2/fs.c
@@ -278,7 +278,7 @@ struct inode *jffs2_iget(struct super_block *sb, unsigned long ino)
 	inode->i_mtime = ITIME(je32_to_cpu(latest_node.mtime));
 	inode->i_ctime = ITIME(je32_to_cpu(latest_node.ctime));
 
-	inode->i_nlink = f->inocache->pino_nlink;
+	set_nlink(inode, f->inocache->pino_nlink);
 
 	inode->i_blocks = (inode->i_size + 511) >> 9;
 
@@ -291,7 +291,7 @@ struct inode *jffs2_iget(struct super_block *sb, unsigned long ino)
 	case S_IFDIR:
 	{
 		struct jffs2_full_dirent *fd;
-		inode->i_nlink = 2; /* parent and '.' */
+		set_nlink(inode, 2); /* parent and '.' */
 
 		for (fd=f->dents; fd; fd = fd->next) {
 			if (fd->type == DT_DIR && fd->ino)
@@ -453,7 +453,7 @@ struct inode *jffs2_new_inode (struct inode *dir_i, umode_t mode, struct jffs2_r
 		iput(inode);
 		return ERR_PTR(ret);
 	}
-	inode->i_nlink = 1;
+	set_nlink(inode, 1);
 	inode->i_ino = je32_to_cpu(ri->ino);
 	inode->i_mode = jemode_to_cpu(ri->mode);
 	inode->i_gid = je16_to_cpu(ri->gid);
diff --git a/fs/jfs/jfs_imap.c b/fs/jfs/jfs_imap.c
index b78b2f9..1b6f15f 100644
--- a/fs/jfs/jfs_imap.c
+++ b/fs/jfs/jfs_imap.c
@@ -457,7 +457,7 @@ struct inode *diReadSpecial(struct super_block *sb, ino_t inum, int secondary)
 	/* read the page of fixed disk inode (AIT) in raw mode */
 	mp = read_metapage(ip, address << sbi->l2nbperpage, PSIZE, 1);
 	if (mp == NULL) {
-		ip->i_nlink = 1;	/* Don't want iput() deleting it */
+		set_nlink(ip, 1);	/* Don't want iput() deleting it */
 		iput(ip);
 		return (NULL);
 	}
@@ -469,7 +469,7 @@ struct inode *diReadSpecial(struct super_block *sb, ino_t inum, int secondary)
 	/* copy on-disk inode to in-memory inode */
 	if ((copy_from_dinode(dp, ip)) != 0) {
 		/* handle bad return by returning NULL for ip */
-		ip->i_nlink = 1;	/* Don't want iput() deleting it */
+		set_nlink(ip, 1);	/* Don't want iput() deleting it */
 		iput(ip);
 		/* release the page */
 		release_metapage(mp);
@@ -3076,7 +3076,7 @@ static int copy_from_dinode(struct dinode * dip, struct inode *ip)
 				ip->i_mode |= 0001;
 		}
 	}
-	ip->i_nlink = le32_to_cpu(dip->di_nlink);
+	set_nlink(ip, le32_to_cpu(dip->di_nlink));
 
 	jfs_ip->saved_uid = le32_to_cpu(dip->di_uid);
 	if (sbi->uid == -1)
diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c
index 94b0a62..a112ad9 100644
--- a/fs/jfs/namei.c
+++ b/fs/jfs/namei.c
@@ -292,7 +292,7 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode)
 		goto out3;
 	}
 
-	ip->i_nlink = 2;	/* for '.' */
+	set_nlink(ip, 2);	/* for '.' */
 	ip->i_op = &jfs_dir_inode_operations;
 	ip->i_fop = &jfs_dir_operations;
 
diff --git a/fs/libfs.c b/fs/libfs.c
index c18e9a1..fe3ec42 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -490,7 +490,7 @@ int simple_fill_super(struct super_block *s, unsigned long magic,
 	inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 	inode->i_op = &simple_dir_inode_operations;
 	inode->i_fop = &simple_dir_operations;
-	inode->i_nlink = 2;
+	set_nlink(inode, 2);
 	root = d_alloc_root(inode);
 	if (!root) {
 		iput(inode);
diff --git a/fs/logfs/readwrite.c b/fs/logfs/readwrite.c
index d8d0938..2ac4217 100644
--- a/fs/logfs/readwrite.c
+++ b/fs/logfs/readwrite.c
@@ -126,7 +126,7 @@ static void logfs_disk_to_inode(struct logfs_disk_inode *di, struct inode*inode)
 	inode->i_atime	= be64_to_timespec(di->di_atime);
 	inode->i_ctime	= be64_to_timespec(di->di_ctime);
 	inode->i_mtime	= be64_to_timespec(di->di_mtime);
-	inode->i_nlink	= be32_to_cpu(di->di_refcount);
+	set_nlink(inode, be32_to_cpu(di->di_refcount));
 	inode->i_generation = be32_to_cpu(di->di_generation);
 
 	switch (inode->i_mode & S_IFMT) {
diff --git a/fs/minix/inode.c b/fs/minix/inode.c
index e7d23e2..64cdcd6 100644
--- a/fs/minix/inode.c
+++ b/fs/minix/inode.c
@@ -446,7 +446,7 @@ static struct inode *V1_minix_iget(struct inode *inode)
 	inode->i_mode = raw_inode->i_mode;
 	inode->i_uid = (uid_t)raw_inode->i_uid;
 	inode->i_gid = (gid_t)raw_inode->i_gid;
-	inode->i_nlink = raw_inode->i_nlinks;
+	set_nlink(inode, raw_inode->i_nlinks);
 	inode->i_size = raw_inode->i_size;
 	inode->i_mtime.tv_sec = inode->i_atime.tv_sec = inode->i_ctime.tv_sec = raw_inode->i_time;
 	inode->i_mtime.tv_nsec = 0;
@@ -479,7 +479,7 @@ static struct inode *V2_minix_iget(struct inode *inode)
 	inode->i_mode = raw_inode->i_mode;
 	inode->i_uid = (uid_t)raw_inode->i_uid;
 	inode->i_gid = (gid_t)raw_inode->i_gid;
-	inode->i_nlink = raw_inode->i_nlinks;
+	set_nlink(inode, raw_inode->i_nlinks);
 	inode->i_size = raw_inode->i_size;
 	inode->i_mtime.tv_sec = raw_inode->i_mtime;
 	inode->i_atime.tv_sec = raw_inode->i_atime;
diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c
index 202f370..5b5fa33 100644
--- a/fs/ncpfs/inode.c
+++ b/fs/ncpfs/inode.c
@@ -228,7 +228,7 @@ static void ncp_set_attr(struct inode *inode, struct ncp_entry_info *nwinfo)
 
 	DDPRINTK("ncp_read_inode: inode->i_mode = %u\n", inode->i_mode);
 
-	inode->i_nlink = 1;
+	set_nlink(inode, 1);
 	inode->i_uid = server->m.uid;
 	inode->i_gid = server->m.gid;
 
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 53e10ff..109dbae 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -355,7 +355,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
 				| NFS_INO_INVALID_DATA
 				| NFS_INO_REVAL_PAGECACHE;
 		if (fattr->valid & NFS_ATTR_FATTR_NLINK)
-			inode->i_nlink = fattr->nlink;
+			set_nlink(inode, fattr->nlink);
 		else if (nfs_server_capable(inode, NFS_CAP_NLINK))
 			nfsi->cache_validity |= NFS_INO_INVALID_ATTR;
 		if (fattr->valid & NFS_ATTR_FATTR_OWNER)
@@ -1361,7 +1361,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
 			invalid |= NFS_INO_INVALID_ATTR;
 			if (S_ISDIR(inode->i_mode))
 				invalid |= NFS_INO_INVALID_DATA;
-			inode->i_nlink = fattr->nlink;
+			set_nlink(inode, fattr->nlink);
 		}
 	} else if (server->caps & NFS_CAP_NLINK)
 		invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR
diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c
index 08ac272..b50ffb7 100644
--- a/fs/nilfs2/inode.c
+++ b/fs/nilfs2/inode.c
@@ -396,7 +396,7 @@ int nilfs_read_inode_common(struct inode *inode,
 	inode->i_mode = le16_to_cpu(raw_inode->i_mode);
 	inode->i_uid = (uid_t)le32_to_cpu(raw_inode->i_uid);
 	inode->i_gid = (gid_t)le32_to_cpu(raw_inode->i_gid);
-	inode->i_nlink = le16_to_cpu(raw_inode->i_links_count);
+	set_nlink(inode, le16_to_cpu(raw_inode->i_links_count));
 	inode->i_size = le64_to_cpu(raw_inode->i_size);
 	inode->i_atime.tv_sec = le64_to_cpu(raw_inode->i_mtime);
 	inode->i_ctime.tv_sec = le64_to_cpu(raw_inode->i_ctime);
diff --git a/fs/nilfs2/namei.c b/fs/nilfs2/namei.c
index a314199..768982d 100644
--- a/fs/nilfs2/namei.c
+++ b/fs/nilfs2/namei.c
@@ -289,7 +289,7 @@ static int nilfs_do_unlink(struct inode *dir, struct dentry *dentry)
 		nilfs_warning(inode->i_sb, __func__,
 			      "deleting nonexistent file (%lu), %d\n",
 			      inode->i_ino, inode->i_nlink);
-		inode->i_nlink = 1;
+		set_nlink(inode, 1);
 	}
 	err = nilfs_delete_entry(de, page);
 	if (err)
diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c
index 1371487..97e2dac 100644
--- a/fs/ntfs/inode.c
+++ b/fs/ntfs/inode.c
@@ -612,7 +612,7 @@ static int ntfs_read_locked_inode(struct inode *vi)
 	 * might be tricky due to vfs interactions. Need to think about this
 	 * some more when implementing the unlink command.
 	 */
-	vi->i_nlink = le16_to_cpu(m->link_count);
+	set_nlink(vi, le16_to_cpu(m->link_count));
 	/*
 	 * FIXME: Reparse points can have the directory bit set even though
 	 * they would be S_IFLNK. Need to deal with this further below when we
@@ -634,7 +634,7 @@ static int ntfs_read_locked_inode(struct inode *vi)
 		vi->i_mode &= ~vol->dmask;
 		/* Things break without this kludge! */
 		if (vi->i_nlink > 1)
-			vi->i_nlink = 1;
+			set_nlink(vi, 1);
 	} else {
 		vi->i_mode |= S_IFREG;
 		/* Apply the file permissions mask set in the mount options. */
@@ -1242,7 +1242,7 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
 	vi->i_version	= base_vi->i_version;
 	vi->i_uid	= base_vi->i_uid;
 	vi->i_gid	= base_vi->i_gid;
-	vi->i_nlink	= base_vi->i_nlink;
+	set_nlink(vi, base_vi->i_nlink);
 	vi->i_mtime	= base_vi->i_mtime;
 	vi->i_ctime	= base_vi->i_ctime;
 	vi->i_atime	= base_vi->i_atime;
@@ -1508,7 +1508,7 @@ static int ntfs_read_locked_index_inode(struct inode *base_vi, struct inode *vi)
 	vi->i_version	= base_vi->i_version;
 	vi->i_uid	= base_vi->i_uid;
 	vi->i_gid	= base_vi->i_gid;
-	vi->i_nlink	= base_vi->i_nlink;
+	set_nlink(vi, base_vi->i_nlink);
 	vi->i_mtime	= base_vi->i_mtime;
 	vi->i_ctime	= base_vi->i_ctime;
 	vi->i_atime	= base_vi->i_atime;
diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c
index 8582e3f..e2878b5 100644
--- a/fs/ocfs2/dir.c
+++ b/fs/ocfs2/dir.c
@@ -2292,7 +2292,7 @@ static int ocfs2_fill_new_dir_id(struct ocfs2_super *osb,
 	ocfs2_journal_dirty(handle, di_bh);
 
 	i_size_write(inode, size);
-	inode->i_nlink = 2;
+	set_nlink(inode, 2);
 	inode->i_blocks = ocfs2_inode_sector_count(inode);
 
 	ret = ocfs2_mark_inode_dirty(handle, inode, di_bh);
@@ -2354,7 +2354,7 @@ static int ocfs2_fill_new_dir_el(struct ocfs2_super *osb,
 	ocfs2_journal_dirty(handle, new_bh);
 
 	i_size_write(inode, inode->i_sb->s_blocksize);
-	inode->i_nlink = 2;
+	set_nlink(inode, 2);
 	inode->i_blocks = ocfs2_inode_sector_count(inode);
 	status = ocfs2_mark_inode_dirty(handle, inode, fe_bh);
 	if (status < 0) {
diff --git a/fs/ocfs2/dlmglue.c b/fs/ocfs2/dlmglue.c
index 7642d7c..e1ed5e5 100644
--- a/fs/ocfs2/dlmglue.c
+++ b/fs/ocfs2/dlmglue.c
@@ -2092,7 +2092,7 @@ static void ocfs2_refresh_inode_from_lvb(struct inode *inode)
 	inode->i_uid     = be32_to_cpu(lvb->lvb_iuid);
 	inode->i_gid     = be32_to_cpu(lvb->lvb_igid);
 	inode->i_mode    = be16_to_cpu(lvb->lvb_imode);
-	inode->i_nlink   = be16_to_cpu(lvb->lvb_inlink);
+	set_nlink(inode, be16_to_cpu(lvb->lvb_inlink));
 	ocfs2_unpack_timespec(&inode->i_atime,
 			      be64_to_cpu(lvb->lvb_iatime_packed));
 	ocfs2_unpack_timespec(&inode->i_mtime,
diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c
index b4c8bb6..a22d2c0 100644
--- a/fs/ocfs2/inode.c
+++ b/fs/ocfs2/inode.c
@@ -291,7 +291,7 @@ void ocfs2_populate_inode(struct inode *inode, struct ocfs2_dinode *fe,
 		     (unsigned long long)OCFS2_I(inode)->ip_blkno,
 		     (unsigned long long)le64_to_cpu(fe->i_blkno));
 
-	inode->i_nlink = ocfs2_read_links_count(fe);
+	set_nlink(inode, ocfs2_read_links_count(fe));
 
 	trace_ocfs2_populate_inode(OCFS2_I(inode)->ip_blkno,
 				   le32_to_cpu(fe->i_flags));
@@ -1290,7 +1290,7 @@ void ocfs2_refresh_inode(struct inode *inode,
 	OCFS2_I(inode)->ip_dyn_features = le16_to_cpu(fe->i_dyn_features);
 	ocfs2_set_inode_flags(inode);
 	i_size_write(inode, le64_to_cpu(fe->i_size));
-	inode->i_nlink = ocfs2_read_links_count(fe);
+	set_nlink(inode, ocfs2_read_links_count(fe));
 	inode->i_uid = le32_to_cpu(fe->i_uid);
 	inode->i_gid = le32_to_cpu(fe->i_gid);
 	inode->i_mode = le16_to_cpu(fe->i_mode);
diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c
index ea0ecbd..a8b2bfe 100644
--- a/fs/ocfs2/namei.c
+++ b/fs/ocfs2/namei.c
@@ -199,7 +199,7 @@ static struct inode *ocfs2_get_init_inode(struct inode *dir, int mode)
 	 * these are used by the support functions here and in
 	 * callers. */
 	if (S_ISDIR(mode))
-		inode->i_nlink = 2;
+		set_nlink(inode, 2);
 	inode_init_owner(inode, dir, mode);
 	dquot_initialize(inode);
 	return inode;
@@ -2016,7 +2016,7 @@ static int ocfs2_orphan_add(struct ocfs2_super *osb,
 	orphan_fe = (struct ocfs2_dinode *) orphan_dir_bh->b_data;
 	if (S_ISDIR(inode->i_mode))
 		ocfs2_add_links_count(orphan_fe, 1);
-	orphan_dir_inode->i_nlink = ocfs2_read_links_count(orphan_fe);
+	set_nlink(orphan_dir_inode, ocfs2_read_links_count(orphan_fe));
 	ocfs2_journal_dirty(handle, orphan_dir_bh);
 
 	status = __ocfs2_add_entry(handle, orphan_dir_inode, name,
@@ -2114,7 +2114,7 @@ int ocfs2_orphan_del(struct ocfs2_super *osb,
 	orphan_fe = (struct ocfs2_dinode *) orphan_dir_bh->b_data;
 	if (S_ISDIR(inode->i_mode))
 		ocfs2_add_links_count(orphan_fe, -1);
-	orphan_dir_inode->i_nlink = ocfs2_read_links_count(orphan_fe);
+	set_nlink(orphan_dir_inode, ocfs2_read_links_count(orphan_fe));
 	ocfs2_journal_dirty(handle, orphan_dir_bh);
 
 leave:
@@ -2435,7 +2435,7 @@ int ocfs2_mv_orphaned_inode_to_new(struct inode *dir,
 	di = (struct ocfs2_dinode *)di_bh->b_data;
 	le32_add_cpu(&di->i_flags, -OCFS2_ORPHANED_FL);
 	di->i_orphaned_slot = 0;
-	inode->i_nlink = 1;
+	set_nlink(inode, 1);
 	ocfs2_set_links_count(di, inode->i_nlink);
 	ocfs2_journal_dirty(handle, di_bh);
 
diff --git a/fs/openpromfs/inode.c b/fs/openpromfs/inode.c
index a2a5bff..e4e0ff7 100644
--- a/fs/openpromfs/inode.c
+++ b/fs/openpromfs/inode.c
@@ -242,7 +242,7 @@ found:
 		inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
 		inode->i_op = &openprom_inode_operations;
 		inode->i_fop = &openprom_operations;
-		inode->i_nlink = 2;
+		set_nlink(inode, 2);
 		break;
 	case op_inode_prop:
 		if (!strcmp(dp->name, "options") && (len == 17) &&
@@ -251,7 +251,7 @@ found:
 		else
 			inode->i_mode = S_IFREG | S_IRUGO;
 		inode->i_fop = &openpromfs_prop_ops;
-		inode->i_nlink = 1;
+		set_nlink(inode, 1);
 		inode->i_size = ent_oi->u.prop->length;
 		break;
 	}
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 5eb0206..1f2ae7d 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -2261,7 +2261,7 @@ static struct dentry *proc_pident_instantiate(struct inode *dir,
 	ei = PROC_I(inode);
 	inode->i_mode = p->mode;
 	if (S_ISDIR(inode->i_mode))
-		inode->i_nlink = 2;	/* Use getattr to fix if necessary */
+		set_nlink(inode, 2);	/* Use getattr to fix if necessary */
 	if (p->iop)
 		inode->i_op = p->iop;
 	if (p->fop)
@@ -2655,7 +2655,7 @@ static struct dentry *proc_base_instantiate(struct inode *dir,
 
 	inode->i_mode = p->mode;
 	if (S_ISDIR(inode->i_mode))
-		inode->i_nlink = 2;
+		set_nlink(inode, 2);
 	if (S_ISLNK(inode->i_mode))
 		inode->i_size = 64;
 	if (p->iop)
@@ -2994,8 +2994,8 @@ static struct dentry *proc_pid_instantiate(struct inode *dir,
 	inode->i_fop = &proc_tgid_base_operations;
 	inode->i_flags|=S_IMMUTABLE;
 
-	inode->i_nlink = 2 + pid_entry_count_dirs(tgid_base_stuff,
-		ARRAY_SIZE(tgid_base_stuff));
+	set_nlink(inode, 2 + pid_entry_count_dirs(tgid_base_stuff,
+						  ARRAY_SIZE(tgid_base_stuff)));
 
 	d_set_d_op(dentry, &pid_dentry_operations);
 
@@ -3246,8 +3246,8 @@ static struct dentry *proc_task_instantiate(struct inode *dir,
 	inode->i_fop = &proc_tid_base_operations;
 	inode->i_flags|=S_IMMUTABLE;
 
-	inode->i_nlink = 2 + pid_entry_count_dirs(tid_base_stuff,
-		ARRAY_SIZE(tid_base_stuff));
+	set_nlink(inode, 2 + pid_entry_count_dirs(tid_base_stuff,
+						  ARRAY_SIZE(tid_base_stuff)));
 
 	d_set_d_op(dentry, &pid_dentry_operations);
 
diff --git a/fs/proc/generic.c b/fs/proc/generic.c
index 9d99131..10090d9 100644
--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -283,7 +283,7 @@ static int proc_getattr(struct vfsmount *mnt, struct dentry *dentry,
 	struct inode *inode = dentry->d_inode;
 	struct proc_dir_entry *de = PROC_I(inode)->pde;
 	if (de && de->nlink)
-		inode->i_nlink = de->nlink;
+		set_nlink(inode, de->nlink);
 
 	generic_fillattr(inode, stat);
 	return 0;
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index 7ed72d6..7737c54 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -445,7 +445,7 @@ struct inode *proc_get_inode(struct super_block *sb, struct proc_dir_entry *de)
 		if (de->size)
 			inode->i_size = de->size;
 		if (de->nlink)
-			inode->i_nlink = de->nlink;
+			set_nlink(inode, de->nlink);
 		if (de->proc_iops)
 			inode->i_op = de->proc_iops;
 		if (de->proc_fops) {
diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c
index 2b06466..3bdd214 100644
--- a/fs/qnx4/inode.c
+++ b/fs/qnx4/inode.c
@@ -379,7 +379,7 @@ struct inode *qnx4_iget(struct super_block *sb, unsigned long ino)
 	inode->i_mode    = le16_to_cpu(raw_inode->di_mode);
 	inode->i_uid     = (uid_t)le16_to_cpu(raw_inode->di_uid);
 	inode->i_gid     = (gid_t)le16_to_cpu(raw_inode->di_gid);
-	inode->i_nlink   = le16_to_cpu(raw_inode->di_nlink);
+	set_nlink(inode, le16_to_cpu(raw_inode->di_nlink));
 	inode->i_size    = le32_to_cpu(raw_inode->di_size);
 	inode->i_mtime.tv_sec   = le32_to_cpu(raw_inode->di_mtime);
 	inode->i_mtime.tv_nsec = 0;
diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c
index c425441..950f13a 100644
--- a/fs/reiserfs/inode.c
+++ b/fs/reiserfs/inode.c
@@ -1154,7 +1154,7 @@ static void init_inode(struct inode *inode, struct treepath *path)
 		set_inode_item_key_version(inode, KEY_FORMAT_3_5);
 		set_inode_sd_version(inode, STAT_DATA_V1);
 		inode->i_mode = sd_v1_mode(sd);
-		inode->i_nlink = sd_v1_nlink(sd);
+		set_nlink(inode, sd_v1_nlink(sd));
 		inode->i_uid = sd_v1_uid(sd);
 		inode->i_gid = sd_v1_gid(sd);
 		inode->i_size = sd_v1_size(sd);
@@ -1199,7 +1199,7 @@ static void init_inode(struct inode *inode, struct treepath *path)
 		struct stat_data *sd = (struct stat_data *)B_I_PITEM(bh, ih);
 
 		inode->i_mode = sd_v2_mode(sd);
-		inode->i_nlink = sd_v2_nlink(sd);
+		set_nlink(inode, sd_v2_nlink(sd));
 		inode->i_uid = sd_v2_uid(sd);
 		inode->i_size = sd_v2_size(sd);
 		inode->i_gid = sd_v2_gid(sd);
@@ -1832,7 +1832,7 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th,
 #endif
 
 	/* fill stat data */
-	inode->i_nlink = (S_ISDIR(mode) ? 2 : 1);
+	set_nlink(inode, (S_ISDIR(mode) ? 2 : 1));
 
 	/* uid and gid must already be set by the caller for quota init */
 
diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c
index 6ce3328..80058e8 100644
--- a/fs/reiserfs/namei.c
+++ b/fs/reiserfs/namei.c
@@ -19,7 +19,7 @@
 #include <linux/reiserfs_xattr.h>
 #include <linux/quotaops.h>
 
-#define INC_DIR_INODE_NLINK(i) if (i->i_nlink != 1) { inc_nlink(i); if (i->i_nlink >= REISERFS_LINK_MAX) i->i_nlink=1; }
+#define INC_DIR_INODE_NLINK(i) if (i->i_nlink != 1) { inc_nlink(i); if (i->i_nlink >= REISERFS_LINK_MAX) set_nlink(i, 1); }
 #define DEC_DIR_INODE_NLINK(i) if (i->i_nlink != 1) drop_nlink(i);
 
 // directory item contains array of entry headers. This performs
@@ -964,7 +964,7 @@ static int reiserfs_unlink(struct inode *dir, struct dentry *dentry)
 		reiserfs_warning(inode->i_sb, "reiserfs-7042",
 				 "deleting nonexistent file (%lu), %d",
 				 inode->i_ino, inode->i_nlink);
-		inode->i_nlink = 1;
+		set_nlink(inode, 1);
 	}
 
 	drop_nlink(inode);
diff --git a/fs/romfs/super.c b/fs/romfs/super.c
index 2305e31..8b4089f 100644
--- a/fs/romfs/super.c
+++ b/fs/romfs/super.c
@@ -337,7 +337,7 @@ static struct inode *romfs_iget(struct super_block *sb, unsigned long pos)
 	inode->i_metasize = (ROMFH_SIZE + nlen + 1 + ROMFH_PAD) & ROMFH_MASK;
 	inode->i_dataoffset = pos + inode->i_metasize;
 
-	i->i_nlink = 1;		/* Hard to decide.. */
+	set_nlink(i, 1);		/* Hard to decide.. */
 	i->i_size = be32_to_cpu(ri.size);
 	i->i_mtime.tv_sec = i->i_atime.tv_sec = i->i_ctime.tv_sec = 0;
 	i->i_mtime.tv_nsec = i->i_atime.tv_nsec = i->i_ctime.tv_nsec = 0;
diff --git a/fs/squashfs/inode.c b/fs/squashfs/inode.c
index 04bebca..fd7b3b3 100644
--- a/fs/squashfs/inode.c
+++ b/fs/squashfs/inode.c
@@ -159,7 +159,7 @@ int squashfs_read_inode(struct inode *inode, long long ino)
 			frag_offset = 0;
 		}
 
-		inode->i_nlink = 1;
+		set_nlink(inode, 1);
 		inode->i_size = le32_to_cpu(sqsh_ino->file_size);
 		inode->i_fop = &generic_ro_fops;
 		inode->i_mode |= S_IFREG;
@@ -203,7 +203,7 @@ int squashfs_read_inode(struct inode *inode, long long ino)
 		}
 
 		xattr_id = le32_to_cpu(sqsh_ino->xattr);
-		inode->i_nlink = le32_to_cpu(sqsh_ino->nlink);
+		set_nlink(inode, le32_to_cpu(sqsh_ino->nlink));
 		inode->i_size = le64_to_cpu(sqsh_ino->file_size);
 		inode->i_op = &squashfs_inode_ops;
 		inode->i_fop = &generic_ro_fops;
@@ -232,7 +232,7 @@ int squashfs_read_inode(struct inode *inode, long long ino)
 		if (err < 0)
 			goto failed_read;
 
-		inode->i_nlink = le32_to_cpu(sqsh_ino->nlink);
+		set_nlink(inode, le32_to_cpu(sqsh_ino->nlink));
 		inode->i_size = le16_to_cpu(sqsh_ino->file_size);
 		inode->i_op = &squashfs_dir_inode_ops;
 		inode->i_fop = &squashfs_dir_ops;
@@ -257,7 +257,7 @@ int squashfs_read_inode(struct inode *inode, long long ino)
 			goto failed_read;
 
 		xattr_id = le32_to_cpu(sqsh_ino->xattr);
-		inode->i_nlink = le32_to_cpu(sqsh_ino->nlink);
+		set_nlink(inode, le32_to_cpu(sqsh_ino->nlink));
 		inode->i_size = le32_to_cpu(sqsh_ino->file_size);
 		inode->i_op = &squashfs_dir_inode_ops;
 		inode->i_fop = &squashfs_dir_ops;
@@ -284,7 +284,7 @@ int squashfs_read_inode(struct inode *inode, long long ino)
 		if (err < 0)
 			goto failed_read;
 
-		inode->i_nlink = le32_to_cpu(sqsh_ino->nlink);
+		set_nlink(inode, le32_to_cpu(sqsh_ino->nlink));
 		inode->i_size = le32_to_cpu(sqsh_ino->symlink_size);
 		inode->i_op = &squashfs_symlink_inode_ops;
 		inode->i_data.a_ops = &squashfs_symlink_aops;
@@ -325,7 +325,7 @@ int squashfs_read_inode(struct inode *inode, long long ino)
 			inode->i_mode |= S_IFCHR;
 		else
 			inode->i_mode |= S_IFBLK;
-		inode->i_nlink = le32_to_cpu(sqsh_ino->nlink);
+		set_nlink(inode, le32_to_cpu(sqsh_ino->nlink));
 		rdev = le32_to_cpu(sqsh_ino->rdev);
 		init_special_inode(inode, inode->i_mode, new_decode_dev(rdev));
 
@@ -349,7 +349,7 @@ int squashfs_read_inode(struct inode *inode, long long ino)
 			inode->i_mode |= S_IFBLK;
 		xattr_id = le32_to_cpu(sqsh_ino->xattr);
 		inode->i_op = &squashfs_inode_ops;
-		inode->i_nlink = le32_to_cpu(sqsh_ino->nlink);
+		set_nlink(inode, le32_to_cpu(sqsh_ino->nlink));
 		rdev = le32_to_cpu(sqsh_ino->rdev);
 		init_special_inode(inode, inode->i_mode, new_decode_dev(rdev));
 
@@ -370,7 +370,7 @@ int squashfs_read_inode(struct inode *inode, long long ino)
 			inode->i_mode |= S_IFIFO;
 		else
 			inode->i_mode |= S_IFSOCK;
-		inode->i_nlink = le32_to_cpu(sqsh_ino->nlink);
+		set_nlink(inode, le32_to_cpu(sqsh_ino->nlink));
 		init_special_inode(inode, inode->i_mode, 0);
 		break;
 	}
@@ -389,7 +389,7 @@ int squashfs_read_inode(struct inode *inode, long long ino)
 			inode->i_mode |= S_IFSOCK;
 		xattr_id = le32_to_cpu(sqsh_ino->xattr);
 		inode->i_op = &squashfs_inode_ops;
-		inode->i_nlink = le32_to_cpu(sqsh_ino->nlink);
+		set_nlink(inode, le32_to_cpu(sqsh_ino->nlink));
 		init_special_inode(inode, inode->i_mode, 0);
 		break;
 	}
diff --git a/fs/stack.c b/fs/stack.c
index b4f2ab4..9c11519 100644
--- a/fs/stack.c
+++ b/fs/stack.c
@@ -71,6 +71,6 @@ void fsstack_copy_attr_all(struct inode *dest, const struct inode *src)
 	dest->i_ctime = src->i_ctime;
 	dest->i_blkbits = src->i_blkbits;
 	dest->i_flags = src->i_flags;
-	dest->i_nlink = src->i_nlink;
+	set_nlink(dest, src->i_nlink);
 }
 EXPORT_SYMBOL_GPL(fsstack_copy_attr_all);
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c
index e3f091a..6b1afb9 100644
--- a/fs/sysfs/inode.c
+++ b/fs/sysfs/inode.c
@@ -230,7 +230,7 @@ static void sysfs_refresh_inode(struct sysfs_dirent *sd, struct inode *inode)
 	}
 
 	if (sysfs_type(sd) == SYSFS_DIR)
-		inode->i_nlink = sysfs_count_nlink(sd);
+		set_nlink(inode, sysfs_count_nlink(sd));
 }
 
 int sysfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c
index 0630eb9..25ffb3e 100644
--- a/fs/sysv/inode.c
+++ b/fs/sysv/inode.c
@@ -219,7 +219,7 @@ struct inode *sysv_iget(struct super_block *sb, unsigned int ino)
 	inode->i_mode = fs16_to_cpu(sbi, raw_inode->i_mode);
 	inode->i_uid = (uid_t)fs16_to_cpu(sbi, raw_inode->i_uid);
 	inode->i_gid = (gid_t)fs16_to_cpu(sbi, raw_inode->i_gid);
-	inode->i_nlink = fs16_to_cpu(sbi, raw_inode->i_nlink);
+	set_nlink(inode, fs16_to_cpu(sbi, raw_inode->i_nlink));
 	inode->i_size = fs32_to_cpu(sbi, raw_inode->i_size);
 	inode->i_atime.tv_sec = fs32_to_cpu(sbi, raw_inode->i_atime);
 	inode->i_mtime.tv_sec = fs32_to_cpu(sbi, raw_inode->i_mtime);
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
index b281212..20403dc 100644
--- a/fs/ubifs/super.c
+++ b/fs/ubifs/super.c
@@ -129,7 +129,7 @@ struct inode *ubifs_iget(struct super_block *sb, unsigned long inum)
 		goto out_ino;
 
 	inode->i_flags |= (S_NOCMTIME | S_NOATIME);
-	inode->i_nlink = le32_to_cpu(ino->nlink);
+	set_nlink(inode, le32_to_cpu(ino->nlink));
 	inode->i_uid   = le32_to_cpu(ino->uid);
 	inode->i_gid   = le32_to_cpu(ino->gid);
 	inode->i_atime.tv_sec  = (int64_t)le64_to_cpu(ino->atime_sec);
diff --git a/fs/ubifs/xattr.c b/fs/ubifs/xattr.c
index 993adc8..bf18f7a 100644
--- a/fs/ubifs/xattr.c
+++ b/fs/ubifs/xattr.c
@@ -561,7 +561,7 @@ int ubifs_removexattr(struct dentry *dentry, const char *name)
 	clear_nlink(inode);
 	err = remove_xattr(c, host, inode, &nm);
 	if (err)
-		inode->i_nlink = 1;
+		set_nlink(inode, 1);
 
 	/* If @i_nlink is 0, 'iput()' will delete the inode */
 	iput(inode);
diff --git a/fs/udf/inode.c b/fs/udf/inode.c
index 1d1358e..6e73f1d 100644
--- a/fs/udf/inode.c
+++ b/fs/udf/inode.c
@@ -1236,6 +1236,7 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
 	int offset;
 	struct udf_sb_info *sbi = UDF_SB(inode->i_sb);
 	struct udf_inode_info *iinfo = UDF_I(inode);
+	unsigned int link_count;
 
 	fe = (struct fileEntry *)bh->b_data;
 	efe = (struct extendedFileEntry *)bh->b_data;
@@ -1318,9 +1319,10 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
 	inode->i_mode &= ~sbi->s_umask;
 	read_unlock(&sbi->s_cred_lock);
 
-	inode->i_nlink = le16_to_cpu(fe->fileLinkCount);
-	if (!inode->i_nlink)
-		inode->i_nlink = 1;
+	link_count = le16_to_cpu(fe->fileLinkCount);
+	if (!link_count)
+		link_count = 1;
+	set_nlink(inode, link_count);
 
 	inode->i_size = le64_to_cpu(fe->informationLength);
 	iinfo->i_lenExtents = inode->i_size;
diff --git a/fs/udf/namei.c b/fs/udf/namei.c
index e8d61b1..f1c64c6 100644
--- a/fs/udf/namei.c
+++ b/fs/udf/namei.c
@@ -667,7 +667,7 @@ static int udf_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 		iput(inode);
 		goto out;
 	}
-	inode->i_nlink = 2;
+	set_nlink(inode, 2);
 	cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
 	cfi.icb.extLocation = cpu_to_lelb(dinfo->i_location);
 	*(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse =
@@ -837,7 +837,7 @@ static int udf_unlink(struct inode *dir, struct dentry *dentry)
 	if (!inode->i_nlink) {
 		udf_debug("Deleting nonexistent file (%lu), %d\n",
 			  inode->i_ino, inode->i_nlink);
-		inode->i_nlink = 1;
+		set_nlink(inode, 1);
 	}
 	retval = udf_delete_entry(dir, fi, &fibh, &cfi);
 	if (retval)
diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c
index b4d791a..879b134 100644
--- a/fs/ufs/inode.c
+++ b/fs/ufs/inode.c
@@ -589,7 +589,7 @@ static int ufs1_read_inode(struct inode *inode, struct ufs_inode *ufs_inode)
 	 * Copy data to the in-core inode.
 	 */
 	inode->i_mode = mode = fs16_to_cpu(sb, ufs_inode->ui_mode);
-	inode->i_nlink = fs16_to_cpu(sb, ufs_inode->ui_nlink);
+	set_nlink(inode, fs16_to_cpu(sb, ufs_inode->ui_nlink));
 	if (inode->i_nlink == 0) {
 		ufs_error (sb, "ufs_read_inode", "inode %lu has zero nlink\n", inode->i_ino);
 		return -1;
@@ -637,7 +637,7 @@ static int ufs2_read_inode(struct inode *inode, struct ufs2_inode *ufs2_inode)
 	 * Copy data to the in-core inode.
 	 */
 	inode->i_mode = mode = fs16_to_cpu(sb, ufs2_inode->ui_mode);
-	inode->i_nlink = fs16_to_cpu(sb, ufs2_inode->ui_nlink);
+	set_nlink(inode, fs16_to_cpu(sb, ufs2_inode->ui_nlink));
 	if (inode->i_nlink == 0) {
 		ufs_error (sb, "ufs_read_inode", "inode %lu has zero nlink\n", inode->i_ino);
 		return -1;
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
index 673704f..91fac2e 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -1152,7 +1152,7 @@ xfs_setup_inode(
 	hlist_add_fake(&inode->i_hash);
 
 	inode->i_mode	= ip->i_d.di_mode;
-	inode->i_nlink	= ip->i_d.di_nlink;
+	set_nlink(inode, ip->i_d.di_nlink);
 	inode->i_uid	= ip->i_d.di_uid;
 	inode->i_gid	= ip->i_d.di_gid;
 
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 0979638..28f4998 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1748,6 +1748,19 @@ static inline void mark_inode_dirty_sync(struct inode *inode)
 }
 
 /**
+ * set_nlink - directly set an inode's link count
+ * @inode: inode
+ * @nlink: new nlink (should be non-zero)
+ *
+ * This is a low-level filesystem helper to replace any
+ * direct filesystem manipulation of i_nlink.
+ */
+static inline void set_nlink(struct inode *inode, unsigned int nlink)
+{
+	inode->i_nlink = nlink;
+}
+
+/**
  * inc_nlink - directly increment an inode's link count
  * @inode: inode
  *
-- 
1.7.3.4


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 11/13] vfs: protect i_nlink
  2011-10-12 14:48 [PATCH 0/13] read-only remount race fix v7 Miklos Szeredi
                   ` (9 preceding siblings ...)
  2011-10-12 14:49 ` [PATCH 10/13] filesystems: add set_nlink() Miklos Szeredi
@ 2011-10-12 14:49 ` Miklos Szeredi
  2011-10-12 14:49 ` [PATCH 12/13] vfs: count unlinked inodes Miklos Szeredi
                   ` (3 subsequent siblings)
  14 siblings, 0 replies; 27+ messages in thread
From: Miklos Szeredi @ 2011-10-12 14:49 UTC (permalink / raw)
  To: viro; +Cc: linux-fsdevel, linux-kernel, jack, hch, akpm, toshi.okajima,
	mszeredi

From: Miklos Szeredi <mszeredi@suse.cz>

Prevent direct modification of i_nlink by making it const and adding a
non-const __i_nlink alias.

Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
---
 fs/inode.c         |    2 +-
 include/linux/fs.h |   20 +++++++++++++++-----
 2 files changed, 16 insertions(+), 6 deletions(-)

diff --git a/fs/inode.c b/fs/inode.c
index ec79246..e2d3633 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -142,7 +142,7 @@ int inode_init_always(struct super_block *sb, struct inode *inode)
 	atomic_set(&inode->i_count, 1);
 	inode->i_op = &empty_iops;
 	inode->i_fop = &empty_fops;
-	inode->i_nlink = 1;
+	inode->__i_nlink = 1;
 	inode->i_opflags = 0;
 	inode->i_uid = 0;
 	inode->i_gid = 0;
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 28f4998..7813404 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -767,7 +767,17 @@ struct inode {
 
 	/* Stat data, not accessed from path walking */
 	unsigned long		i_ino;
-	unsigned int		i_nlink;
+	/*
+	 * Filesystems may only read i_nlink directly.  They shall use the
+	 * following functions for modification:
+	 *
+	 *    (set|clear|inc|drop)_nlink
+	 *    inode_(inc|dec)_link_count
+	 */
+	union {
+		const unsigned int i_nlink;
+		unsigned int __i_nlink;
+	};
 	dev_t			i_rdev;
 	loff_t			i_size;
 	struct timespec		i_atime;
@@ -1757,7 +1767,7 @@ static inline void mark_inode_dirty_sync(struct inode *inode)
  */
 static inline void set_nlink(struct inode *inode, unsigned int nlink)
 {
-	inode->i_nlink = nlink;
+	inode->__i_nlink = nlink;
 }
 
 /**
@@ -1770,7 +1780,7 @@ static inline void set_nlink(struct inode *inode, unsigned int nlink)
  */
 static inline void inc_nlink(struct inode *inode)
 {
-	inode->i_nlink++;
+	inode->__i_nlink++;
 }
 
 static inline void inode_inc_link_count(struct inode *inode)
@@ -1792,7 +1802,7 @@ static inline void inode_inc_link_count(struct inode *inode)
  */
 static inline void drop_nlink(struct inode *inode)
 {
-	inode->i_nlink--;
+	inode->__i_nlink--;
 }
 
 /**
@@ -1805,7 +1815,7 @@ static inline void drop_nlink(struct inode *inode)
  */
 static inline void clear_nlink(struct inode *inode)
 {
-	inode->i_nlink = 0;
+	inode->__i_nlink = 0;
 }
 
 static inline void inode_dec_link_count(struct inode *inode)
-- 
1.7.3.4

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 12/13] vfs: count unlinked inodes
  2011-10-12 14:48 [PATCH 0/13] read-only remount race fix v7 Miklos Szeredi
                   ` (10 preceding siblings ...)
  2011-10-12 14:49 ` [PATCH 11/13] vfs: protect i_nlink Miklos Szeredi
@ 2011-10-12 14:49 ` Miklos Szeredi
  2011-10-28  6:08   ` Christoph Hellwig
  2011-10-12 14:49 ` [PATCH 13/13] vfs: prevent remount read-only if pending removes Miklos Szeredi
                   ` (2 subsequent siblings)
  14 siblings, 1 reply; 27+ messages in thread
From: Miklos Szeredi @ 2011-10-12 14:49 UTC (permalink / raw)
  To: viro; +Cc: linux-fsdevel, linux-kernel, jack, hch, akpm, toshi.okajima,
	mszeredi

From: Miklos Szeredi <mszeredi@suse.cz>

Add a new counter to the superblock that keeps track of unlinked but
not yet deleted inodes.

Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
---
 fs/inode.c         |   81 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/fs.h |   61 ++++----------------------------------
 2 files changed, 88 insertions(+), 54 deletions(-)

diff --git a/fs/inode.c b/fs/inode.c
index e2d3633..ca27d4e 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -241,6 +241,11 @@ void __destroy_inode(struct inode *inode)
 	BUG_ON(inode_has_buffers(inode));
 	security_inode_free(inode);
 	fsnotify_inode_delete(inode);
+	if (!inode->i_nlink) {
+		WARN_ON(atomic_long_read(&inode->i_sb->s_remove_count) == 0);
+		atomic_long_dec(&inode->i_sb->s_remove_count);
+	}
+
 #ifdef CONFIG_FS_POSIX_ACL
 	if (inode->i_acl && inode->i_acl != ACL_NOT_CACHED)
 		posix_acl_release(inode->i_acl);
@@ -268,6 +273,82 @@ static void destroy_inode(struct inode *inode)
 		call_rcu(&inode->i_rcu, i_callback);
 }
 
+/**
+ * drop_nlink - directly drop an inode's link count
+ * @inode: inode
+ *
+ * This is a low-level filesystem helper to replace any
+ * direct filesystem manipulation of i_nlink.  In cases
+ * where we are attempting to track writes to the
+ * filesystem, a decrement to zero means an imminent
+ * write when the file is truncated and actually unlinked
+ * on the filesystem.
+ */
+void drop_nlink(struct inode *inode)
+{
+	WARN_ON(inode->i_nlink == 0);
+	inode->__i_nlink--;
+	if (!inode->i_nlink)
+		atomic_long_inc(&inode->i_sb->s_remove_count);
+}
+EXPORT_SYMBOL(drop_nlink);
+
+/**
+ * clear_nlink - directly zero an inode's link count
+ * @inode: inode
+ *
+ * This is a low-level filesystem helper to replace any
+ * direct filesystem manipulation of i_nlink.  See
+ * drop_nlink() for why we care about i_nlink hitting zero.
+ */
+void clear_nlink(struct inode *inode)
+{
+	if (inode->i_nlink) {
+		inode->__i_nlink = 0;
+		atomic_long_inc(&inode->i_sb->s_remove_count);
+	}
+}
+EXPORT_SYMBOL(clear_nlink);
+
+/**
+ * set_nlink - directly set an inode's link count
+ * @inode: inode
+ * @nlink: new nlink (should be non-zero)
+ *
+ * This is a low-level filesystem helper to replace any
+ * direct filesystem manipulation of i_nlink.
+ */
+void set_nlink(struct inode *inode, unsigned int nlink)
+{
+	if (WARN_ON(!nlink)) {
+		clear_nlink(inode);
+	} else {
+		/* Yes, some filesystems do change nlink from zero to one */
+		if (inode->i_nlink == 0)
+			atomic_long_dec(&inode->i_sb->s_remove_count);
+
+		inode->__i_nlink = nlink;
+	}
+}
+EXPORT_SYMBOL(set_nlink);
+
+/**
+ * inc_nlink - directly increment an inode's link count
+ * @inode: inode
+ *
+ * This is a low-level filesystem helper to replace any
+ * direct filesystem manipulation of i_nlink.  Currently,
+ * it is only here for parity with dec_nlink().
+ */
+void inc_nlink(struct inode *inode)
+{
+	if (WARN_ON(inode->i_nlink == 0))
+		atomic_long_dec(&inode->i_sb->s_remove_count);
+
+	inode->__i_nlink++;
+}
+EXPORT_SYMBOL(inc_nlink);
+
 void address_space_init_once(struct address_space *mapping)
 {
 	memset(mapping, 0, sizeof(*mapping));
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 7813404..71bacce 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1473,6 +1473,9 @@ struct super_block {
 
 	struct shrinker s_shrink;	/* per-sb shrinker handle */
 
+	/* Number of inodes with nlink == 0 but still referenced */
+	atomic_long_t s_remove_count;
+
 	/* Being remounted read-only */
 	int s_readonly_remount;
 };
@@ -1757,31 +1760,10 @@ static inline void mark_inode_dirty_sync(struct inode *inode)
 	__mark_inode_dirty(inode, I_DIRTY_SYNC);
 }
 
-/**
- * set_nlink - directly set an inode's link count
- * @inode: inode
- * @nlink: new nlink (should be non-zero)
- *
- * This is a low-level filesystem helper to replace any
- * direct filesystem manipulation of i_nlink.
- */
-static inline void set_nlink(struct inode *inode, unsigned int nlink)
-{
-	inode->__i_nlink = nlink;
-}
-
-/**
- * inc_nlink - directly increment an inode's link count
- * @inode: inode
- *
- * This is a low-level filesystem helper to replace any
- * direct filesystem manipulation of i_nlink.  Currently,
- * it is only here for parity with dec_nlink().
- */
-static inline void inc_nlink(struct inode *inode)
-{
-	inode->__i_nlink++;
-}
+extern void inc_nlink(struct inode *inode);
+extern void drop_nlink(struct inode *inode);
+extern void clear_nlink(struct inode *inode);
+extern void set_nlink(struct inode *inode, unsigned int nlink);
 
 static inline void inode_inc_link_count(struct inode *inode)
 {
@@ -1789,35 +1771,6 @@ static inline void inode_inc_link_count(struct inode *inode)
 	mark_inode_dirty(inode);
 }
 
-/**
- * drop_nlink - directly drop an inode's link count
- * @inode: inode
- *
- * This is a low-level filesystem helper to replace any
- * direct filesystem manipulation of i_nlink.  In cases
- * where we are attempting to track writes to the
- * filesystem, a decrement to zero means an imminent
- * write when the file is truncated and actually unlinked
- * on the filesystem.
- */
-static inline void drop_nlink(struct inode *inode)
-{
-	inode->__i_nlink--;
-}
-
-/**
- * clear_nlink - directly zero an inode's link count
- * @inode: inode
- *
- * This is a low-level filesystem helper to replace any
- * direct filesystem manipulation of i_nlink.  See
- * drop_nlink() for why we care about i_nlink hitting zero.
- */
-static inline void clear_nlink(struct inode *inode)
-{
-	inode->__i_nlink = 0;
-}
-
 static inline void inode_dec_link_count(struct inode *inode)
 {
 	drop_nlink(inode);
-- 
1.7.3.4

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 13/13] vfs: prevent remount read-only if pending removes
  2011-10-12 14:48 [PATCH 0/13] read-only remount race fix v7 Miklos Szeredi
                   ` (11 preceding siblings ...)
  2011-10-12 14:49 ` [PATCH 12/13] vfs: count unlinked inodes Miklos Szeredi
@ 2011-10-12 14:49 ` Miklos Szeredi
  2011-10-12 15:03 ` [PATCH 0/13] read-only remount race fix v7 Christoph Hellwig
  2011-10-13  7:10 ` Toshiyuki Okajima
  14 siblings, 0 replies; 27+ messages in thread
From: Miklos Szeredi @ 2011-10-12 14:49 UTC (permalink / raw)
  To: viro; +Cc: linux-fsdevel, linux-kernel, jack, hch, akpm, toshi.okajima,
	mszeredi

From: Miklos Szeredi <mszeredi@suse.cz>

If there are any inodes on the super block that have been unlinked
(i_nlink == 0) but have not yet been deleted then prevent the
remounting the super block read-only.

Reported-by: Toshiyuki Okajima <toshi.okajima@jp.fujitsu.com>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
---
 fs/file_table.c    |   26 --------------------------
 fs/namespace.c     |    7 +++++++
 fs/super.c         |    4 ----
 include/linux/fs.h |    2 --
 4 files changed, 7 insertions(+), 32 deletions(-)

diff --git a/fs/file_table.c b/fs/file_table.c
index dc9f437..20002e3 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -474,32 +474,6 @@ void file_sb_list_del(struct file *file)
 
 #endif
 
-int fs_may_remount_ro(struct super_block *sb)
-{
-	struct file *file;
-	/* Check that no files are currently opened for writing. */
-	lg_global_lock(files_lglock);
-	do_file_list_for_each_entry(sb, file) {
-		struct inode *inode = file->f_path.dentry->d_inode;
-
-		/* File with pending delete? */
-		if (inode->i_nlink == 0)
-			goto too_bad;
-
-		/*
-		 * Writable file?
-		 * Should be caught by sb_prepare_remount_readonly().
-		 */
-		if (WARN_ON(S_ISREG(inode->i_mode) && (file->f_mode & FMODE_WRITE)))
-			goto too_bad;
-	} while_file_list_for_each_entry;
-	lg_global_unlock(files_lglock);
-	return 1; /* Tis' cool bro. */
-too_bad:
-	lg_global_unlock(files_lglock);
-	return 0;
-}
-
 /**
  *	mark_files_ro - mark all files read-only
  *	@sb: superblock in question
diff --git a/fs/namespace.c b/fs/namespace.c
index 85838f5..617705f 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -480,6 +480,10 @@ int sb_prepare_remount_readonly(struct super_block *sb)
 	struct vfsmount *mnt;
 	int err = 0;
 
+	/* Racy optimization.  Recheck the counter under MNT_WRITE_HOLD */
+	if (atomic_long_read(&sb->s_remove_count))
+		return -EBUSY;
+
 	br_write_lock(vfsmount_lock);
 	list_for_each_entry(mnt, &sb->s_mounts, mnt_instance) {
 		if (!(mnt->mnt_flags & MNT_READONLY)) {
@@ -491,6 +495,9 @@ int sb_prepare_remount_readonly(struct super_block *sb)
 			}
 		}
 	}
+	if (!err && atomic_long_read(&sb->s_remove_count))
+		err = -EBUSY;
+
 	if (!err) {
 		sb->s_readonly_remount = 1;
 		smp_wmb();
diff --git a/fs/super.c b/fs/super.c
index 94c8ace..7b28dae 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -727,10 +727,6 @@ int do_remount_sb(struct super_block *sb, int flags, void *data, int force)
 			retval = sb_prepare_remount_readonly(sb);
 			if (retval)
 				return retval;
-
-			retval = -EBUSY;
-			if (!fs_may_remount_ro(sb))
-				goto cancel_readonly;
 		}
 	}
 
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 71bacce..c791aa8b 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2135,8 +2135,6 @@ extern const struct file_operations read_pipefifo_fops;
 extern const struct file_operations write_pipefifo_fops;
 extern const struct file_operations rdwr_pipefifo_fops;
 
-extern int fs_may_remount_ro(struct super_block *);
-
 #ifdef CONFIG_BLOCK
 /*
  * return READ, READA, or WRITE
-- 
1.7.3.4

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* Re: [PATCH 0/13] read-only remount race fix v7
  2011-10-12 14:48 [PATCH 0/13] read-only remount race fix v7 Miklos Szeredi
                   ` (12 preceding siblings ...)
  2011-10-12 14:49 ` [PATCH 13/13] vfs: prevent remount read-only if pending removes Miklos Szeredi
@ 2011-10-12 15:03 ` Christoph Hellwig
  2011-10-12 15:09   ` Miklos Szeredi
  2011-10-13  7:10 ` Toshiyuki Okajima
  14 siblings, 1 reply; 27+ messages in thread
From: Christoph Hellwig @ 2011-10-12 15:03 UTC (permalink / raw)
  To: Miklos Szeredi
  Cc: viro, linux-fsdevel, linux-kernel, jack, hch, akpm, toshi.okajima,
	mszeredi

On Wed, Oct 12, 2011 at 04:48:53PM +0200, Miklos Szeredi wrote:
> Here's an update of the read-only remount race fixes.
> 
> It should now fix the races after unlink.  I haven't been able to
> trigger the bad behavior with the test scripts provided by Toshiyuki
> Okajima.

How does the test script look like?  Could we integrate it into xfstests
so that we have a good regular run regression test for this?

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 0/13] read-only remount race fix v7
  2011-10-12 15:03 ` [PATCH 0/13] read-only remount race fix v7 Christoph Hellwig
@ 2011-10-12 15:09   ` Miklos Szeredi
  0 siblings, 0 replies; 27+ messages in thread
From: Miklos Szeredi @ 2011-10-12 15:09 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: viro, linux-fsdevel, linux-kernel, jack, akpm, toshi.okajima

[-- Attachment #1: Type: text/plain, Size: 608 bytes --]

Christoph Hellwig <hch@infradead.org> writes:

> On Wed, Oct 12, 2011 at 04:48:53PM +0200, Miklos Szeredi wrote:
>> Here's an update of the read-only remount race fixes.
>> 
>> It should now fix the races after unlink.  I haven't been able to
>> trigger the bad behavior with the test scripts provided by Toshiyuki
>> Okajima.
>
> How does the test script look like?  Could we integrate it into xfstests
> so that we have a good regular run regression test for this?

Attaching the scripts.  It doesn't detect failure, currenly that needs
to be derived from the output of the run and dmesg.

Thanks,
Miklos


[-- Attachment #2: go.sh --]
[-- Type: application/x-shellscript, Size: 397 bytes --]

[-- Attachment #3: writer.sh --]
[-- Type: application/x-shellscript, Size: 502 bytes --]

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 06/13] jfs: remove unnecessary nlink setting
  2011-10-12 14:48 ` [PATCH 06/13] jfs: " Miklos Szeredi
@ 2011-10-12 15:26   ` Dave Kleikamp
  0 siblings, 0 replies; 27+ messages in thread
From: Dave Kleikamp @ 2011-10-12 15:26 UTC (permalink / raw)
  To: Miklos Szeredi
  Cc: viro, linux-fsdevel, linux-kernel, jack, hch, akpm, toshi.okajima,
	mszeredi

On 10/12/2011 09:48 AM, Miklos Szeredi wrote:
> From: Miklos Szeredi <mszeredi@suse.cz>
> 
> alloc_inode() initializes i_nlink to 1.  Remove unnecessary
> re-initialization.
> 
> Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>

Acked-by: Dave Kleikamp <dave.kleikamp@oracle.com>

> ---
>  fs/jfs/super.c |    1 -
>  1 files changed, 0 insertions(+), 1 deletions(-)
> 
> diff --git a/fs/jfs/super.c b/fs/jfs/super.c
> index 06c8a67..a44eff0 100644
> --- a/fs/jfs/super.c
> +++ b/fs/jfs/super.c
> @@ -485,7 +485,6 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent)
>  		goto out_unload;
>  	}
>  	inode->i_ino = 0;
> -	inode->i_nlink = 1;
>  	inode->i_size = sb->s_bdev->bd_inode->i_size;
>  	inode->i_mapping->a_ops = &jfs_metapage_aops;
>  	insert_inode_hash(inode);

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 0/13] read-only remount race fix v7
  2011-10-12 14:48 [PATCH 0/13] read-only remount race fix v7 Miklos Szeredi
                   ` (13 preceding siblings ...)
  2011-10-12 15:03 ` [PATCH 0/13] read-only remount race fix v7 Christoph Hellwig
@ 2011-10-13  7:10 ` Toshiyuki Okajima
  2011-10-18  6:28   ` Toshiyuki Okajima
  14 siblings, 1 reply; 27+ messages in thread
From: Toshiyuki Okajima @ 2011-10-13  7:10 UTC (permalink / raw)
  To: Miklos Szeredi
  Cc: toshi.okajima, viro, linux-fsdevel, linux-kernel, jack, hch, akpm,
	mszeredi

Hi.

(2011/10/12 23:48), Miklos Szeredi wrote:
> Here's an update of the read-only remount race fixes.
> 
> It should now fix the races after unlink.  I haven't been able to
> trigger the bad behavior with the test scripts provided by Toshiyuki
> Okajima.
> 
> Toshiyuki-san, could you please test these patches too?
OK. I will test them with ext4. Please wait.

Best Regards,
Toshiyuki Okajima

> 
> Thanks,
> Miklos
> ---
> 
> Miklos Szeredi (13):
>       vfs: ignore error on forced remount
>       vfs: keep list of mounts for each superblock
>       vfs: protect remounting superblock read-only
>       vfs: fs_may_remount_ro: turn unnecessary check into a WARN_ON
>       hypfs: remove unnecessary nlink setting
>       jfs: remove unnecessary nlink setting
>       ocfs2: remove unnecessary nlink setting
>       logfs: remove unnecessary nlink setting
>       filesystems: add missing nlink wrappers
>       filesystems: add set_nlink()
>       vfs: protect i_nlink
>       vfs: count unlinked inodes
>       vfs: prevent remount read-only if pending removes
> 
> ---
>  arch/s390/hypfs/inode.c          |    6 +--
>  drivers/mtd/mtdchar.c            |    2 +-
>  drivers/staging/pohmelfs/inode.c |    2 +-
>  fs/9p/vfs_inode.c                |    4 +-
>  fs/9p/vfs_inode_dotl.c           |    4 +-
>  fs/adfs/inode.c                  |    2 +-
>  fs/affs/amigaffs.c               |    4 +-
>  fs/affs/inode.c                  |    8 ++--
>  fs/affs/namei.c                  |    6 +-
>  fs/afs/fsclient.c                |    2 +-
>  fs/afs/inode.c                   |    4 +-
>  fs/autofs4/inode.c               |    2 +-
>  fs/befs/linuxvfs.c               |    2 +-
>  fs/bfs/dir.c                     |    2 +-
>  fs/bfs/inode.c                   |    2 +-
>  fs/binfmt_misc.c                 |    2 +-
>  fs/btrfs/delayed-inode.c         |    2 +-
>  fs/btrfs/disk-io.c               |    2 +-
>  fs/btrfs/inode.c                 |    4 +-
>  fs/btrfs/tree-log.c              |    2 +-
>  fs/ceph/caps.c                   |    2 +-
>  fs/ceph/inode.c                  |    2 +-
>  fs/cifs/inode.c                  |    6 +-
>  fs/cifs/link.c                   |    2 +-
>  fs/coda/coda_linux.c             |    2 +-
>  fs/coda/dir.c                    |    2 +-
>  fs/devpts/inode.c                |    4 +-
>  fs/ecryptfs/inode.c              |   12 +++---
>  fs/efs/inode.c                   |    2 +-
>  fs/exofs/inode.c                 |    2 +-
>  fs/ext2/ialloc.c                 |    2 +-
>  fs/ext2/inode.c                  |    2 +-
>  fs/ext3/ialloc.c                 |    2 +-
>  fs/ext3/inode.c                  |    2 +-
>  fs/ext3/namei.c                  |    6 +-
>  fs/ext4/ialloc.c                 |    2 +-
>  fs/ext4/inode.c                  |    2 +-
>  fs/ext4/migrate.c                |    2 +-
>  fs/ext4/namei.c                  |    8 ++--
>  fs/fat/inode.c                   |    4 +-
>  fs/fat/namei_msdos.c             |    2 +-
>  fs/fat/namei_vfat.c              |    2 +-
>  fs/file_table.c                  |   23 ----------
>  fs/freevxfs/vxfs_inode.c         |    2 +-
>  fs/fuse/control.c                |    2 +-
>  fs/fuse/inode.c                  |    2 +-
>  fs/gfs2/glops.c                  |    2 +-
>  fs/hfs/dir.c                     |    4 +-
>  fs/hfs/inode.c                   |    4 +-
>  fs/hfsplus/dir.c                 |    4 +-
>  fs/hfsplus/inode.c               |   10 ++--
>  fs/hostfs/hostfs_kern.c          |    2 +-
>  fs/hpfs/dir.c                    |    2 +-
>  fs/hpfs/inode.c                  |   10 ++--
>  fs/hpfs/namei.c                  |    8 ++--
>  fs/hppfs/hppfs.c                 |    2 +-
>  fs/hugetlbfs/inode.c             |    2 +-
>  fs/inode.c                       |   83 +++++++++++++++++++++++++++++++++++++-
>  fs/internal.h                    |    1 +
>  fs/isofs/inode.c                 |    4 +-
>  fs/isofs/rock.c                  |    4 +-
>  fs/jffs2/dir.c                   |    6 +-
>  fs/jffs2/fs.c                    |    6 +-
>  fs/jfs/jfs_imap.c                |    6 +-
>  fs/jfs/jfs_inode.c               |    2 +-
>  fs/jfs/namei.c                   |   12 +++---
>  fs/jfs/super.c                   |    1 -
>  fs/libfs.c                       |    2 +-
>  fs/logfs/dir.c                   |    8 ++--
>  fs/logfs/inode.c                 |    3 +-
>  fs/logfs/readwrite.c             |    2 +-
>  fs/minix/inode.c                 |    4 +-
>  fs/namespace.c                   |   57 +++++++++++++++++++++++++-
>  fs/ncpfs/inode.c                 |    2 +-
>  fs/nfs/inode.c                   |    6 +-
>  fs/nilfs2/inode.c                |    4 +-
>  fs/nilfs2/namei.c                |    2 +-
>  fs/ntfs/inode.c                  |    8 ++--
>  fs/ocfs2/dir.c                   |    4 +-
>  fs/ocfs2/dlmglue.c               |    2 +-
>  fs/ocfs2/inode.c                 |    4 +-
>  fs/ocfs2/namei.c                 |   18 ++++-----
>  fs/openpromfs/inode.c            |    4 +-
>  fs/proc/base.c                   |   12 +++---
>  fs/proc/generic.c                |    2 +-
>  fs/proc/inode.c                  |    2 +-
>  fs/proc/proc_sysctl.c            |    2 +-
>  fs/qnx4/inode.c                  |    2 +-
>  fs/reiserfs/inode.c              |   10 ++--
>  fs/reiserfs/namei.c              |   16 ++++----
>  fs/romfs/super.c                 |    2 +-
>  fs/squashfs/inode.c              |   18 ++++----
>  fs/stack.c                       |    2 +-
>  fs/super.c                       |   27 ++++++++++--
>  fs/sysfs/inode.c                 |    2 +-
>  fs/sysv/inode.c                  |    2 +-
>  fs/ubifs/super.c                 |    2 +-
>  fs/ubifs/xattr.c                 |    4 +-
>  fs/udf/inode.c                   |    8 ++-
>  fs/udf/namei.c                   |   15 +++----
>  fs/ufs/ialloc.c                  |    2 +-
>  fs/ufs/inode.c                   |    4 +-
>  fs/xfs/xfs_iops.c                |    2 +-
>  include/linux/fs.h               |   66 ++++++++++--------------------
>  include/linux/mount.h            |    1 +
>  mm/shmem.c                       |    2 +-
>  106 files changed, 389 insertions(+), 286 deletions(-)
> 
> 
> 

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 10/13] filesystems: add set_nlink()
  2011-10-12 14:49 ` [PATCH 10/13] filesystems: add set_nlink() Miklos Szeredi
@ 2011-10-13 16:33   ` Steven Whitehouse
  2011-10-14 15:04     ` Miklos Szeredi
  0 siblings, 1 reply; 27+ messages in thread
From: Steven Whitehouse @ 2011-10-13 16:33 UTC (permalink / raw)
  To: Miklos Szeredi
  Cc: viro, linux-fsdevel, linux-kernel, jack, hch, akpm, toshi.okajima,
	mszeredi

Hi,

On Wed, 2011-10-12 at 16:49 +0200, Miklos Szeredi wrote:
> From: Miklos Szeredi <mszeredi@suse.cz>
> 
> Replace remaining direct i_nlink updates with a new set_nlink()
> updater function.
> 
> Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
> ---
[snip]



> diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c
> index da21eca..102cf5e 100644
> --- a/fs/gfs2/glops.c
> +++ b/fs/gfs2/glops.c
> @@ -277,7 +277,7 @@ static void gfs2_set_nlink(struct inode *inode, u32 nlink)
>  		if (nlink == 0)
>  			clear_nlink(inode);
>  		else
> -			inode->i_nlink = nlink;
> +			set_nlink(inode, nlink);
>  	}
>  }

So long as it is ok to call set_nlink() with nlink == 0, then the if
statement here can be removed and just replaced with set_nlink()

Steve.




^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 10/13] filesystems: add set_nlink()
  2011-10-13 16:33   ` Steven Whitehouse
@ 2011-10-14 15:04     ` Miklos Szeredi
  0 siblings, 0 replies; 27+ messages in thread
From: Miklos Szeredi @ 2011-10-14 15:04 UTC (permalink / raw)
  To: Steven Whitehouse
  Cc: viro, linux-fsdevel, linux-kernel, jack, hch, akpm, toshi.okajima

Steven Whitehouse <swhiteho@redhat.com> writes:

> Hi,
>
> On Wed, 2011-10-12 at 16:49 +0200, Miklos Szeredi wrote:
>> From: Miklos Szeredi <mszeredi@suse.cz>
>> 
>> Replace remaining direct i_nlink updates with a new set_nlink()
>> updater function.
>> 
>> Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
>> ---
> [snip]
>
>
>
>> diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c
>> index da21eca..102cf5e 100644
>> --- a/fs/gfs2/glops.c
>> +++ b/fs/gfs2/glops.c
>> @@ -277,7 +277,7 @@ static void gfs2_set_nlink(struct inode *inode, u32 nlink)
>>  		if (nlink == 0)
>>  			clear_nlink(inode);
>>  		else
>> -			inode->i_nlink = nlink;
>> +			set_nlink(inode, nlink);
>>  	}
>>  }
>
> So long as it is ok to call set_nlink() with nlink == 0, then the if
> statement here can be removed and just replaced with set_nlink()

Current patchset will WARN if set_nlink() is called with nlink == 0.  I
think it's cleaner to keep the two cases separate.

Thanks,
Miklos

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 0/13] read-only remount race fix v7
  2011-10-13  7:10 ` Toshiyuki Okajima
@ 2011-10-18  6:28   ` Toshiyuki Okajima
  2011-10-18  9:02     ` Miklos Szeredi
  0 siblings, 1 reply; 27+ messages in thread
From: Toshiyuki Okajima @ 2011-10-18  6:28 UTC (permalink / raw)
  To: Miklos Szeredi
  Cc: Toshiyuki Okajima, viro, linux-fsdevel, linux-kernel, jack, hch,
	akpm, mszeredi

Miklos-san,

(2011/10/13 16:10), Toshiyuki Okajima wrote:
> Hi.
> 
> (2011/10/12 23:48), Miklos Szeredi wrote:
>> Here's an update of the read-only remount race fixes.
>>
>> It should now fix the races after unlink.  I haven't been able to
>> trigger the bad behavior with the test scripts provided by Toshiyuki
>> Okajima.
>>
>> Toshiyuki-san, could you please test these patches too?
> OK. I will test them with ext4. Please wait.
I have tested your latest patch set by my reproducer with ext4.

On my environment, this reproducer usually detects
 "EXT4-fs (xxx): Couldn't remount RDWR because of unprocessed orphan inode list"
message within 20 minutes when I use your previous patch set.
However, when I use your latest patche set, this producer has not yet 
detected the message for 2 days.

So, I think your latest patch set fixes the problem that delayed deletion 
can start when we remount a superblock read-only.

Tested-by: Toshiyuki Okajima <toshi.okajima@jp.fujitsu.com>

Regards,
Toshiyuki Okajima

> 
> Best Regards,
> Toshiyuki Okajima
> 
>>
>> Thanks,
>> Miklos
>> ---
>>
>> Miklos Szeredi (13):
>>       vfs: ignore error on forced remount
>>       vfs: keep list of mounts for each superblock
>>       vfs: protect remounting superblock read-only
>>       vfs: fs_may_remount_ro: turn unnecessary check into a WARN_ON
>>       hypfs: remove unnecessary nlink setting
>>       jfs: remove unnecessary nlink setting
>>       ocfs2: remove unnecessary nlink setting
>>       logfs: remove unnecessary nlink setting
>>       filesystems: add missing nlink wrappers
>>       filesystems: add set_nlink()
>>       vfs: protect i_nlink
>>       vfs: count unlinked inodes
>>       vfs: prevent remount read-only if pending removes
>>
>> ---
>>  arch/s390/hypfs/inode.c          |    6 +--
>>  drivers/mtd/mtdchar.c            |    2 +-
>>  drivers/staging/pohmelfs/inode.c |    2 +-
>>  fs/9p/vfs_inode.c                |    4 +-
>>  fs/9p/vfs_inode_dotl.c           |    4 +-
>>  fs/adfs/inode.c                  |    2 +-
>>  fs/affs/amigaffs.c               |    4 +-
>>  fs/affs/inode.c                  |    8 ++--
>>  fs/affs/namei.c                  |    6 +-
>>  fs/afs/fsclient.c                |    2 +-
>>  fs/afs/inode.c                   |    4 +-
>>  fs/autofs4/inode.c               |    2 +-
>>  fs/befs/linuxvfs.c               |    2 +-
>>  fs/bfs/dir.c                     |    2 +-
>>  fs/bfs/inode.c                   |    2 +-
>>  fs/binfmt_misc.c                 |    2 +-
>>  fs/btrfs/delayed-inode.c         |    2 +-
>>  fs/btrfs/disk-io.c               |    2 +-
>>  fs/btrfs/inode.c                 |    4 +-
>>  fs/btrfs/tree-log.c              |    2 +-
>>  fs/ceph/caps.c                   |    2 +-
>>  fs/ceph/inode.c                  |    2 +-
>>  fs/cifs/inode.c                  |    6 +-
>>  fs/cifs/link.c                   |    2 +-
>>  fs/coda/coda_linux.c             |    2 +-
>>  fs/coda/dir.c                    |    2 +-
>>  fs/devpts/inode.c                |    4 +-
>>  fs/ecryptfs/inode.c              |   12 +++---
>>  fs/efs/inode.c                   |    2 +-
>>  fs/exofs/inode.c                 |    2 +-
>>  fs/ext2/ialloc.c                 |    2 +-
>>  fs/ext2/inode.c                  |    2 +-
>>  fs/ext3/ialloc.c                 |    2 +-
>>  fs/ext3/inode.c                  |    2 +-
>>  fs/ext3/namei.c                  |    6 +-
>>  fs/ext4/ialloc.c                 |    2 +-
>>  fs/ext4/inode.c                  |    2 +-
>>  fs/ext4/migrate.c                |    2 +-
>>  fs/ext4/namei.c                  |    8 ++--
>>  fs/fat/inode.c                   |    4 +-
>>  fs/fat/namei_msdos.c             |    2 +-
>>  fs/fat/namei_vfat.c              |    2 +-
>>  fs/file_table.c                  |   23 ----------
>>  fs/freevxfs/vxfs_inode.c         |    2 +-
>>  fs/fuse/control.c                |    2 +-
>>  fs/fuse/inode.c                  |    2 +-
>>  fs/gfs2/glops.c                  |    2 +-
>>  fs/hfs/dir.c                     |    4 +-
>>  fs/hfs/inode.c                   |    4 +-
>>  fs/hfsplus/dir.c                 |    4 +-
>>  fs/hfsplus/inode.c               |   10 ++--
>>  fs/hostfs/hostfs_kern.c          |    2 +-
>>  fs/hpfs/dir.c                    |    2 +-
>>  fs/hpfs/inode.c                  |   10 ++--
>>  fs/hpfs/namei.c                  |    8 ++--
>>  fs/hppfs/hppfs.c                 |    2 +-
>>  fs/hugetlbfs/inode.c             |    2 +-
>>  fs/inode.c                       |   83 +++++++++++++++++++++++++++++++++++++-
>>  fs/internal.h                    |    1 +
>>  fs/isofs/inode.c                 |    4 +-
>>  fs/isofs/rock.c                  |    4 +-
>>  fs/jffs2/dir.c                   |    6 +-
>>  fs/jffs2/fs.c                    |    6 +-
>>  fs/jfs/jfs_imap.c                |    6 +-
>>  fs/jfs/jfs_inode.c               |    2 +-
>>  fs/jfs/namei.c                   |   12 +++---
>>  fs/jfs/super.c                   |    1 -
>>  fs/libfs.c                       |    2 +-
>>  fs/logfs/dir.c                   |    8 ++--
>>  fs/logfs/inode.c                 |    3 +-
>>  fs/logfs/readwrite.c             |    2 +-
>>  fs/minix/inode.c                 |    4 +-
>>  fs/namespace.c                   |   57 +++++++++++++++++++++++++-
>>  fs/ncpfs/inode.c                 |    2 +-
>>  fs/nfs/inode.c                   |    6 +-
>>  fs/nilfs2/inode.c                |    4 +-
>>  fs/nilfs2/namei.c                |    2 +-
>>  fs/ntfs/inode.c                  |    8 ++--
>>  fs/ocfs2/dir.c                   |    4 +-
>>  fs/ocfs2/dlmglue.c               |    2 +-
>>  fs/ocfs2/inode.c                 |    4 +-
>>  fs/ocfs2/namei.c                 |   18 ++++-----
>>  fs/openpromfs/inode.c            |    4 +-
>>  fs/proc/base.c                   |   12 +++---
>>  fs/proc/generic.c                |    2 +-
>>  fs/proc/inode.c                  |    2 +-
>>  fs/proc/proc_sysctl.c            |    2 +-
>>  fs/qnx4/inode.c                  |    2 +-
>>  fs/reiserfs/inode.c              |   10 ++--
>>  fs/reiserfs/namei.c              |   16 ++++----
>>  fs/romfs/super.c                 |    2 +-
>>  fs/squashfs/inode.c              |   18 ++++----
>>  fs/stack.c                       |    2 +-
>>  fs/super.c                       |   27 ++++++++++--
>>  fs/sysfs/inode.c                 |    2 +-
>>  fs/sysv/inode.c                  |    2 +-
>>  fs/ubifs/super.c                 |    2 +-
>>  fs/ubifs/xattr.c                 |    4 +-
>>  fs/udf/inode.c                   |    8 ++-
>>  fs/udf/namei.c                   |   15 +++----
>>  fs/ufs/ialloc.c                  |    2 +-
>>  fs/ufs/inode.c                   |    4 +-
>>  fs/xfs/xfs_iops.c                |    2 +-
>>  include/linux/fs.h               |   66 ++++++++++--------------------
>>  include/linux/mount.h            |    1 +
>>  mm/shmem.c                       |    2 +-
>>  106 files changed, 389 insertions(+), 286 deletions(-)



^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 0/13] read-only remount race fix v7
  2011-10-18  6:28   ` Toshiyuki Okajima
@ 2011-10-18  9:02     ` Miklos Szeredi
  0 siblings, 0 replies; 27+ messages in thread
From: Miklos Szeredi @ 2011-10-18  9:02 UTC (permalink / raw)
  To: toshi.okajima; +Cc: viro, linux-fsdevel, linux-kernel, jack, hch, akpm

Toshiyuki Okajima <toshi.okajima@jp.fujitsu.com> writes:

> Miklos-san,
>
> (2011/10/13 16:10), Toshiyuki Okajima wrote:
>> Hi.
>> 
>> (2011/10/12 23:48), Miklos Szeredi wrote:
>>> Here's an update of the read-only remount race fixes.
>>>
>>> It should now fix the races after unlink.  I haven't been able to
>>> trigger the bad behavior with the test scripts provided by Toshiyuki
>>> Okajima.
>>>
>>> Toshiyuki-san, could you please test these patches too?
>> OK. I will test them with ext4. Please wait.
> I have tested your latest patch set by my reproducer with ext4.
>
> On my environment, this reproducer usually detects
>  "EXT4-fs (xxx): Couldn't remount RDWR because of unprocessed orphan inode list"
> message within 20 minutes when I use your previous patch set.
> However, when I use your latest patche set, this producer has not yet 
> detected the message for 2 days.
>
> So, I think your latest patch set fixes the problem that delayed deletion 
> can start when we remount a superblock read-only.
>
> Tested-by: Toshiyuki Okajima <toshi.okajima@jp.fujitsu.com>

Thanks for testing.

Miklos

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 12/13] vfs: count unlinked inodes
  2011-10-12 14:49 ` [PATCH 12/13] vfs: count unlinked inodes Miklos Szeredi
@ 2011-10-28  6:08   ` Christoph Hellwig
  2011-10-28  7:53     ` Miklos Szeredi
  0 siblings, 1 reply; 27+ messages in thread
From: Christoph Hellwig @ 2011-10-28  6:08 UTC (permalink / raw)
  To: Miklos Szeredi
  Cc: viro, linux-fsdevel, linux-kernel, jack, hch, akpm, toshi.okajima,
	mszeredi

This one gets me a repeated spew of WARN_ONs during XFS log recover,
repeating the following pattern:

[ 1083.852789] ------------[ cut here ]------------
[ 1083.854471] WARNING: at /home/hch/work/linux-2.6/fs/inode.c:323
set_nlink+0x46/0x50()
[ 1083.857632] Hardware name: Bochs
[ 1083.858731] Modules linked in:
[ 1083.859932] Pid: 3111, comm: mount Not tainted 3.1.0+ #88
[ 1083.861735] Call Trace:
[ 1083.862694]  [<ffffffff8108743a>] warn_slowpath_common+0x7a/0xb0
[ 1083.864995]  [<ffffffff81087485>] warn_slowpath_null+0x15/0x20
[ 1083.867465]  [<ffffffff81153b76>] set_nlink+0x46/0x50
[ 1083.868970]  [<ffffffff813d70a9>] xfs_setup_inode+0x59/0x2b0
[ 1083.870817]  [<ffffffff813d1b36>] xfs_iget+0x386/0x880
[ 1083.871809]  [<ffffffff81427406>] xlog_recover_process_one_iunlink+0x46/0x1f0
[ 1083.872675]  [<ffffffff813c914c>] ? xfs_buf_rele+0x8c/0x1e0
[ 1083.873523]  [<ffffffff81427648>] xlog_recover_process_iunlinks+0x98/0x130
[ 1083.874378]  [<ffffffff8142833e>] xlog_recover_finish+0x3e/0xd0
[ 1083.875130]  [<ffffffff8142ebd4>] xfs_log_mount_finish+0x44/0x50
[ 1083.875933]  [<ffffffff8142b91e>] xfs_mountfs+0x51e/0x7c0
[ 1083.876748]  [<ffffffff813d8eda>] ? xfs_mru_cache_create+0x15a/0x180
[ 1083.877582]  [<ffffffff813db42d>] xfs_fs_fill_super+0x1cd/0x280
[ 1083.878399]  [<ffffffff8113e662>] mount_bdev+0x1a2/0x1e0
[ 1083.879090]  [<ffffffff813db260>] ? xfs_finish_flags+0x120/0x120
[ 1083.879881]  [<ffffffff813d92c0>] xfs_fs_mount+0x10/0x20
[ 1083.880716]  [<ffffffff8113f12b>] mount_fs+0x1b/0xd0
[ 1083.881374]  [<ffffffff81157e19>] vfs_kern_mount+0x69/0xf0
[ 1083.882117]  [<ffffffff811582af>] do_kern_mount+0x4f/0x100
[ 1083.882831]  [<ffffffff81159dd2>] do_mount+0x542/0x850
[ 1083.883642]  [<ffffffff81116621>] ? memdup_user+0x41/0x80
[ 1083.884347]  [<ffffffff811166b3>] ? strndup_user+0x53/0x70
[ 1083.885062]  [<ffffffff81180c6f>] compat_sys_mount+0xdf/0x260
[ 1083.885798]  [<ffffffff819e15c5>] sysenter_dispatch+0x7/0x2b
[ 1083.886518] ---[ end trace 4902e59f8848ff74 ]---

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 12/13] vfs: count unlinked inodes
  2011-10-28  6:08   ` Christoph Hellwig
@ 2011-10-28  7:53     ` Miklos Szeredi
  2011-10-28  8:04       ` Christoph Hellwig
  0 siblings, 1 reply; 27+ messages in thread
From: Miklos Szeredi @ 2011-10-28  7:53 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: Miklos Szeredi, viro, linux-fsdevel, linux-kernel, jack, akpm,
	toshi.okajima

On Fri, 2011-10-28 at 02:08 -0400, Christoph Hellwig wrote:
> This one gets me a repeated spew of WARN_ONs during XFS log recover,
> repeating the following pattern:

The assumption here is that set_nlink() is called with a non-zero count.
The point of introducing set_nlink() was to verify this assumption,
otherwise pending delete accounting will be screwed up.

If setting i_nlink to zero is not a bug in xfs we can do two things:

 1) do a conditional clear_nlink() in xfs_setup_inode() to document that
nlink can indeed be zero

 2) remove the warning from set_nlink().  That may hide some cases where
i_nlink was cleared without the intention of the filesystem but it will
work just fine wrt. the pending delete accounting. 

Thanks,
Miklos

> 
> [ 1083.852789] ------------[ cut here ]------------
> [ 1083.854471] WARNING: at /home/hch/work/linux-2.6/fs/inode.c:323
> set_nlink+0x46/0x50()
> [ 1083.857632] Hardware name: Bochs
> [ 1083.858731] Modules linked in:
> [ 1083.859932] Pid: 3111, comm: mount Not tainted 3.1.0+ #88
> [ 1083.861735] Call Trace:
> [ 1083.862694]  [<ffffffff8108743a>] warn_slowpath_common+0x7a/0xb0
> [ 1083.864995]  [<ffffffff81087485>] warn_slowpath_null+0x15/0x20
> [ 1083.867465]  [<ffffffff81153b76>] set_nlink+0x46/0x50
> [ 1083.868970]  [<ffffffff813d70a9>] xfs_setup_inode+0x59/0x2b0
> [ 1083.870817]  [<ffffffff813d1b36>] xfs_iget+0x386/0x880
> [ 1083.871809]  [<ffffffff81427406>] xlog_recover_process_one_iunlink+0x46/0x1f0
> [ 1083.872675]  [<ffffffff813c914c>] ? xfs_buf_rele+0x8c/0x1e0
> [ 1083.873523]  [<ffffffff81427648>] xlog_recover_process_iunlinks+0x98/0x130
> [ 1083.874378]  [<ffffffff8142833e>] xlog_recover_finish+0x3e/0xd0
> [ 1083.875130]  [<ffffffff8142ebd4>] xfs_log_mount_finish+0x44/0x50
> [ 1083.875933]  [<ffffffff8142b91e>] xfs_mountfs+0x51e/0x7c0
> [ 1083.876748]  [<ffffffff813d8eda>] ? xfs_mru_cache_create+0x15a/0x180
> [ 1083.877582]  [<ffffffff813db42d>] xfs_fs_fill_super+0x1cd/0x280
> [ 1083.878399]  [<ffffffff8113e662>] mount_bdev+0x1a2/0x1e0
> [ 1083.879090]  [<ffffffff813db260>] ? xfs_finish_flags+0x120/0x120
> [ 1083.879881]  [<ffffffff813d92c0>] xfs_fs_mount+0x10/0x20
> [ 1083.880716]  [<ffffffff8113f12b>] mount_fs+0x1b/0xd0
> [ 1083.881374]  [<ffffffff81157e19>] vfs_kern_mount+0x69/0xf0
> [ 1083.882117]  [<ffffffff811582af>] do_kern_mount+0x4f/0x100
> [ 1083.882831]  [<ffffffff81159dd2>] do_mount+0x542/0x850
> [ 1083.883642]  [<ffffffff81116621>] ? memdup_user+0x41/0x80
> [ 1083.884347]  [<ffffffff811166b3>] ? strndup_user+0x53/0x70
> [ 1083.885062]  [<ffffffff81180c6f>] compat_sys_mount+0xdf/0x260
> [ 1083.885798]  [<ffffffff819e15c5>] sysenter_dispatch+0x7/0x2b
> [ 1083.886518] ---[ end trace 4902e59f8848ff74 ]---
> 

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 12/13] vfs: count unlinked inodes
  2011-10-28  7:53     ` Miklos Szeredi
@ 2011-10-28  8:04       ` Christoph Hellwig
  2011-10-28  8:20         ` Miklos Szeredi
  0 siblings, 1 reply; 27+ messages in thread
From: Christoph Hellwig @ 2011-10-28  8:04 UTC (permalink / raw)
  To: Miklos Szeredi
  Cc: Christoph Hellwig, Miklos Szeredi, viro, linux-fsdevel,
	linux-kernel, jack, akpm, toshi.okajima

On Fri, Oct 28, 2011 at 09:53:53AM +0200, Miklos Szeredi wrote:
> On Fri, 2011-10-28 at 02:08 -0400, Christoph Hellwig wrote:
> > This one gets me a repeated spew of WARN_ONs during XFS log recover,
> > repeating the following pattern:
> 
> The assumption here is that set_nlink() is called with a non-zero count.
> The point of introducing set_nlink() was to verify this assumption,
> otherwise pending delete accounting will be screwed up.
> 
> If setting i_nlink to zero is not a bug in xfs we can do two things:
> 
>  1) do a conditional clear_nlink() in xfs_setup_inode() to document that
> nlink can indeed be zero
> 
>  2) remove the warning from set_nlink().  That may hide some cases where
> i_nlink was cleared without the intention of the filesystem but it will
> work just fine wrt. the pending delete accounting. 

I suspect 2 might be the better option.  The pattern we see here in
XFS is pretty typical for transactional filesytems - when we mount a
filesystem after an unclean shutdown we need to drop all inodes that
were open but unlinked when the system crashed, and that typically
means reading inodes from disk that have a zero i_nlink.  Maybe some
filesystems never instanciate a VFS inode for it, but I suspect many
do.

For XFS we will actually see it during regularly testing as we have
an ioctl that simulates a shutdown and can thus trigger log recovery
easily, while for others like ext4 you'd actually have to do a real
reset of your (physical or virtual) machine.

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 12/13] vfs: count unlinked inodes
  2011-10-28  8:04       ` Christoph Hellwig
@ 2011-10-28  8:20         ` Miklos Szeredi
  2011-10-28  8:29           ` Christoph Hellwig
  0 siblings, 1 reply; 27+ messages in thread
From: Miklos Szeredi @ 2011-10-28  8:20 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: viro, linux-fsdevel, linux-kernel, jack, akpm, toshi.okajima

Christoph Hellwig <hch@infradead.org> writes:

> On Fri, Oct 28, 2011 at 09:53:53AM +0200, Miklos Szeredi wrote:
>> On Fri, 2011-10-28 at 02:08 -0400, Christoph Hellwig wrote:
>> > This one gets me a repeated spew of WARN_ONs during XFS log recover,
>> > repeating the following pattern:
>> 
>> The assumption here is that set_nlink() is called with a non-zero count.
>> The point of introducing set_nlink() was to verify this assumption,
>> otherwise pending delete accounting will be screwed up.
>> 
>> If setting i_nlink to zero is not a bug in xfs we can do two things:
>> 
>>  1) do a conditional clear_nlink() in xfs_setup_inode() to document that
>> nlink can indeed be zero
>> 
>>  2) remove the warning from set_nlink().  That may hide some cases where
>> i_nlink was cleared without the intention of the filesystem but it will
>> work just fine wrt. the pending delete accounting. 
>
> I suspect 2 might be the better option.  The pattern we see here in
> XFS is pretty typical for transactional filesytems - when we mount a
> filesystem after an unclean shutdown we need to drop all inodes that
> were open but unlinked when the system crashed, and that typically
> means reading inodes from disk that have a zero i_nlink.  Maybe some
> filesystems never instanciate a VFS inode for it, but I suspect many
> do.
>
> For XFS we will actually see it during regularly testing as we have
> an ioctl that simulates a shutdown and can thus trigger log recovery
> easily, while for others like ext4 you'd actually have to do a real
> reset of your (physical or virtual) machine.

Okay, so a WARN_ON is not warranted.  Perhaps a printk instead?

While initializing nlink with zero normally shouldn't be a problem it
might indicate something unexpected.

Thanks,
Miklos

---
 fs/inode.c |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

Index: linux-2.6/fs/inode.c
===================================================================
--- linux-2.6.orig/fs/inode.c	2011-10-27 22:26:12.000000000 +0200
+++ linux-2.6/fs/inode.c	2011-10-28 10:14:18.000000000 +0200
@@ -320,7 +320,8 @@ EXPORT_SYMBOL(clear_nlink);
  */
 void set_nlink(struct inode *inode, unsigned int nlink)
 {
-	if (WARN_ON(!nlink)) {
+	if (!nlink) {
+		printk(KERN_INFO "set_nlink() clearing i_nlink on %s inode %li\n", inode->i_sb->s_type->name, inode->i_ino);
 		clear_nlink(inode);
 	} else {
 		/* Yes, some filesystems do change nlink from zero to one */

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 12/13] vfs: count unlinked inodes
  2011-10-28  8:20         ` Miklos Szeredi
@ 2011-10-28  8:29           ` Christoph Hellwig
  0 siblings, 0 replies; 27+ messages in thread
From: Christoph Hellwig @ 2011-10-28  8:29 UTC (permalink / raw)
  To: Miklos Szeredi
  Cc: Christoph Hellwig, viro, linux-fsdevel, linux-kernel, jack, akpm,
	toshi.okajima

On Fri, Oct 28, 2011 at 10:20:06AM +0200, Miklos Szeredi wrote:
> Okay, so a WARN_ON is not warranted.  Perhaps a printk instead?
> 
> While initializing nlink with zero normally shouldn't be a problem it
> might indicate something unexpected.

Please do a ratelimited printk.  If the log recovery case hits any fs
it will usually do it for tons of inodes in a short period.

Also please try to stick to 80 character lines if possible.

^ permalink raw reply	[flat|nested] 27+ messages in thread

end of thread, other threads:[~2011-10-28  8:29 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-10-12 14:48 [PATCH 0/13] read-only remount race fix v7 Miklos Szeredi
2011-10-12 14:48 ` [PATCH 01/13] vfs: ignore error on forced remount Miklos Szeredi
2011-10-12 14:48 ` [PATCH 02/13] vfs: keep list of mounts for each superblock Miklos Szeredi
2011-10-12 14:48 ` [PATCH 03/13] vfs: protect remounting superblock read-only Miklos Szeredi
2011-10-12 14:48 ` [PATCH 04/13] vfs: fs_may_remount_ro: turn unnecessary check into a WARN_ON Miklos Szeredi
2011-10-12 14:48 ` [PATCH 05/13] hypfs: remove unnecessary nlink setting Miklos Szeredi
2011-10-12 14:48 ` [PATCH 06/13] jfs: " Miklos Szeredi
2011-10-12 15:26   ` Dave Kleikamp
2011-10-12 14:49 ` [PATCH 07/13] ocfs2: " Miklos Szeredi
2011-10-12 14:49 ` [PATCH 08/13] logfs: " Miklos Szeredi
2011-10-12 14:49 ` [PATCH 09/13] filesystems: add missing nlink wrappers Miklos Szeredi
2011-10-12 14:49 ` [PATCH 10/13] filesystems: add set_nlink() Miklos Szeredi
2011-10-13 16:33   ` Steven Whitehouse
2011-10-14 15:04     ` Miklos Szeredi
2011-10-12 14:49 ` [PATCH 11/13] vfs: protect i_nlink Miklos Szeredi
2011-10-12 14:49 ` [PATCH 12/13] vfs: count unlinked inodes Miklos Szeredi
2011-10-28  6:08   ` Christoph Hellwig
2011-10-28  7:53     ` Miklos Szeredi
2011-10-28  8:04       ` Christoph Hellwig
2011-10-28  8:20         ` Miklos Szeredi
2011-10-28  8:29           ` Christoph Hellwig
2011-10-12 14:49 ` [PATCH 13/13] vfs: prevent remount read-only if pending removes Miklos Szeredi
2011-10-12 15:03 ` [PATCH 0/13] read-only remount race fix v7 Christoph Hellwig
2011-10-12 15:09   ` Miklos Szeredi
2011-10-13  7:10 ` Toshiyuki Okajima
2011-10-18  6:28   ` Toshiyuki Okajima
2011-10-18  9:02     ` Miklos Szeredi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).