public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/6] read-only bind mount prep work
@ 2006-08-09 16:57 Dave Hansen
  2006-08-09 16:57 ` [PATCH 1/6] prepare for write access checks: collapse if() Dave Hansen
                   ` (5 more replies)
  0 siblings, 6 replies; 21+ messages in thread
From: Dave Hansen @ 2006-08-09 16:57 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel, hch, Dave Hansen

The following patches lay some of the groundwork for the
read-only bind mounts.  Christoph Hellwig suggested that
I send them in separately.  This was a good suggestion,
as the bulk of the modifications of the entire set happen
in here, and these should make no functional changes, and
should be pretty easy to merge.

-- Dave

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

* [PATCH 1/6] prepare for write access checks: collapse if()
  2006-08-09 16:57 [PATCH 0/6] read-only bind mount prep work Dave Hansen
@ 2006-08-09 16:57 ` Dave Hansen
  2006-08-09 17:09   ` Christoph Hellwig
  2006-08-09 16:57 ` [PATCH 2/6] r/o bind mount prepwork: move open_namei()'s vfs_create() Dave Hansen
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 21+ messages in thread
From: Dave Hansen @ 2006-08-09 16:57 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel, hch, Dave Hansen


We're shortly going to be adding a bunch more permission
checks in these functions.  That requires adding either a
bunch of new if() conditions, or some gotos.  This patch
collapses existing if()s and uses gotos instead to
prepare for the upcoming changes.

Signed-off-by: Dave Hansen <haveblue@us.ibm.com>
---

 lxc-dave/fs/namei.c |   93 +++++++++++++++++++++++++++-------------------------
 lxc-dave/fs/open.c  |   64 ++++++++++++++++++++---------------
 2 files changed, 87 insertions(+), 70 deletions(-)

diff -puN fs/namei.c~B1-prepwork-collapse-ifs fs/namei.c
--- lxc/fs/namei.c~B1-prepwork-collapse-ifs	2006-08-06 03:21:02.000000000 -0700
+++ lxc-dave/fs/namei.c	2006-08-08 09:18:49.000000000 -0700
@@ -1926,30 +1926,32 @@ asmlinkage long sys_mkdirat(int dfd, con
 {
 	int error = 0;
 	char * tmp;
+	struct dentry *dentry;
+	struct nameidata nd;
 
 	tmp = getname(pathname);
 	error = PTR_ERR(tmp);
-	if (!IS_ERR(tmp)) {
-		struct dentry *dentry;
-		struct nameidata nd;
+	if (IS_ERR(tmp))
+		goto out_err;
 
-		error = do_path_lookup(dfd, tmp, LOOKUP_PARENT, &nd);
-		if (error)
-			goto out;
-		dentry = lookup_create(&nd, 1);
-		error = PTR_ERR(dentry);
-		if (!IS_ERR(dentry)) {
-			if (!IS_POSIXACL(nd.dentry->d_inode))
-				mode &= ~current->fs->umask;
-			error = vfs_mkdir(nd.dentry->d_inode, dentry, mode);
-			dput(dentry);
-		}
-		mutex_unlock(&nd.dentry->d_inode->i_mutex);
-		path_release(&nd);
-out:
-		putname(tmp);
-	}
+	error = do_path_lookup(dfd, tmp, LOOKUP_PARENT, &nd);
+	if (error)
+		goto out;
+	dentry = lookup_create(&nd, 1);
+	error = PTR_ERR(dentry);
+	if (IS_ERR(dentry))
+		goto out_unlock;
 
+	if (!IS_POSIXACL(nd.dentry->d_inode))
+		mode &= ~current->fs->umask;
+	error = vfs_mkdir(nd.dentry->d_inode, dentry, mode);
+	dput(dentry);
+out_unlock:
+	mutex_unlock(&nd.dentry->d_inode->i_mutex);
+	path_release(&nd);
+out:
+	putname(tmp);
+out_err:
 	return error;
 }
 
@@ -2048,10 +2050,11 @@ static long do_rmdir(int dfd, const char
 	mutex_lock_nested(&nd.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
 	dentry = lookup_hash(&nd);
 	error = PTR_ERR(dentry);
-	if (!IS_ERR(dentry)) {
-		error = vfs_rmdir(nd.dentry->d_inode, dentry);
-		dput(dentry);
-	}
+	if (IS_ERR(dentry))
+		goto exit2;
+	error = vfs_rmdir(nd.dentry->d_inode, dentry);
+	dput(dentry);
+exit2:
 	mutex_unlock(&nd.dentry->d_inode->i_mutex);
 exit1:
 	path_release(&nd);
@@ -2191,30 +2194,33 @@ asmlinkage long sys_symlinkat(const char
 	int error = 0;
 	char * from;
 	char * to;
+	struct dentry *dentry;
+	struct nameidata nd;
 
 	from = getname(oldname);
 	if(IS_ERR(from))
 		return PTR_ERR(from);
 	to = getname(newname);
 	error = PTR_ERR(to);
-	if (!IS_ERR(to)) {
-		struct dentry *dentry;
-		struct nameidata nd;
+	if (IS_ERR(to))
+		goto out_putname;
 
-		error = do_path_lookup(newdfd, to, LOOKUP_PARENT, &nd);
-		if (error)
-			goto out;
-		dentry = lookup_create(&nd, 0);
-		error = PTR_ERR(dentry);
-		if (!IS_ERR(dentry)) {
-			error = vfs_symlink(nd.dentry->d_inode, dentry, from, S_IALLUGO);
-			dput(dentry);
-		}
-		mutex_unlock(&nd.dentry->d_inode->i_mutex);
-		path_release(&nd);
+	error = do_path_lookup(newdfd, to, LOOKUP_PARENT, &nd);
+	if (error)
+		goto out;
+	dentry = lookup_create(&nd, 0);
+	error = PTR_ERR(dentry);
+	if (IS_ERR(dentry))
+		goto out_unlock;
+
+	error = vfs_symlink(nd.dentry->d_inode, dentry, from, S_IALLUGO);
+	dput(dentry);
+out_unlock:
+	mutex_unlock(&nd.dentry->d_inode->i_mutex);
+	path_release(&nd);
 out:
-		putname(to);
-	}
+	putname(to);
+out_putname:
 	putname(from);
 	return error;
 }
@@ -2300,10 +2306,11 @@ asmlinkage long sys_linkat(int olddfd, c
 		goto out_release;
 	new_dentry = lookup_create(&nd, 0);
 	error = PTR_ERR(new_dentry);
-	if (!IS_ERR(new_dentry)) {
-		error = vfs_link(old_nd.dentry, nd.dentry->d_inode, new_dentry);
-		dput(new_dentry);
-	}
+	if (IS_ERR(new_dentry))
+		goto out_unlock;
+	error = vfs_link(old_nd.dentry, nd.dentry->d_inode, new_dentry);
+	dput(new_dentry);
+out_unlock:
 	mutex_unlock(&nd.dentry->d_inode->i_mutex);
 out_release:
 	path_release(&nd);
diff -puN fs/open.c~B1-prepwork-collapse-ifs fs/open.c
--- lxc/fs/open.c~B1-prepwork-collapse-ifs	2006-08-06 03:21:03.000000000 -0700
+++ lxc-dave/fs/open.c	2006-08-08 09:18:49.000000000 -0700
@@ -520,15 +520,21 @@ asmlinkage long sys_faccessat(int dfd, c
 		current->cap_effective = current->cap_permitted;
 
 	res = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW|LOOKUP_ACCESS, &nd);
-	if (!res) {
-		res = vfs_permission(&nd, mode);
-		/* SuS v2 requires we report a read only fs too */
-		if(!res && (mode & S_IWOTH) && IS_RDONLY(nd.dentry->d_inode)
-		   && !special_file(nd.dentry->d_inode->i_mode))
-			res = -EROFS;
-		path_release(&nd);
-	}
+	if (res)
+		goto out;
+
+	res = vfs_permission(&nd, mode);
+	/* SuS v2 requires we report a read only fs too */
+	if(res || !(mode & S_IWOTH) ||
+	   special_file(nd.dentry->d_inode->i_mode))
+		goto out_path_release;
+
+	if(IS_RDONLY(nd.dentry->d_inode))
+		res = -EROFS;
 
+out_path_release:
+	path_release(&nd);
+out:
 	current->fsuid = old_fsuid;
 	current->fsgid = old_fsgid;
 	current->cap_effective = old_cap;
@@ -737,10 +743,11 @@ asmlinkage long sys_chown(const char __u
 	int error;
 
 	error = user_path_walk(filename, &nd);
-	if (!error) {
-		error = chown_common(nd.dentry, user, group);
-		path_release(&nd);
-	}
+	if (error)
+		goto out;
+	error = chown_common(nd.dentry, user, group);
+	path_release(&nd);
+out:
 	return error;
 }
 
@@ -756,10 +763,10 @@ asmlinkage long sys_fchownat(int dfd, co
 
 	follow = (flag & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW;
 	error = __user_walk_fd(dfd, filename, follow, &nd);
-	if (!error) {
-		error = chown_common(nd.dentry, user, group);
-		path_release(&nd);
-	}
+	if (error)
+		goto out;
+	error = chown_common(nd.dentry, user, group);
+	path_release(&nd);
 out:
 	return error;
 }
@@ -770,10 +777,11 @@ asmlinkage long sys_lchown(const char __
 	int error;
 
 	error = user_path_walk_link(filename, &nd);
-	if (!error) {
-		error = chown_common(nd.dentry, user, group);
-		path_release(&nd);
-	}
+	if (error)
+		goto out;
+	error = chown_common(nd.dentry, user, group);
+	path_release(&nd);
+out:
 	return error;
 }
 
@@ -782,15 +790,17 @@ asmlinkage long sys_fchown(unsigned int 
 {
 	struct file * file;
 	int error = -EBADF;
+	struct dentry * dentry;
 
 	file = fget(fd);
-	if (file) {
-		struct dentry * dentry;
-		dentry = file->f_dentry;
-		audit_inode(NULL, dentry->d_inode);
-		error = chown_common(dentry, user, group);
-		fput(file);
-	}
+	if (!file)
+		goto out;
+
+	dentry = file->f_dentry;
+	audit_inode(NULL, dentry->d_inode);
+	error = chown_common(dentry, user, group);
+	fput(file);
+out:
 	return error;
 }
 
_

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

* [PATCH 2/6] r/o bind mount prepwork: move open_namei()'s vfs_create()
  2006-08-09 16:57 [PATCH 0/6] read-only bind mount prep work Dave Hansen
  2006-08-09 16:57 ` [PATCH 1/6] prepare for write access checks: collapse if() Dave Hansen
@ 2006-08-09 16:57 ` Dave Hansen
  2006-08-09 17:09   ` Christoph Hellwig
  2006-08-09 16:57 ` [PATCH 4/6] r/o bind mount prepwork: inc_nlink() helper Dave Hansen
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 21+ messages in thread
From: Dave Hansen @ 2006-08-09 16:57 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel, hch, Dave Hansen


The code around vfs_create() in open_namei() is getting a
bit too complex.  Right now, there is at least the reference
count on the dentry, and the i_mutex to worry about.  Soon,
we'll also have mnt_writecount.

So, break the vfs_create() call out of open_namei(), and
into a helper function.  This duplicates the call to
may_open(), but that isn't such a bad thing since the
arguments (acc_mode and flag) were being heavily massaged
anyway.

Signed-off-by: Dave Hansen <haveblue@us.ibm.com>
---

 lxc-dave/fs/namei.c |   30 ++++++++++++++++++++----------
 1 files changed, 20 insertions(+), 10 deletions(-)

diff -puN fs/namei.c~B2-prepwork-cleanup-open_namei fs/namei.c
--- lxc/fs/namei.c~B2-prepwork-cleanup-open_namei	2006-08-08 09:18:49.000000000 -0700
+++ lxc-dave/fs/namei.c	2006-08-08 09:18:50.000000000 -0700
@@ -1587,6 +1587,24 @@ int may_open(struct nameidata *nd, int a
 	return 0;
 }
 
+static int open_namei_create(struct nameidata *nd, struct path *path,
+				int flag, int mode)
+{
+	int error;
+	struct dentry *dir = nd->dentry;
+
+	if (!IS_POSIXACL(dir->d_inode))
+		mode &= ~current->fs->umask;
+	error = vfs_create(dir->d_inode, path->dentry, mode, nd);
+	mutex_unlock(&dir->d_inode->i_mutex);
+	dput(nd->dentry);
+	nd->dentry = path->dentry;
+	if (error)
+		return error;
+	/* Don't check for write permission, don't truncate */
+	return may_open(nd, 0, flag & ~O_TRUNC);
+}
+
 /*
  *	open_namei()
  *
@@ -1668,18 +1686,10 @@ do_last:
 
 	/* Negative dentry, just create the file */
 	if (!path.dentry->d_inode) {
-		if (!IS_POSIXACL(dir->d_inode))
-			mode &= ~current->fs->umask;
-		error = vfs_create(dir->d_inode, path.dentry, mode, nd);
-		mutex_unlock(&dir->d_inode->i_mutex);
-		dput(nd->dentry);
-		nd->dentry = path.dentry;
+		error = open_namei_create(nd, &path, flag, mode);
 		if (error)
 			goto exit;
-		/* Don't check for write permission, don't truncate */
-		acc_mode = 0;
-		flag &= ~O_TRUNC;
-		goto ok;
+		return 0;
 	}
 
 	/*
_

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

* [PATCH 4/6] r/o bind mount prepwork: inc_nlink() helper
  2006-08-09 16:57 [PATCH 0/6] read-only bind mount prep work Dave Hansen
  2006-08-09 16:57 ` [PATCH 1/6] prepare for write access checks: collapse if() Dave Hansen
  2006-08-09 16:57 ` [PATCH 2/6] r/o bind mount prepwork: move open_namei()'s vfs_create() Dave Hansen
@ 2006-08-09 16:57 ` Dave Hansen
  2006-08-09 17:11   ` Christoph Hellwig
  2006-08-09 16:57 ` [PATCH 3/6] unlink: monitor i_nlink Dave Hansen
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 21+ messages in thread
From: Dave Hansen @ 2006-08-09 16:57 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel, hch, Dave Hansen


This is mostly included for parity with dec_nlink(), where
we will have some more hooks.  This one should stay pretty
darn straightforward for now.


Signed-off-by: Dave Hansen <haveblue@us.ibm.com>
---

 lxc-dave/drivers/infiniband/hw/ipath/ipath_fs.c |    4 ++--
 lxc-dave/drivers/usb/core/inode.c               |    4 ++--
 lxc-dave/fs/9p/vfs_inode.c                      |    2 +-
 lxc-dave/fs/autofs/root.c                       |    2 +-
 lxc-dave/fs/autofs4/root.c                      |    2 +-
 lxc-dave/fs/bfs/dir.c                           |    2 +-
 lxc-dave/fs/cifs/inode.c                        |    2 +-
 lxc-dave/fs/coda/dir.c                          |    2 +-
 lxc-dave/fs/configfs/dir.c                      |    4 ++--
 lxc-dave/fs/configfs/mount.c                    |    2 +-
 lxc-dave/fs/debugfs/inode.c                     |    4 ++--
 lxc-dave/fs/ext3/namei.c                        |    6 +++---
 lxc-dave/fs/fuse/control.c                      |    2 +-
 lxc-dave/fs/hfsplus/dir.c                       |    2 +-
 lxc-dave/fs/hpfs/namei.c                        |    4 ++--
 lxc-dave/fs/hugetlbfs/inode.c                   |    4 ++--
 lxc-dave/fs/jffs2/dir.c                         |    6 +++---
 lxc-dave/fs/jffs2/fs.c                          |    6 +++---
 lxc-dave/fs/jfs/namei.c                         |    6 +++---
 lxc-dave/fs/libfs.c                             |    4 ++--
 lxc-dave/fs/msdos/namei.c                       |    4 ++--
 lxc-dave/fs/ocfs2/dlm/dlmfs.c                   |    6 +++---
 lxc-dave/fs/ocfs2/namei.c                       |    8 ++++----
 lxc-dave/fs/ramfs/inode.c                       |    4 ++--
 lxc-dave/fs/reiserfs/namei.c                    |    6 +++---
 lxc-dave/fs/sysfs/dir.c                         |    4 ++--
 lxc-dave/fs/sysfs/mount.c                       |    2 +-
 lxc-dave/fs/udf/inode.c                         |    2 +-
 lxc-dave/fs/udf/namei.c                         |    6 +++---
 lxc-dave/fs/vfat/namei.c                        |    4 ++--
 lxc-dave/include/linux/fs.h                     |    7 ++++++-
 lxc-dave/ipc/mqueue.c                           |    2 +-
 lxc-dave/kernel/cpuset.c                        |    8 ++++----
 lxc-dave/mm/shmem.c                             |    8 ++++----
 lxc-dave/net/sunrpc/rpc_pipe.c                  |    6 +++---
 lxc-dave/security/inode.c                       |    4 ++--
 lxc-dave/security/selinux/selinuxfs.c           |    4 ++--
 37 files changed, 80 insertions(+), 75 deletions(-)

diff -puN include/linux/fs.h~B4-monitor_inc_nlink include/linux/fs.h
--- lxc/include/linux/fs.h~B4-monitor_inc_nlink	2006-08-08 10:57:11.000000000 -0700
+++ lxc-dave/include/linux/fs.h	2006-08-08 10:57:59.000000000 -0700
@@ -1256,9 +1256,14 @@ static inline void mark_inode_dirty_sync
 	__mark_inode_dirty(inode, I_DIRTY_SYNC);
 }
 
-static inline void inode_inc_link_count(struct inode *inode)
+static inline void inc_nlink(struct inode *inode)
 {
 	inode->i_nlink++;
+}
+
+static inline void inode_inc_link_count(struct inode *inode)
+{
+	inc_nlink(inode);
 	mark_inode_dirty(inode);
 }
 
diff -puN fs/libfs.c~B4-monitor_inc_nlink fs/libfs.c
--- lxc/fs/libfs.c~B4-monitor_inc_nlink	2006-08-08 10:57:11.000000000 -0700
+++ lxc-dave/fs/libfs.c	2006-08-08 10:57:59.000000000 -0700
@@ -243,7 +243,7 @@ int simple_link(struct dentry *old_dentr
 	struct inode *inode = old_dentry->d_inode;
 
 	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
-	inode->i_nlink++;
+	inc_nlink(inode);
 	atomic_inc(&inode->i_count);
 	dget(dentry);
 	d_instantiate(dentry, inode);
@@ -306,7 +306,7 @@ int simple_rename(struct inode *old_dir,
 			drop_nlink(old_dir);
 	} else if (they_are_dirs) {
 		drop_nlink(old_dir);
-		new_dir->i_nlink++;
+		inc_nlink(new_dir);
 	}
 
 	old_dir->i_ctime = old_dir->i_mtime = new_dir->i_ctime =
diff -puN mm/shmem.c~B4-monitor_inc_nlink mm/shmem.c
--- lxc/mm/shmem.c~B4-monitor_inc_nlink	2006-08-08 10:57:11.000000000 -0700
+++ lxc-dave/mm/shmem.c	2006-08-08 10:57:59.000000000 -0700
@@ -1371,7 +1371,7 @@ shmem_get_inode(struct super_block *sb, 
 							&sbinfo->policy_nodes);
 			break;
 		case S_IFDIR:
-			inode->i_nlink++;
+			inc_nlink(inode);
 			/* Some things misbehave if size == 0 on a directory */
 			inode->i_size = 2 * BOGO_DIRENT_SIZE;
 			inode->i_op = &shmem_dir_inode_operations;
@@ -1703,7 +1703,7 @@ static int shmem_mkdir(struct inode *dir
 
 	if ((error = shmem_mknod(dir, dentry, mode | S_IFDIR, 0)))
 		return error;
-	dir->i_nlink++;
+	inc_nlink(dir);
 	return 0;
 }
 
@@ -1738,7 +1738,7 @@ static int shmem_link(struct dentry *old
 
 	dir->i_size += BOGO_DIRENT_SIZE;
 	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
-	inode->i_nlink++;
+	inc_nlink(inode);
 	atomic_inc(&inode->i_count);	/* New dentry reference */
 	dget(dentry);		/* Extra pinning count for the created dentry */
 	d_instantiate(dentry, inode);
@@ -1795,7 +1795,7 @@ static int shmem_rename(struct inode *ol
 			drop_nlink(old_dir);
 	} else if (they_are_dirs) {
 		drop_nlink(old_dir);
-		new_dir->i_nlink++;
+		inc_nlink(new_dir);
 	}
 
 	old_dir->i_size -= BOGO_DIRENT_SIZE;
diff -puN drivers/infiniband/hw/ipath/ipath_fs.c~B4-monitor_inc_nlink drivers/infiniband/hw/ipath/ipath_fs.c
--- lxc/drivers/infiniband/hw/ipath/ipath_fs.c~B4-monitor_inc_nlink	2006-08-08 09:30:58.000000000 -0700
+++ lxc-dave/drivers/infiniband/hw/ipath/ipath_fs.c	2006-08-08 10:57:59.000000000 -0700
@@ -66,8 +66,8 @@ static int ipathfs_mknod(struct inode *d
 	inode->i_private = data;
 	if ((mode & S_IFMT) == S_IFDIR) {
 		inode->i_op = &simple_dir_inode_operations;
-		inode->i_nlink++;
-		dir->i_nlink++;
+		inc_nlink(inode);
+		inc_nlink(dir);
 	}
 
 	inode->i_fop = fops;
diff -puN drivers/usb/core/inode.c~B4-monitor_inc_nlink drivers/usb/core/inode.c
--- lxc/drivers/usb/core/inode.c~B4-monitor_inc_nlink	2006-08-08 10:57:11.000000000 -0700
+++ lxc-dave/drivers/usb/core/inode.c	2006-08-08 10:57:59.000000000 -0700
@@ -263,7 +263,7 @@ static struct inode *usbfs_get_inode (st
 			inode->i_fop = &simple_dir_operations;
 
 			/* directory inodes start off with i_nlink == 2 (for "." entry) */
-			inode->i_nlink++;
+			inc_nlink(inode);
 			break;
 		}
 	}
@@ -295,7 +295,7 @@ static int usbfs_mkdir (struct inode *di
 	mode = (mode & (S_IRWXUGO | S_ISVTX)) | S_IFDIR;
 	res = usbfs_mknod (dir, dentry, mode, 0);
 	if (!res)
-		dir->i_nlink++;
+		inc_nlink(dir);
 	return res;
 }
 
diff -puN fs/9p/vfs_inode.c~B4-monitor_inc_nlink fs/9p/vfs_inode.c
--- lxc/fs/9p/vfs_inode.c~B4-monitor_inc_nlink	2006-08-08 09:30:58.000000000 -0700
+++ lxc-dave/fs/9p/vfs_inode.c	2006-08-08 10:57:59.000000000 -0700
@@ -233,7 +233,7 @@ struct inode *v9fs_get_inode(struct supe
 			inode->i_op = &v9fs_symlink_inode_operations;
 			break;
 		case S_IFDIR:
-			inode->i_nlink++;
+			inc_nlink(inode);
 			if(v9ses->extended)
 				inode->i_op = &v9fs_dir_inode_operations_ext;
 			else
diff -puN fs/autofs/root.c~B4-monitor_inc_nlink fs/autofs/root.c
--- lxc/fs/autofs/root.c~B4-monitor_inc_nlink	2006-08-08 10:57:11.000000000 -0700
+++ lxc-dave/fs/autofs/root.c	2006-08-08 10:57:59.000000000 -0700
@@ -466,7 +466,7 @@ static int autofs_root_mkdir(struct inod
 	ent->dentry = dentry;
 	autofs_hash_insert(dh,ent);
 
-	dir->i_nlink++;
+	inc_nlink(dir);
 	d_instantiate(dentry, iget(dir->i_sb,ino));
 	unlock_kernel();
 
diff -puN fs/autofs4/root.c~B4-monitor_inc_nlink fs/autofs4/root.c
--- lxc/fs/autofs4/root.c~B4-monitor_inc_nlink	2006-08-08 10:57:11.000000000 -0700
+++ lxc-dave/fs/autofs4/root.c	2006-08-08 10:57:59.000000000 -0700
@@ -713,7 +713,7 @@ static int autofs4_dir_mkdir(struct inod
 	if (p_ino && dentry->d_parent != dentry)
 		atomic_inc(&p_ino->count);
 	ino->inode = inode;
-	dir->i_nlink++;
+	inc_nlink(dir);
 	dir->i_mtime = CURRENT_TIME;
 
 	return 0;
diff -puN fs/bfs/dir.c~B4-monitor_inc_nlink fs/bfs/dir.c
--- lxc/fs/bfs/dir.c~B4-monitor_inc_nlink	2006-08-08 10:57:11.000000000 -0700
+++ lxc-dave/fs/bfs/dir.c	2006-08-08 10:57:59.000000000 -0700
@@ -163,7 +163,7 @@ static int bfs_link(struct dentry * old,
 		unlock_kernel();
 		return err;
 	}
-	inode->i_nlink++;
+	inc_nlink(inode);
 	inode->i_ctime = CURRENT_TIME_SEC;
 	mark_inode_dirty(inode);
 	atomic_inc(&inode->i_count);
diff -puN fs/cifs/inode.c~B4-monitor_inc_nlink fs/cifs/inode.c
--- lxc/fs/cifs/inode.c~B4-monitor_inc_nlink	2006-08-08 10:57:11.000000000 -0700
+++ lxc-dave/fs/cifs/inode.c	2006-08-08 10:57:59.000000000 -0700
@@ -736,7 +736,7 @@ int cifs_mkdir(struct inode *inode, stru
 		cFYI(1, ("cifs_mkdir returned 0x%x", rc));
 		d_drop(direntry);
 	} else {
-		inode->i_nlink++;
+		inc_nlink(inode);
 		if (pTcon->ses->capabilities & CAP_UNIX)
 			rc = cifs_get_inode_info_unix(&newinode, full_path,
 						      inode->i_sb,xid);
diff -puN fs/coda/dir.c~B4-monitor_inc_nlink fs/coda/dir.c
--- lxc/fs/coda/dir.c~B4-monitor_inc_nlink	2006-08-08 10:57:11.000000000 -0700
+++ lxc-dave/fs/coda/dir.c	2006-08-08 10:57:59.000000000 -0700
@@ -304,7 +304,7 @@ static int coda_link(struct dentry *sour
 	coda_dir_changed(dir_inode, 0);
 	atomic_inc(&inode->i_count);
 	d_instantiate(de, inode);
-	inode->i_nlink++;
+	inc_nlink(inode);
         
 out:
 	unlock_kernel();
diff -puN fs/configfs/dir.c~B4-monitor_inc_nlink fs/configfs/dir.c
--- lxc/fs/configfs/dir.c~B4-monitor_inc_nlink	2006-08-08 09:30:58.000000000 -0700
+++ lxc-dave/fs/configfs/dir.c	2006-08-08 10:57:59.000000000 -0700
@@ -113,7 +113,7 @@ static int init_dir(struct inode * inode
 	inode->i_fop = &configfs_dir_operations;
 
 	/* directory inodes start off with i_nlink == 2 (for "." entry) */
-	inode->i_nlink++;
+	inc_nlink(inode);
 	return 0;
 }
 
@@ -141,7 +141,7 @@ static int create_dir(struct config_item
 	if (!error) {
 		error = configfs_create(d, mode, init_dir);
 		if (!error) {
-			p->d_inode->i_nlink++;
+			inc_nlink(p->d_inode);
 			(d)->d_op = &configfs_dentry_ops;
 		} else {
 			struct configfs_dirent *sd = d->d_fsdata;
diff -puN fs/configfs/mount.c~B4-monitor_inc_nlink fs/configfs/mount.c
--- lxc/fs/configfs/mount.c~B4-monitor_inc_nlink	2006-08-08 09:30:58.000000000 -0700
+++ lxc-dave/fs/configfs/mount.c	2006-08-08 10:57:59.000000000 -0700
@@ -84,7 +84,7 @@ static int configfs_fill_super(struct su
 		inode->i_op = &configfs_dir_inode_operations;
 		inode->i_fop = &configfs_dir_operations;
 		/* directory inodes start off with i_nlink == 2 (for "." entry) */
-		inode->i_nlink++;
+		inc_nlink(inode);
 	} else {
 		pr_debug("configfs: could not get root inode\n");
 		return -ENOMEM;
diff -puN fs/debugfs/inode.c~B4-monitor_inc_nlink fs/debugfs/inode.c
--- lxc/fs/debugfs/inode.c~B4-monitor_inc_nlink	2006-08-08 09:30:58.000000000 -0700
+++ lxc-dave/fs/debugfs/inode.c	2006-08-08 10:57:59.000000000 -0700
@@ -54,7 +54,7 @@ static struct inode *debugfs_get_inode(s
 			inode->i_fop = &simple_dir_operations;
 
 			/* directory inodes start off with i_nlink == 2 (for "." entry) */
-			inode->i_nlink++;
+			inc_nlink(inode);
 			break;
 		}
 	}
@@ -87,7 +87,7 @@ static int debugfs_mkdir(struct inode *d
 	mode = (mode & (S_IRWXUGO | S_ISVTX)) | S_IFDIR;
 	res = debugfs_mknod(dir, dentry, mode, 0);
 	if (!res)
-		dir->i_nlink++;
+		inc_nlink(dir);
 	return res;
 }
 
diff -puN fs/ext3/namei.c~B4-monitor_inc_nlink fs/ext3/namei.c
--- lxc/fs/ext3/namei.c~B4-monitor_inc_nlink	2006-08-08 10:57:11.000000000 -0700
+++ lxc-dave/fs/ext3/namei.c	2006-08-08 10:57:59.000000000 -0700
@@ -1616,7 +1616,7 @@ static int ext3_delete_entry (handle_t *
  */
 static inline void ext3_inc_count(handle_t *handle, struct inode *inode)
 {
-	inode->i_nlink++;
+	inc_nlink(inode);
 }
 
 static inline void ext3_dec_count(handle_t *handle, struct inode *inode)
@@ -1775,7 +1775,7 @@ retry:
 		iput (inode);
 		goto out_stop;
 	}
-	dir->i_nlink++;
+	inc_nlink(dir);
 	ext3_update_dx_flag(dir);
 	ext3_mark_inode_dirty(handle, dir);
 	d_instantiate(dentry, inode);
@@ -2341,7 +2341,7 @@ static int ext3_rename (struct inode * o
 		if (new_inode) {
 			drop_nlink(new_inode);
 		} else {
-			new_dir->i_nlink++;
+			inc_nlink(new_dir);
 			ext3_update_dx_flag(new_dir);
 			ext3_mark_inode_dirty(handle, new_dir);
 		}
diff -puN fs/fuse/control.c~B4-monitor_inc_nlink fs/fuse/control.c
--- lxc/fs/fuse/control.c~B4-monitor_inc_nlink	2006-08-08 09:30:58.000000000 -0700
+++ lxc-dave/fs/fuse/control.c	2006-08-08 10:57:59.000000000 -0700
@@ -116,7 +116,7 @@ int fuse_ctl_add_conn(struct fuse_conn *
 		return 0;
 
 	parent = fuse_control_sb->s_root;
-	parent->d_inode->i_nlink++;
+	inc_nlink(parent->d_inode);
 	sprintf(name, "%llu", (unsigned long long) fc->id);
 	parent = fuse_ctl_add_dentry(parent, fc, name, S_IFDIR | 0500, 2,
 				     &simple_dir_inode_operations,
diff -puN fs/hfsplus/dir.c~B4-monitor_inc_nlink fs/hfsplus/dir.c
--- lxc/fs/hfsplus/dir.c~B4-monitor_inc_nlink	2006-08-08 10:57:11.000000000 -0700
+++ lxc-dave/fs/hfsplus/dir.c	2006-08-08 10:57:59.000000000 -0700
@@ -298,7 +298,7 @@ static int hfsplus_link(struct dentry *s
 	if (res)
 		return res;
 
-	inode->i_nlink++;
+	inc_nlink(inode);
 	hfsplus_instantiate(dst_dentry, inode, cnid);
 	atomic_inc(&inode->i_count);
 	inode->i_ctime = CURRENT_TIME_SEC;
diff -puN fs/hpfs/namei.c~B4-monitor_inc_nlink fs/hpfs/namei.c
--- lxc/fs/hpfs/namei.c~B4-monitor_inc_nlink	2006-08-08 10:57:11.000000000 -0700
+++ lxc-dave/fs/hpfs/namei.c	2006-08-08 10:57:59.000000000 -0700
@@ -89,7 +89,7 @@ static int hpfs_mkdir(struct inode *dir,
 	brelse(bh);
 	hpfs_mark_4buffers_dirty(&qbh0);
 	hpfs_brelse4(&qbh0);
-	dir->i_nlink++;
+	inc_nlink(dir);
 	insert_inode_hash(result);
 
 	if (result->i_uid != current->fsuid ||
@@ -635,7 +635,7 @@ static int hpfs_rename(struct inode *old
 	end:
 	hpfs_i(i)->i_parent_dir = new_dir->i_ino;
 	if (S_ISDIR(i->i_mode)) {
-		new_dir->i_nlink++;
+		inc_nlink(new_dir);
 		drop_nlink(old_dir);
 	}
 	if ((fnode = hpfs_map_fnode(i->i_sb, i->i_ino, &bh))) {
diff -puN fs/hugetlbfs/inode.c~B4-monitor_inc_nlink fs/hugetlbfs/inode.c
--- lxc/fs/hugetlbfs/inode.c~B4-monitor_inc_nlink	2006-08-08 09:30:58.000000000 -0700
+++ lxc-dave/fs/hugetlbfs/inode.c	2006-08-08 10:57:59.000000000 -0700
@@ -377,7 +377,7 @@ static struct inode *hugetlbfs_get_inode
 			inode->i_fop = &simple_dir_operations;
 
 			/* directory inodes start off with i_nlink == 2 (for "." entry) */
-			inode->i_nlink++;
+			inc_nlink(inode);
 			break;
 		case S_IFLNK:
 			inode->i_op = &page_symlink_inode_operations;
@@ -418,7 +418,7 @@ static int hugetlbfs_mkdir(struct inode 
 {
 	int retval = hugetlbfs_mknod(dir, dentry, mode | S_IFDIR, 0);
 	if (!retval)
-		dir->i_nlink++;
+		inc_nlink(dir);
 	return retval;
 }
 
diff -puN fs/jffs2/dir.c~B4-monitor_inc_nlink fs/jffs2/dir.c
--- lxc/fs/jffs2/dir.c~B4-monitor_inc_nlink	2006-08-08 10:57:11.000000000 -0700
+++ lxc-dave/fs/jffs2/dir.c	2006-08-08 10:57:59.000000000 -0700
@@ -588,7 +588,7 @@ static int jffs2_mkdir (struct inode *di
 	}
 
 	dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime));
-	dir_i->i_nlink++;
+	inc_nlink(dir_i);
 
 	jffs2_free_raw_dirent(rd);
 
@@ -836,7 +836,7 @@ static int jffs2_rename (struct inode *o
 	/* If it was a directory we moved, and there was no victim,
 	   increase i_nlink on its new parent */
 	if (S_ISDIR(old_dentry->d_inode->i_mode) && !victim_f)
-		new_dir_i->i_nlink++;
+		inc_nlink(new_dir_i);
 
 	/* Unlink the original */
 	ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i),
@@ -848,7 +848,7 @@ static int jffs2_rename (struct inode *o
 		/* Oh shit. We really ought to make a single node which can do both atomically */
 		struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_dentry->d_inode);
 		down(&f->sem);
-		old_dentry->d_inode->i_nlink++;
+		inc_nlink(old_dentry->d_inode);
 		if (f->inocache)
 			f->inocache->nlink++;
 		up(&f->sem);
diff -puN fs/jffs2/fs.c~B4-monitor_inc_nlink fs/jffs2/fs.c
--- lxc/fs/jffs2/fs.c~B4-monitor_inc_nlink	2006-08-08 09:30:58.000000000 -0700
+++ lxc-dave/fs/jffs2/fs.c	2006-08-08 10:57:59.000000000 -0700
@@ -277,13 +277,13 @@ void jffs2_read_inode (struct inode *ino
 
 		for (fd=f->dents; fd; fd = fd->next) {
 			if (fd->type == DT_DIR && fd->ino)
-				inode->i_nlink++;
+				inc_nlink(inode);
 		}
 		/* and '..' */
-		inode->i_nlink++;
+		inc_nlink(inode);
 		/* Root dir gets i_nlink 3 for some reason */
 		if (inode->i_ino == 1)
-			inode->i_nlink++;
+			inc_nlink(inode);
 
 		inode->i_op = &jffs2_dir_inode_operations;
 		inode->i_fop = &jffs2_dir_operations;
diff -puN fs/jfs/namei.c~B4-monitor_inc_nlink fs/jfs/namei.c
--- lxc/fs/jfs/namei.c~B4-monitor_inc_nlink	2006-08-08 10:57:11.000000000 -0700
+++ lxc-dave/fs/jfs/namei.c	2006-08-08 10:57:59.000000000 -0700
@@ -292,7 +292,7 @@ static int jfs_mkdir(struct inode *dip, 
 	mark_inode_dirty(ip);
 
 	/* update parent directory inode */
-	dip->i_nlink++;		/* for '..' from child directory */
+	inc_nlink(dip);		/* for '..' from child directory */
 	dip->i_ctime = dip->i_mtime = CURRENT_TIME;
 	mark_inode_dirty(dip);
 
@@ -822,7 +822,7 @@ static int jfs_link(struct dentry *old_d
 		goto free_dname;
 
 	/* update object inode */
-	ip->i_nlink++;		/* for new link */
+	inc_nlink(ip);		/* for new link */
 	ip->i_ctime = CURRENT_TIME;
 	dir->i_ctime = dir->i_mtime = CURRENT_TIME;
 	mark_inode_dirty(dir);
@@ -1206,7 +1206,7 @@ static int jfs_rename(struct inode *old_
 			goto out4;
 		}
 		if (S_ISDIR(old_ip->i_mode))
-			new_dir->i_nlink++;
+			inc_nlink(new_dir);
 	}
 	/*
 	 * Remove old directory entry
diff -puN fs/msdos/namei.c~B4-monitor_inc_nlink fs/msdos/namei.c
--- lxc/fs/msdos/namei.c~B4-monitor_inc_nlink	2006-08-08 10:57:11.000000000 -0700
+++ lxc-dave/fs/msdos/namei.c	2006-08-08 10:57:59.000000000 -0700
@@ -385,7 +385,7 @@ static int msdos_mkdir(struct inode *dir
 	err = msdos_add_entry(dir, msdos_name, 1, is_hid, cluster, &ts, &sinfo);
 	if (err)
 		goto out_free;
-	dir->i_nlink++;
+	inc_nlink(dir);
 
 	inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
 	brelse(sinfo.bh);
@@ -544,7 +544,7 @@ static int do_msdos_rename(struct inode 
 		}
 		drop_nlink(old_dir);
 		if (!new_inode)
-			new_dir->i_nlink++;
+			inc_nlink(new_dir);
 	}
 
 	err = fat_remove_entries(old_dir, &old_sinfo);	/* and releases bh */
diff -puN fs/ocfs2/dlm/dlmfs.c~B4-monitor_inc_nlink fs/ocfs2/dlm/dlmfs.c
--- lxc/fs/ocfs2/dlm/dlmfs.c~B4-monitor_inc_nlink	2006-08-08 09:30:58.000000000 -0700
+++ lxc-dave/fs/ocfs2/dlm/dlmfs.c	2006-08-08 10:57:59.000000000 -0700
@@ -338,7 +338,7 @@ static struct inode *dlmfs_get_root_inod
 		inode->i_blocks = 0;
 		inode->i_mapping->backing_dev_info = &dlmfs_backing_dev_info;
 		inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
-		inode->i_nlink++;
+		inc_nlink(inode);
 
 		inode->i_fop = &simple_dir_operations;
 		inode->i_op = &dlmfs_root_inode_operations;
@@ -395,7 +395,7 @@ static struct inode *dlmfs_get_inode(str
 
 		/* directory inodes start off with i_nlink ==
 		 * 2 (for "." entry) */
-		inode->i_nlink++;
+		inc_nlink(inode);
 		break;
 	}
 
@@ -449,7 +449,7 @@ static int dlmfs_mkdir(struct inode * di
 	}
 	ip->ip_dlm = dlm;
 
-	dir->i_nlink++;
+	inc_nlink(dir);
 	d_instantiate(dentry, inode);
 	dget(dentry);	/* Extra count - pin the dentry in core */
 
diff -puN fs/ocfs2/namei.c~B4-monitor_inc_nlink fs/ocfs2/namei.c
--- lxc/fs/ocfs2/namei.c~B4-monitor_inc_nlink	2006-08-08 10:57:11.000000000 -0700
+++ lxc-dave/fs/ocfs2/namei.c	2006-08-08 10:57:59.000000000 -0700
@@ -408,7 +408,7 @@ static int ocfs2_mknod(struct inode *dir
 			mlog_errno(status);
 			goto leave;
 		}
-		dir->i_nlink++;
+		inc_nlink(dir);
 	}
 
 	status = ocfs2_add_entry(handle, dentry, inode,
@@ -702,7 +702,7 @@ static int ocfs2_link(struct dentry *old
 		goto bail;
 	}
 
-	inode->i_nlink++;
+	inc_nlink(inode);
 	inode->i_ctime = CURRENT_TIME;
 	fe->i_links_count = cpu_to_le16(inode->i_nlink);
 	fe->i_ctime = cpu_to_le64(inode->i_ctime.tv_sec);
@@ -902,7 +902,7 @@ static int ocfs2_unlink(struct inode *di
 						parent_node_bh);
 		if (status < 0) {
 			mlog_errno(status);
-			dir->i_nlink++;
+			inc_nlink(dir);
 		}
 	}
 
@@ -1344,7 +1344,7 @@ static int ocfs2_rename(struct inode *ol
 		if (new_inode) {
 			new_inode->i_nlink--;
 		} else {
-			new_dir->i_nlink++;
+			inc_nlink(new_dir);
 			mark_inode_dirty(new_dir);
 		}
 	}
diff -puN fs/ramfs/inode.c~B4-monitor_inc_nlink fs/ramfs/inode.c
--- lxc/fs/ramfs/inode.c~B4-monitor_inc_nlink	2006-08-08 09:30:58.000000000 -0700
+++ lxc-dave/fs/ramfs/inode.c	2006-08-08 10:57:59.000000000 -0700
@@ -75,7 +75,7 @@ struct inode *ramfs_get_inode(struct sup
 			inode->i_fop = &simple_dir_operations;
 
 			/* directory inodes start off with i_nlink == 2 (for "." entry) */
-			inode->i_nlink++;
+			inc_nlink(inode);
 			break;
 		case S_IFLNK:
 			inode->i_op = &page_symlink_inode_operations;
@@ -113,7 +113,7 @@ static int ramfs_mkdir(struct inode * di
 {
 	int retval = ramfs_mknod(dir, dentry, mode | S_IFDIR, 0);
 	if (!retval)
-		dir->i_nlink++;
+		inc_nlink(dir);
 	return retval;
 }
 
diff -puN fs/reiserfs/namei.c~B4-monitor_inc_nlink fs/reiserfs/namei.c
--- lxc/fs/reiserfs/namei.c~B4-monitor_inc_nlink	2006-08-08 10:57:11.000000000 -0700
+++ lxc-dave/fs/reiserfs/namei.c	2006-08-08 10:57:59.000000000 -0700
@@ -19,7 +19,7 @@
 #include <linux/smp_lock.h>
 #include <linux/quotaops.h>
 
-#define INC_DIR_INODE_NLINK(i) if (i->i_nlink != 1) { i->i_nlink++; 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) i->i_nlink=1; }
 #define DEC_DIR_INODE_NLINK(i) if (i->i_nlink != 1) drop_nlink(i);
 
 // directory item contains array of entry headers. This performs
@@ -1006,7 +1006,7 @@ static int reiserfs_unlink(struct inode 
 	    reiserfs_cut_from_item(&th, &path, &(de.de_entry_key), dir, NULL,
 				   0);
 	if (retval < 0) {
-		inode->i_nlink++;
+		inc_nlink(inode);
 		goto end_unlink;
 	}
 	inode->i_ctime = CURRENT_TIME_SEC;
@@ -1143,7 +1143,7 @@ static int reiserfs_link(struct dentry *
 	}
 
 	/* inc before scheduling so reiserfs_unlink knows we are here */
-	inode->i_nlink++;
+	inc_nlink(inode);
 
 	retval = journal_begin(&th, dir->i_sb, jbegin_count);
 	if (retval) {
diff -puN fs/sysfs/dir.c~B4-monitor_inc_nlink fs/sysfs/dir.c
--- lxc/fs/sysfs/dir.c~B4-monitor_inc_nlink	2006-08-08 09:30:58.000000000 -0700
+++ lxc-dave/fs/sysfs/dir.c	2006-08-08 10:57:59.000000000 -0700
@@ -103,7 +103,7 @@ static int init_dir(struct inode * inode
 	inode->i_fop = &sysfs_dir_operations;
 
 	/* directory inodes start off with i_nlink == 2 (for "." entry) */
-	inode->i_nlink++;
+	inc_nlink(inode);
 	return 0;
 }
 
@@ -137,7 +137,7 @@ static int create_dir(struct kobject * k
 		if (!error) {
 			error = sysfs_create(*d, mode, init_dir);
 			if (!error) {
-				p->d_inode->i_nlink++;
+				inc_nlink(p->d_inode);
 				(*d)->d_op = &sysfs_dentry_ops;
 				d_rehash(*d);
 			}
diff -puN fs/sysfs/mount.c~B4-monitor_inc_nlink fs/sysfs/mount.c
--- lxc/fs/sysfs/mount.c~B4-monitor_inc_nlink	2006-08-08 09:30:58.000000000 -0700
+++ lxc-dave/fs/sysfs/mount.c	2006-08-08 10:57:59.000000000 -0700
@@ -49,7 +49,7 @@ static int sysfs_fill_super(struct super
 		inode->i_op = &sysfs_dir_inode_operations;
 		inode->i_fop = &sysfs_dir_operations;
 		/* directory inodes start off with i_nlink == 2 (for "." entry) */
-		inode->i_nlink++;	
+		inc_nlink(inode);
 	} else {
 		pr_debug("sysfs: could not get root inode\n");
 		return -ENOMEM;
diff -puN fs/udf/inode.c~B4-monitor_inc_nlink fs/udf/inode.c
--- lxc/fs/udf/inode.c~B4-monitor_inc_nlink	2006-08-08 09:30:58.000000000 -0700
+++ lxc-dave/fs/udf/inode.c	2006-08-08 10:57:59.000000000 -0700
@@ -1165,7 +1165,7 @@ static void udf_fill_inode(struct inode 
 			inode->i_op = &udf_dir_inode_operations;
 			inode->i_fop = &udf_dir_operations;
 			inode->i_mode |= S_IFDIR;
-			inode->i_nlink ++;
+			inc_nlink(inode);
 			break;
 		}
 		case ICBTAG_FILE_TYPE_REALTIME:
diff -puN fs/udf/namei.c~B4-monitor_inc_nlink fs/udf/namei.c
--- lxc/fs/udf/namei.c~B4-monitor_inc_nlink	2006-08-08 10:57:11.000000000 -0700
+++ lxc-dave/fs/udf/namei.c	2006-08-08 10:57:59.000000000 -0700
@@ -762,7 +762,7 @@ static int udf_mkdir(struct inode * dir,
 		cpu_to_le32(UDF_I_UNIQUE(inode) & 0x00000000FFFFFFFFUL);
 	cfi.fileCharacteristics |= FID_FILE_CHAR_DIRECTORY;
 	udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
-	dir->i_nlink++;
+	inc_nlink(dir);
 	mark_inode_dirty(dir);
 	d_instantiate(dentry, inode);
 	if (fibh.sbh != fibh.ebh)
@@ -1147,7 +1147,7 @@ static int udf_link(struct dentry * old_
 	if (fibh.sbh != fibh.ebh)
 		udf_release_data(fibh.ebh);
 	udf_release_data(fibh.sbh);
-	inode->i_nlink ++;
+	inc_nlink(inode);
 	inode->i_ctime = current_fs_time(inode->i_sb);
 	mark_inode_dirty(inode);
 	atomic_inc(&inode->i_count);
@@ -1282,7 +1282,7 @@ static int udf_rename (struct inode * ol
 		}
 		else
 		{
-			new_dir->i_nlink ++;
+			inc_nlink(new_dir);
 			mark_inode_dirty(new_dir);
 		}
 	}
diff -puN fs/vfat/namei.c~B4-monitor_inc_nlink fs/vfat/namei.c
--- lxc/fs/vfat/namei.c~B4-monitor_inc_nlink	2006-08-08 10:57:11.000000000 -0700
+++ lxc-dave/fs/vfat/namei.c	2006-08-08 10:57:59.000000000 -0700
@@ -837,7 +837,7 @@ static int vfat_mkdir(struct inode *dir,
 	if (err)
 		goto out_free;
 	dir->i_version++;
-	dir->i_nlink++;
+	inc_nlink(dir);
 
 	inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
 	brelse(sinfo.bh);
@@ -932,7 +932,7 @@ static int vfat_rename(struct inode *old
 		}
 		drop_nlink(old_dir);
 		if (!new_inode)
- 			new_dir->i_nlink++;
+ 			inc_nlink(new_dir);
 	}
 
 	err = fat_remove_entries(old_dir, &old_sinfo);	/* and releases bh */
diff -puN ipc/mqueue.c~B4-monitor_inc_nlink ipc/mqueue.c
--- lxc/ipc/mqueue.c~B4-monitor_inc_nlink	2006-08-08 10:57:11.000000000 -0700
+++ lxc-dave/ipc/mqueue.c	2006-08-08 10:57:59.000000000 -0700
@@ -168,7 +168,7 @@ static struct inode *mqueue_get_inode(st
 			/* all is ok */
 			info->user = get_uid(u);
 		} else if (S_ISDIR(mode)) {
-			inode->i_nlink++;
+			inc_nlink(inode);
 			/* Some things misbehave if size == 0 on a directory */
 			inode->i_size = 2 * DIRENT_SIZE;
 			inode->i_op = &mqueue_dir_inode_operations;
diff -puN kernel/cpuset.c~B4-monitor_inc_nlink kernel/cpuset.c
--- lxc/kernel/cpuset.c~B4-monitor_inc_nlink	2006-08-08 09:30:58.000000000 -0700
+++ lxc-dave/kernel/cpuset.c	2006-08-08 10:57:59.000000000 -0700
@@ -377,7 +377,7 @@ static int cpuset_fill_super(struct supe
 		inode->i_op = &simple_dir_inode_operations;
 		inode->i_fop = &simple_dir_operations;
 		/* directories start off with i_nlink == 2 (for "." entry) */
-		inode->i_nlink++;
+		inc_nlink(inode);
 	} else {
 		return -ENOMEM;
 	}
@@ -1552,7 +1552,7 @@ static int cpuset_create_file(struct den
 		inode->i_fop = &simple_dir_operations;
 
 		/* start off with i_nlink == 2 (for "." entry) */
-		inode->i_nlink++;
+		inc_nlink(inode);
 	} else if (S_ISREG(mode)) {
 		inode->i_size = 0;
 		inode->i_fop = &cpuset_file_operations;
@@ -1585,7 +1585,7 @@ static int cpuset_create_dir(struct cpus
 	error = cpuset_create_file(dentry, S_IFDIR | mode);
 	if (!error) {
 		dentry->d_fsdata = cs;
-		parent->d_inode->i_nlink++;
+		inc_nlink(parent->d_inode);
 		cs->dentry = dentry;
 	}
 	dput(dentry);
@@ -2020,7 +2020,7 @@ int __init cpuset_init(void)
 	}
 	root = cpuset_mount->mnt_sb->s_root;
 	root->d_fsdata = &top_cpuset;
-	root->d_inode->i_nlink++;
+	inc_nlink(root->d_inode);
 	top_cpuset.dentry = root;
 	root->d_inode->i_op = &cpuset_dir_inode_operations;
 	number_of_cpusets = 1;
diff -puN net/sunrpc/rpc_pipe.c~B4-monitor_inc_nlink net/sunrpc/rpc_pipe.c
--- lxc/net/sunrpc/rpc_pipe.c~B4-monitor_inc_nlink	2006-08-08 09:30:58.000000000 -0700
+++ lxc-dave/net/sunrpc/rpc_pipe.c	2006-08-08 10:57:59.000000000 -0700
@@ -496,7 +496,7 @@ rpc_get_inode(struct super_block *sb, in
 		case S_IFDIR:
 			inode->i_fop = &simple_dir_operations;
 			inode->i_op = &simple_dir_inode_operations;
-			inode->i_nlink++;
+			inc_nlink(inode);
 		default:
 			break;
 	}
@@ -572,7 +572,7 @@ rpc_populate(struct dentry *parent,
 		if (private)
 			rpc_inode_setowner(inode, private);
 		if (S_ISDIR(mode))
-			dir->i_nlink++;
+			inc_nlink(dir);
 		d_add(dentry, inode);
 	}
 	mutex_unlock(&dir->i_mutex);
@@ -594,7 +594,7 @@ __rpc_mkdir(struct inode *dir, struct de
 		goto out_err;
 	inode->i_ino = iunique(dir->i_sb, 100);
 	d_instantiate(dentry, inode);
-	dir->i_nlink++;
+	inc_nlink(dir);
 	inode_dir_notify(dir, DN_CREATE);
 	return 0;
 out_err:
diff -puN security/inode.c~B4-monitor_inc_nlink security/inode.c
--- lxc/security/inode.c~B4-monitor_inc_nlink	2006-08-08 09:30:58.000000000 -0700
+++ lxc-dave/security/inode.c	2006-08-08 10:57:59.000000000 -0700
@@ -78,7 +78,7 @@ static struct inode *get_inode(struct su
 			inode->i_fop = &simple_dir_operations;
 
 			/* directory inodes start off with i_nlink == 2 (for "." entry) */
-			inode->i_nlink++;
+			inc_nlink(inode);
 			break;
 		}
 	}
@@ -111,7 +111,7 @@ static int mkdir(struct inode *dir, stru
 	mode = (mode & (S_IRWXUGO | S_ISVTX)) | S_IFDIR;
 	res = mknod(dir, dentry, mode, 0);
 	if (!res)
-		dir->i_nlink++;
+		inc_nlink(dir);
 	return res;
 }
 
diff -puN security/selinux/selinuxfs.c~B4-monitor_inc_nlink security/selinux/selinuxfs.c
--- lxc/security/selinux/selinuxfs.c~B4-monitor_inc_nlink	2006-08-08 09:30:58.000000000 -0700
+++ lxc-dave/security/selinux/selinuxfs.c	2006-08-08 10:57:59.000000000 -0700
@@ -1253,10 +1253,10 @@ static int sel_make_dir(struct inode *di
 	inode->i_op = &simple_dir_inode_operations;
 	inode->i_fop = &simple_dir_operations;
 	/* directory inodes start off with i_nlink == 2 (for "." entry) */
-	inode->i_nlink++;
+	inc_nlink(inode);
 	d_add(dentry, inode);
 	/* bump link count on parent directory, too */
-	dir->i_nlink++;
+	inc_nlink(dir);
 out:
 	return ret;
 }
_

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

* [PATCH 3/6] unlink: monitor i_nlink
  2006-08-09 16:57 [PATCH 0/6] read-only bind mount prep work Dave Hansen
                   ` (2 preceding siblings ...)
  2006-08-09 16:57 ` [PATCH 4/6] r/o bind mount prepwork: inc_nlink() helper Dave Hansen
@ 2006-08-09 16:57 ` Dave Hansen
  2006-08-09 17:11   ` Christoph Hellwig
  2006-08-09 16:57 ` [PATCH 5/6] clean up OCFS2 nlink handling Dave Hansen
  2006-08-09 16:57 ` [PATCH 6/6] monitor zeroing of i_nlink Dave Hansen
  5 siblings, 1 reply; 21+ messages in thread
From: Dave Hansen @ 2006-08-09 16:57 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel, hch, Dave Hansen


When a filesystem decrements i_nlink to zero, it means that a
write must be performed in order to drop the inode from the
filesystem.

We're shortly going to have keep filesystems from being remounted
r/o between the time that this i_nlink decrement and that write
occurs.  

So, add a little helper function to do the decrements.  We'll
tie into it in a bit to note when i_nlink hits zero.

Signed-off-by: Dave Hansen <haveblue@us.ibm.com>
---

 lxc-dave/drivers/usb/core/inode.c |    7 ++++---
 lxc-dave/fs/autofs/root.c         |    2 +-
 lxc-dave/fs/autofs4/root.c        |    2 +-
 lxc-dave/fs/bfs/dir.c             |    9 +++------
 lxc-dave/fs/cifs/inode.c          |   10 +++++-----
 lxc-dave/fs/coda/dir.c            |    4 ++--
 lxc-dave/fs/ext2/namei.c          |    2 +-
 lxc-dave/fs/ext3/namei.c          |   14 +++++++-------
 lxc-dave/fs/hfs/dir.c             |    2 +-
 lxc-dave/fs/hfsplus/dir.c         |    2 +-
 lxc-dave/fs/hpfs/namei.c          |    6 +++---
 lxc-dave/fs/jffs/inode-v23.c      |    3 +--
 lxc-dave/fs/jffs2/dir.c           |    6 +++---
 lxc-dave/fs/jfs/namei.c           |   14 ++++++--------
 lxc-dave/fs/libfs.c               |   10 +++++-----
 lxc-dave/fs/minix/namei.c         |    2 +-
 lxc-dave/fs/msdos/namei.c         |    9 ++++-----
 lxc-dave/fs/nfs/dir.c             |    6 +++---
 lxc-dave/fs/ocfs2/namei.c         |    4 ++--
 lxc-dave/fs/qnx4/namei.c          |    6 ++----
 lxc-dave/fs/reiserfs/namei.c      |    6 +++---
 lxc-dave/fs/sysv/namei.c          |    2 +-
 lxc-dave/fs/udf/namei.c           |   18 ++++++------------
 lxc-dave/fs/ufs/namei.c           |    2 +-
 lxc-dave/fs/vfat/namei.c          |    9 ++++-----
 lxc-dave/include/linux/fs.h       |    7 ++++++-
 lxc-dave/ipc/mqueue.c             |    2 +-
 lxc-dave/mm/shmem.c               |   10 +++++-----
 28 files changed, 83 insertions(+), 93 deletions(-)

diff -puN include/linux/fs.h~B3-unlink-monitor-i_nlink-0 include/linux/fs.h
--- lxc/include/linux/fs.h~B3-unlink-monitor-i_nlink-0	2006-08-08 09:30:58.000000000 -0700
+++ lxc-dave/include/linux/fs.h	2006-08-08 10:57:11.000000000 -0700
@@ -1262,9 +1262,14 @@ static inline void inode_inc_link_count(
 	mark_inode_dirty(inode);
 }
 
-static inline void inode_dec_link_count(struct inode *inode)
+static inline void drop_nlink(struct inode *inode)
 {
 	inode->i_nlink--;
+}
+
+static inline void inode_dec_link_count(struct inode *inode)
+{
+	drop_nlink(inode);
 	mark_inode_dirty(inode);
 }
 
diff -puN drivers/usb/core/inode.c~B3-unlink-monitor-i_nlink-0 drivers/usb/core/inode.c
--- lxc/drivers/usb/core/inode.c~B3-unlink-monitor-i_nlink-0	2006-08-08 09:30:58.000000000 -0700
+++ lxc-dave/drivers/usb/core/inode.c	2006-08-08 10:57:11.000000000 -0700
@@ -332,7 +332,7 @@ static int usbfs_unlink (struct inode *d
 {
 	struct inode *inode = dentry->d_inode;
 	mutex_lock(&inode->i_mutex);
-	dentry->d_inode->i_nlink--;
+	drop_nlink(dentry->d_inode);
 	dput(dentry);
 	mutex_unlock(&inode->i_mutex);
 	d_delete(dentry);
@@ -347,10 +347,11 @@ static int usbfs_rmdir(struct inode *dir
 	mutex_lock(&inode->i_mutex);
 	dentry_unhash(dentry);
 	if (usbfs_empty(dentry)) {
-		dentry->d_inode->i_nlink -= 2;
+		drop_nlink(dentry->d_inode);
+		drop_nlink(dentry->d_inode);
 		dput(dentry);
 		inode->i_flags |= S_DEAD;
-		dir->i_nlink--;
+		drop_nlink(dir);
 		error = 0;
 	}
 	mutex_unlock(&inode->i_mutex);
diff -puN fs/autofs/root.c~B3-unlink-monitor-i_nlink-0 fs/autofs/root.c
--- lxc/fs/autofs/root.c~B3-unlink-monitor-i_nlink-0	2006-08-08 09:30:58.000000000 -0700
+++ lxc-dave/fs/autofs/root.c	2006-08-08 10:57:11.000000000 -0700
@@ -414,7 +414,7 @@ static int autofs_root_rmdir(struct inod
 
 	dentry->d_time = (unsigned long)(struct autofs_dir_ent *)NULL;
 	autofs_hash_delete(ent);
-	dir->i_nlink--;
+	drop_nlink(dir);
 	d_drop(dentry);
 	unlock_kernel();
 
diff -puN fs/autofs4/root.c~B3-unlink-monitor-i_nlink-0 fs/autofs4/root.c
--- lxc/fs/autofs4/root.c~B3-unlink-monitor-i_nlink-0	2006-08-08 09:30:58.000000000 -0700
+++ lxc-dave/fs/autofs4/root.c	2006-08-08 10:57:11.000000000 -0700
@@ -676,7 +676,7 @@ static int autofs4_dir_rmdir(struct inod
 	dentry->d_inode->i_nlink = 0;
 
 	if (dir->i_nlink)
-		dir->i_nlink--;
+		drop_nlink(dir);
 
 	return 0;
 }
diff -puN fs/bfs/dir.c~B3-unlink-monitor-i_nlink-0 fs/bfs/dir.c
--- lxc/fs/bfs/dir.c~B3-unlink-monitor-i_nlink-0	2006-08-08 09:30:58.000000000 -0700
+++ lxc-dave/fs/bfs/dir.c	2006-08-08 10:57:11.000000000 -0700
@@ -117,8 +117,7 @@ static int bfs_create(struct inode * dir
 
 	err = bfs_add_entry(dir, dentry->d_name.name, dentry->d_name.len, inode->i_ino);
 	if (err) {
-		inode->i_nlink--;
-		mark_inode_dirty(inode);
+		inode_dec_link_count(inode);
 		iput(inode);
 		unlock_kernel();
 		return err;
@@ -196,9 +195,8 @@ static int bfs_unlink(struct inode * dir
 	mark_buffer_dirty(bh);
 	dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
 	mark_inode_dirty(dir);
-	inode->i_nlink--;
 	inode->i_ctime = dir->i_ctime;
-	mark_inode_dirty(inode);
+	inode_dec_link_count(inode);
 	error = 0;
 
 out_brelse:
@@ -249,9 +247,8 @@ static int bfs_rename(struct inode * old
 	old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME_SEC;
 	mark_inode_dirty(old_dir);
 	if (new_inode) {
-		new_inode->i_nlink--;
 		new_inode->i_ctime = CURRENT_TIME_SEC;
-		mark_inode_dirty(new_inode);
+		inode_dec_link_count(new_inode);
 	}
 	mark_buffer_dirty(old_bh);
 	error = 0;
diff -puN fs/cifs/inode.c~B3-unlink-monitor-i_nlink-0 fs/cifs/inode.c
--- lxc/fs/cifs/inode.c~B3-unlink-monitor-i_nlink-0	2006-08-08 09:30:58.000000000 -0700
+++ lxc-dave/fs/cifs/inode.c	2006-08-08 10:57:11.000000000 -0700
@@ -591,7 +591,7 @@ int cifs_unlink(struct inode *inode, str
 
 	if (!rc) {
 		if (direntry->d_inode)
-			direntry->d_inode->i_nlink--;
+			drop_nlink(direntry->d_inode);
 	} else if (rc == -ENOENT) {
 		d_drop(direntry);
 	} else if (rc == -ETXTBSY) {
@@ -610,7 +610,7 @@ int cifs_unlink(struct inode *inode, str
 						CIFS_MOUNT_MAP_SPECIAL_CHR);
 			CIFSSMBClose(xid, pTcon, netfid);
 			if (direntry->d_inode)
-				direntry->d_inode->i_nlink--;
+				drop_nlink(direntry->d_inode);
 		}
 	} else if (rc == -EACCES) {
 		/* try only if r/o attribute set in local lookup data? */
@@ -664,7 +664,7 @@ int cifs_unlink(struct inode *inode, str
 						CIFS_MOUNT_MAP_SPECIAL_CHR);
 			if (!rc) {
 				if (direntry->d_inode)
-					direntry->d_inode->i_nlink--;
+					drop_nlink(direntry->d_inode);
 			} else if (rc == -ETXTBSY) {
 				int oplock = FALSE;
 				__u16 netfid;
@@ -685,7 +685,7 @@ int cifs_unlink(struct inode *inode, str
 						    CIFS_MOUNT_MAP_SPECIAL_CHR);
 					CIFSSMBClose(xid, pTcon, netfid);
 					if (direntry->d_inode)
-			                        direntry->d_inode->i_nlink--;
+						drop_nlink(direntry->d_inode);
 				}
 			/* BB if rc = -ETXTBUSY goto the rename logic BB */
 			}
@@ -817,7 +817,7 @@ int cifs_rmdir(struct inode *inode, stru
 			  cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
 
 	if (!rc) {
-		inode->i_nlink--;
+		drop_nlink(inode);
 		i_size_write(direntry->d_inode,0);
 		direntry->d_inode->i_nlink = 0;
 	}
diff -puN fs/coda/dir.c~B3-unlink-monitor-i_nlink-0 fs/coda/dir.c
--- lxc/fs/coda/dir.c~B3-unlink-monitor-i_nlink-0	2006-08-08 09:30:58.000000000 -0700
+++ lxc-dave/fs/coda/dir.c	2006-08-08 10:57:11.000000000 -0700
@@ -367,7 +367,7 @@ int coda_unlink(struct inode *dir, struc
         }
 
 	coda_dir_changed(dir, 0);
-	de->d_inode->i_nlink--;
+	drop_nlink(de->d_inode);
 	unlock_kernel();
 
         return 0;
@@ -394,7 +394,7 @@ int coda_rmdir(struct inode *dir, struct
         }
 
 	coda_dir_changed(dir, -1);
-	de->d_inode->i_nlink--;
+	drop_nlink(de->d_inode);
 	d_delete(de);
 	unlock_kernel();
 
diff -puN fs/ext2/namei.c~B3-unlink-monitor-i_nlink-0 fs/ext2/namei.c
--- lxc/fs/ext2/namei.c~B3-unlink-monitor-i_nlink-0	2006-08-08 09:30:58.000000000 -0700
+++ lxc-dave/fs/ext2/namei.c	2006-08-08 10:57:11.000000000 -0700
@@ -326,7 +326,7 @@ static int ext2_rename (struct inode * o
 		ext2_set_link(new_dir, new_de, new_page, old_inode);
 		new_inode->i_ctime = CURRENT_TIME_SEC;
 		if (dir_de)
-			new_inode->i_nlink--;
+			drop_nlink(new_inode);
 		inode_dec_link_count(new_inode);
 	} else {
 		if (dir_de) {
diff -puN fs/ext3/namei.c~B3-unlink-monitor-i_nlink-0 fs/ext3/namei.c
--- lxc/fs/ext3/namei.c~B3-unlink-monitor-i_nlink-0	2006-08-08 09:30:58.000000000 -0700
+++ lxc-dave/fs/ext3/namei.c	2006-08-08 10:57:11.000000000 -0700
@@ -1621,7 +1621,7 @@ static inline void ext3_inc_count(handle
 
 static inline void ext3_dec_count(handle_t *handle, struct inode *inode)
 {
-	inode->i_nlink--;
+	drop_nlink(inode);
 }
 
 static int ext3_add_nondir(handle_t *handle,
@@ -1743,7 +1743,7 @@ retry:
 	inode->i_size = EXT3_I(inode)->i_disksize = inode->i_sb->s_blocksize;
 	dir_block = ext3_bread (handle, inode, 0, 1, &err);
 	if (!dir_block) {
-		inode->i_nlink--; /* is this nlink == 0? */
+		drop_nlink(inode); /* is this nlink == 0? */
 		ext3_mark_inode_dirty(handle, inode);
 		iput (inode);
 		goto out_stop;
@@ -2053,7 +2053,7 @@ static int ext3_rmdir (struct inode * di
 	ext3_orphan_add(handle, inode);
 	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
 	ext3_mark_inode_dirty(handle, inode);
-	dir->i_nlink--;
+	drop_nlink(dir);
 	ext3_update_dx_flag(dir);
 	ext3_mark_inode_dirty(handle, dir);
 
@@ -2104,7 +2104,7 @@ static int ext3_unlink(struct inode * di
 	dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
 	ext3_update_dx_flag(dir);
 	ext3_mark_inode_dirty(handle, dir);
-	inode->i_nlink--;
+	drop_nlink(inode);
 	if (!inode->i_nlink)
 		ext3_orphan_add(handle, inode);
 	inode->i_ctime = dir->i_ctime;
@@ -2326,7 +2326,7 @@ static int ext3_rename (struct inode * o
 	}
 
 	if (new_inode) {
-		new_inode->i_nlink--;
+		drop_nlink(new_inode);
 		new_inode->i_ctime = CURRENT_TIME_SEC;
 	}
 	old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME_SEC;
@@ -2337,9 +2337,9 @@ static int ext3_rename (struct inode * o
 		PARENT_INO(dir_bh->b_data) = cpu_to_le32(new_dir->i_ino);
 		BUFFER_TRACE(dir_bh, "call ext3_journal_dirty_metadata");
 		ext3_journal_dirty_metadata(handle, dir_bh);
-		old_dir->i_nlink--;
+		drop_nlink(old_dir);
 		if (new_inode) {
-			new_inode->i_nlink--;
+			drop_nlink(new_inode);
 		} else {
 			new_dir->i_nlink++;
 			ext3_update_dx_flag(new_dir);
diff -puN fs/hfs/dir.c~B3-unlink-monitor-i_nlink-0 fs/hfs/dir.c
--- lxc/fs/hfs/dir.c~B3-unlink-monitor-i_nlink-0	2006-08-08 09:30:58.000000000 -0700
+++ lxc-dave/fs/hfs/dir.c	2006-08-08 10:57:11.000000000 -0700
@@ -246,7 +246,7 @@ static int hfs_unlink(struct inode *dir,
 	if (res)
 		return res;
 
-	inode->i_nlink--;
+	drop_nlink(inode);
 	hfs_delete_inode(inode);
 	inode->i_ctime = CURRENT_TIME_SEC;
 	mark_inode_dirty(inode);
diff -puN fs/hfsplus/dir.c~B3-unlink-monitor-i_nlink-0 fs/hfsplus/dir.c
--- lxc/fs/hfsplus/dir.c~B3-unlink-monitor-i_nlink-0	2006-08-08 09:30:58.000000000 -0700
+++ lxc-dave/fs/hfsplus/dir.c	2006-08-08 10:57:11.000000000 -0700
@@ -338,7 +338,7 @@ static int hfsplus_unlink(struct inode *
 		return res;
 
 	if (inode->i_nlink > 0)
-		inode->i_nlink--;
+		drop_nlink(inode);
 	hfsplus_delete_inode(inode);
 	if (inode->i_ino != cnid && !inode->i_nlink) {
 		if (!atomic_read(&HFSPLUS_I(inode).opencnt)) {
diff -puN fs/hpfs/namei.c~B3-unlink-monitor-i_nlink-0 fs/hpfs/namei.c
--- lxc/fs/hpfs/namei.c~B3-unlink-monitor-i_nlink-0	2006-08-08 09:30:58.000000000 -0700
+++ lxc-dave/fs/hpfs/namei.c	2006-08-08 10:57:11.000000000 -0700
@@ -434,7 +434,7 @@ again:
 		unlock_kernel();
 		return -ENOSPC;
 	default:
-		inode->i_nlink--;
+		drop_nlink(inode);
 		err = 0;
 	}
 	goto out;
@@ -494,7 +494,7 @@ static int hpfs_rmdir(struct inode *dir,
 		err = -ENOSPC;
 		break;
 	default:
-		dir->i_nlink--;
+		drop_nlink(dir);
 		inode->i_nlink = 0;
 		err = 0;
 	}
@@ -636,7 +636,7 @@ static int hpfs_rename(struct inode *old
 	hpfs_i(i)->i_parent_dir = new_dir->i_ino;
 	if (S_ISDIR(i->i_mode)) {
 		new_dir->i_nlink++;
-		old_dir->i_nlink--;
+		drop_nlink(old_dir);
 	}
 	if ((fnode = hpfs_map_fnode(i->i_sb, i->i_ino, &bh))) {
 		fnode->up = new_dir->i_ino;
diff -puN fs/jffs2/dir.c~B3-unlink-monitor-i_nlink-0 fs/jffs2/dir.c
--- lxc/fs/jffs2/dir.c~B3-unlink-monitor-i_nlink-0	2006-08-08 09:30:58.000000000 -0700
+++ lxc-dave/fs/jffs2/dir.c	2006-08-08 10:57:11.000000000 -0700
@@ -615,7 +615,7 @@ static int jffs2_rmdir (struct inode *di
 	}
 	ret = jffs2_unlink(dir_i, dentry);
 	if (!ret)
-		dir_i->i_nlink--;
+		drop_nlink(dir_i);
 	return ret;
 }
 
@@ -823,7 +823,7 @@ static int jffs2_rename (struct inode *o
 
 	if (victim_f) {
 		/* There was a victim. Kill it off nicely */
-		new_dentry->d_inode->i_nlink--;
+		drop_nlink(new_dentry->d_inode);
 		/* Don't oops if the victim was a dirent pointing to an
 		   inode which didn't exist. */
 		if (victim_f->inocache) {
@@ -862,7 +862,7 @@ static int jffs2_rename (struct inode *o
 	}
 
 	if (S_ISDIR(old_dentry->d_inode->i_mode))
-		old_dir_i->i_nlink--;
+		drop_nlink(old_dir_i);
 
 	new_dir_i->i_mtime = new_dir_i->i_ctime = old_dir_i->i_mtime = old_dir_i->i_ctime = ITIME(now);
 
diff -puN fs/jfs/namei.c~B3-unlink-monitor-i_nlink-0 fs/jfs/namei.c
--- lxc/fs/jfs/namei.c~B3-unlink-monitor-i_nlink-0	2006-08-08 09:30:58.000000000 -0700
+++ lxc-dave/fs/jfs/namei.c	2006-08-08 10:57:11.000000000 -0700
@@ -393,9 +393,8 @@ static int jfs_rmdir(struct inode *dip, 
 	/* update parent directory's link count corresponding
 	 * to ".." entry of the target directory deleted
 	 */
-	dip->i_nlink--;
 	dip->i_ctime = dip->i_mtime = CURRENT_TIME;
-	mark_inode_dirty(dip);
+	inode_dec_link_count(dip);
 
 	/*
 	 * OS/2 could have created EA and/or ACL
@@ -515,8 +514,7 @@ static int jfs_unlink(struct inode *dip,
 	mark_inode_dirty(dip);
 
 	/* update target's inode */
-	ip->i_nlink--;
-	mark_inode_dirty(ip);
+	inode_dec_link_count(ip);
 
 	/*
 	 *      commit zero link count object
@@ -835,7 +833,7 @@ static int jfs_link(struct dentry *old_d
 	rc = txCommit(tid, 2, &iplist[0], 0);
 
 	if (rc) {
-		ip->i_nlink--;
+		ip->i_nlink--; /* never instantiated */
 		iput(ip);
 	} else
 		d_instantiate(dentry, ip);
@@ -1155,9 +1153,9 @@ static int jfs_rename(struct inode *old_
 			      old_ip->i_ino, JFS_RENAME);
 		if (rc)
 			goto out4;
-		new_ip->i_nlink--;
+		drop_nlink(new_ip);
 		if (S_ISDIR(new_ip->i_mode)) {
-			new_ip->i_nlink--;
+			drop_nlink(new_ip);
 			if (new_ip->i_nlink) {
 				mutex_unlock(&JFS_IP(new_ip)->commit_mutex);
 				if (old_dir != new_dir)
@@ -1223,7 +1221,7 @@ static int jfs_rename(struct inode *old_
 		goto out4;
 	}
 	if (S_ISDIR(old_ip->i_mode)) {
-		old_dir->i_nlink--;
+		drop_nlink(old_dir);
 		if (old_dir != new_dir) {
 			/*
 			 * Change inode number of parent for moved directory
diff -puN fs/libfs.c~B3-unlink-monitor-i_nlink-0 fs/libfs.c
--- lxc/fs/libfs.c~B3-unlink-monitor-i_nlink-0	2006-08-08 09:30:58.000000000 -0700
+++ lxc-dave/fs/libfs.c	2006-08-08 10:57:11.000000000 -0700
@@ -275,7 +275,7 @@ int simple_unlink(struct inode *dir, str
 	struct inode *inode = dentry->d_inode;
 
 	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
-	inode->i_nlink--;
+	drop_nlink(inode);
 	dput(dentry);
 	return 0;
 }
@@ -285,9 +285,9 @@ int simple_rmdir(struct inode *dir, stru
 	if (!simple_empty(dentry))
 		return -ENOTEMPTY;
 
-	dentry->d_inode->i_nlink--;
+	drop_nlink(dentry->d_inode);
 	simple_unlink(dir, dentry);
-	dir->i_nlink--;
+	drop_nlink(dir);
 	return 0;
 }
 
@@ -303,9 +303,9 @@ int simple_rename(struct inode *old_dir,
 	if (new_dentry->d_inode) {
 		simple_unlink(new_dir, new_dentry);
 		if (they_are_dirs)
-			old_dir->i_nlink--;
+			drop_nlink(old_dir);
 	} else if (they_are_dirs) {
-		old_dir->i_nlink--;
+		drop_nlink(old_dir);
 		new_dir->i_nlink++;
 	}
 
diff -puN fs/nfs/dir.c~B3-unlink-monitor-i_nlink-0 fs/nfs/dir.c
--- lxc/fs/nfs/dir.c~B3-unlink-monitor-i_nlink-0	2006-08-08 09:30:58.000000000 -0700
+++ lxc-dave/fs/nfs/dir.c	2006-08-08 10:57:11.000000000 -0700
@@ -842,7 +842,7 @@ static void nfs_dentry_iput(struct dentr
 	nfs_inode_return_delegation(inode);
 	if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {
 		lock_kernel();
-		inode->i_nlink--;
+		drop_nlink(inode);
 		nfs_complete_unlink(dentry);
 		unlock_kernel();
 	}
@@ -1395,7 +1395,7 @@ static int nfs_safe_remove(struct dentry
 		error = NFS_PROTO(dir)->remove(dir, &dentry->d_name);
 		/* The VFS may want to delete this inode */
 		if (error == 0)
-			inode->i_nlink--;
+			drop_nlink(inode);
 		nfs_mark_for_revalidate(inode);
 		nfs_end_data_update(inode);
 	} else
@@ -1599,7 +1599,7 @@ static int nfs_rename(struct inode *old_
 			goto out;
 		}
 	} else
-		new_inode->i_nlink--;
+		drop_nlink(new_inode);
 
 go_ahead:
 	/*
diff -puN fs/ocfs2/namei.c~B3-unlink-monitor-i_nlink-0 fs/ocfs2/namei.c
--- lxc/fs/ocfs2/namei.c~B3-unlink-monitor-i_nlink-0	2006-08-08 09:30:58.000000000 -0700
+++ lxc-dave/fs/ocfs2/namei.c	2006-08-08 10:57:11.000000000 -0700
@@ -711,7 +711,7 @@ static int ocfs2_link(struct dentry *old
 	err = ocfs2_journal_dirty(handle, fe_bh);
 	if (err < 0) {
 		le16_add_cpu(&fe->i_links_count, -1);
-		inode->i_nlink--;
+		drop_nlink(inode);
 		mlog_errno(err);
 		goto bail;
 	}
@@ -721,7 +721,7 @@ static int ocfs2_link(struct dentry *old
 			      parent_fe_bh, de_bh);
 	if (err) {
 		le16_add_cpu(&fe->i_links_count, -1);
-		inode->i_nlink--;
+		drop_nlink(inode);
 		mlog_errno(err);
 		goto bail;
 	}
diff -puN fs/qnx4/namei.c~B3-unlink-monitor-i_nlink-0 fs/qnx4/namei.c
--- lxc/fs/qnx4/namei.c~B3-unlink-monitor-i_nlink-0	2006-08-08 09:30:58.000000000 -0700
+++ lxc-dave/fs/qnx4/namei.c	2006-08-08 10:57:11.000000000 -0700
@@ -189,8 +189,7 @@ int qnx4_rmdir(struct inode *dir, struct
 	inode->i_nlink = 0;
 	mark_inode_dirty(inode);
 	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
-	dir->i_nlink--;
-	mark_inode_dirty(dir);
+	inode_dec_link_count(dir);
 	retval = 0;
 
       end_rmdir:
@@ -234,9 +233,8 @@ int qnx4_unlink(struct inode *dir, struc
 	mark_buffer_dirty(bh);
 	dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
 	mark_inode_dirty(dir);
-	inode->i_nlink--;
 	inode->i_ctime = dir->i_ctime;
-	mark_inode_dirty(inode);
+	inode_dec_link_count(inode);
 	retval = 0;
 
 end_unlink:
diff -puN fs/reiserfs/namei.c~B3-unlink-monitor-i_nlink-0 fs/reiserfs/namei.c
--- lxc/fs/reiserfs/namei.c~B3-unlink-monitor-i_nlink-0	2006-08-08 09:30:58.000000000 -0700
+++ lxc-dave/fs/reiserfs/namei.c	2006-08-08 10:57:11.000000000 -0700
@@ -20,7 +20,7 @@
 #include <linux/quotaops.h>
 
 #define INC_DIR_INODE_NLINK(i) if (i->i_nlink != 1) { i->i_nlink++; if (i->i_nlink >= REISERFS_LINK_MAX) i->i_nlink=1; }
-#define DEC_DIR_INODE_NLINK(i) if (i->i_nlink != 1) i->i_nlink--;
+#define DEC_DIR_INODE_NLINK(i) if (i->i_nlink != 1) drop_nlink(i);
 
 // directory item contains array of entry headers. This performs
 // binary search through that array
@@ -994,7 +994,7 @@ static int reiserfs_unlink(struct inode 
 		inode->i_nlink = 1;
 	}
 
-	inode->i_nlink--;
+	drop_nlink(inode);
 
 	/*
 	 * we schedule before doing the add_save_link call, save the link
@@ -1475,7 +1475,7 @@ static int reiserfs_rename(struct inode 
 		if (S_ISDIR(new_dentry_inode->i_mode)) {
 			new_dentry_inode->i_nlink = 0;
 		} else {
-			new_dentry_inode->i_nlink--;
+			drop_nlink(new_dentry_inode);
 		}
 		new_dentry_inode->i_ctime = ctime;
 		savelink = new_dentry_inode->i_nlink;
diff -puN fs/sysv/namei.c~B3-unlink-monitor-i_nlink-0 fs/sysv/namei.c
--- lxc/fs/sysv/namei.c~B3-unlink-monitor-i_nlink-0	2006-08-08 09:30:58.000000000 -0700
+++ lxc-dave/fs/sysv/namei.c	2006-08-08 10:57:11.000000000 -0700
@@ -250,7 +250,7 @@ static int sysv_rename(struct inode * ol
 		sysv_set_link(new_de, new_page, old_inode);
 		new_inode->i_ctime = CURRENT_TIME_SEC;
 		if (dir_de)
-			new_inode->i_nlink--;
+			drop_nlink(new_inode);
 		inode_dec_link_count(new_inode);
 	} else {
 		if (dir_de) {
diff -puN fs/udf/namei.c~B3-unlink-monitor-i_nlink-0 fs/udf/namei.c
--- lxc/fs/udf/namei.c~B3-unlink-monitor-i_nlink-0	2006-08-08 09:30:58.000000000 -0700
+++ lxc-dave/fs/udf/namei.c	2006-08-08 10:57:11.000000000 -0700
@@ -878,8 +878,7 @@ static int udf_rmdir(struct inode * dir,
 			inode->i_nlink);
 	inode->i_nlink = 0;
 	inode->i_size = 0;
-	mark_inode_dirty(inode);
-	dir->i_nlink --;
+	inode_dec_link_count(inode);
 	inode->i_ctime = dir->i_ctime = dir->i_mtime = current_fs_time(dir->i_sb);
 	mark_inode_dirty(dir);
 
@@ -923,8 +922,7 @@ static int udf_unlink(struct inode * dir
 		goto end_unlink;
 	dir->i_ctime = dir->i_mtime = current_fs_time(dir->i_sb);
 	mark_inode_dirty(dir);
-	inode->i_nlink--;
-	mark_inode_dirty(inode);
+	inode_dec_link_count(inode);
 	inode->i_ctime = dir->i_ctime;
 	retval = 0;
 
@@ -1101,8 +1099,7 @@ out:
 	return err;
 
 out_no_entry:
-	inode->i_nlink--;
-	mark_inode_dirty(inode);
+	inode_dec_link_count(inode);
 	iput(inode);
 	goto out;
 }
@@ -1261,9 +1258,8 @@ static int udf_rename (struct inode * ol
 
 	if (new_inode)
 	{
-		new_inode->i_nlink--;
 		new_inode->i_ctime = current_fs_time(new_inode->i_sb);
-		mark_inode_dirty(new_inode);
+		inode_dec_link_count(new_inode);
 	}
 	old_dir->i_ctime = old_dir->i_mtime = current_fs_time(old_dir->i_sb);
 	mark_inode_dirty(old_dir);
@@ -1279,12 +1275,10 @@ static int udf_rename (struct inode * ol
 		}
 		else
 			mark_buffer_dirty_inode(dir_bh, old_inode);
-		old_dir->i_nlink --;
-		mark_inode_dirty(old_dir);
+		inode_dec_link_count(old_dir);
 		if (new_inode)
 		{
-			new_inode->i_nlink --;
-			mark_inode_dirty(new_inode);
+			inode_dec_link_count(new_inode);
 		}
 		else
 		{
diff -puN fs/ufs/namei.c~B3-unlink-monitor-i_nlink-0 fs/ufs/namei.c
--- lxc/fs/ufs/namei.c~B3-unlink-monitor-i_nlink-0	2006-08-08 09:30:58.000000000 -0700
+++ lxc-dave/fs/ufs/namei.c	2006-08-08 10:57:11.000000000 -0700
@@ -308,7 +308,7 @@ static int ufs_rename(struct inode *old_
 		ufs_set_link(new_dir, new_de, new_page, old_inode);
 		new_inode->i_ctime = CURRENT_TIME_SEC;
 		if (dir_de)
-			new_inode->i_nlink--;
+			drop_nlink(new_inode);
 		inode_dec_link_count(new_inode);
 	} else {
 		if (dir_de) {
diff -puN fs/vfat/namei.c~B3-unlink-monitor-i_nlink-0 fs/vfat/namei.c
--- lxc/fs/vfat/namei.c~B3-unlink-monitor-i_nlink-0	2006-08-08 09:30:58.000000000 -0700
+++ lxc-dave/fs/vfat/namei.c	2006-08-08 10:57:11.000000000 -0700
@@ -782,7 +782,7 @@ static int vfat_rmdir(struct inode *dir,
 	err = fat_remove_entries(dir, &sinfo);	/* and releases bh */
 	if (err)
 		goto out;
-	dir->i_nlink--;
+	drop_nlink(dir);
 
 	inode->i_nlink = 0;
 	inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
@@ -930,7 +930,7 @@ static int vfat_rename(struct inode *old
 			if (err)
 				goto error_dotdot;
 		}
-		old_dir->i_nlink--;
+		drop_nlink(old_dir);
 		if (!new_inode)
  			new_dir->i_nlink++;
 	}
@@ -947,10 +947,9 @@ static int vfat_rename(struct inode *old
 		mark_inode_dirty(old_dir);
 
 	if (new_inode) {
+		drop_nlink(new_inode);
 		if (is_dir)
-			new_inode->i_nlink -= 2;
-		else
-			new_inode->i_nlink--;
+			drop_nlink(new_inode);
 		new_inode->i_ctime = ts;
 	}
 out:
diff -puN ipc/mqueue.c~B3-unlink-monitor-i_nlink-0 ipc/mqueue.c
--- lxc/ipc/mqueue.c~B3-unlink-monitor-i_nlink-0	2006-08-08 09:30:58.000000000 -0700
+++ lxc-dave/ipc/mqueue.c	2006-08-08 10:57:11.000000000 -0700
@@ -307,7 +307,7 @@ static int mqueue_unlink(struct inode *d
 
 	dir->i_ctime = dir->i_mtime = dir->i_atime = CURRENT_TIME;
 	dir->i_size -= DIRENT_SIZE;
-  	inode->i_nlink--;
+  	drop_nlink(inode);
   	dput(dentry);
   	return 0;
 }
diff -puN mm/shmem.c~B3-unlink-monitor-i_nlink-0 mm/shmem.c
--- lxc/mm/shmem.c~B3-unlink-monitor-i_nlink-0	2006-08-08 09:30:58.000000000 -0700
+++ lxc-dave/mm/shmem.c	2006-08-08 10:57:11.000000000 -0700
@@ -1760,7 +1760,7 @@ static int shmem_unlink(struct inode *di
 
 	dir->i_size -= BOGO_DIRENT_SIZE;
 	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
-	inode->i_nlink--;
+	drop_nlink(inode);
 	dput(dentry);	/* Undo the count from "create" - this does all the work */
 	return 0;
 }
@@ -1770,8 +1770,8 @@ static int shmem_rmdir(struct inode *dir
 	if (!simple_empty(dentry))
 		return -ENOTEMPTY;
 
-	dentry->d_inode->i_nlink--;
-	dir->i_nlink--;
+	drop_nlink(dentry->d_inode);
+	drop_nlink(dir);
 	return shmem_unlink(dir, dentry);
 }
 
@@ -1792,9 +1792,9 @@ static int shmem_rename(struct inode *ol
 	if (new_dentry->d_inode) {
 		(void) shmem_unlink(new_dir, new_dentry);
 		if (they_are_dirs)
-			old_dir->i_nlink--;
+			drop_nlink(old_dir);
 	} else if (they_are_dirs) {
-		old_dir->i_nlink--;
+		drop_nlink(old_dir);
 		new_dir->i_nlink++;
 	}
 
diff -puN fs/binfmt_misc.c~B3-unlink-monitor-i_nlink-0 fs/binfmt_misc.c
diff -puN fs/jffs/inode-v23.c~B3-unlink-monitor-i_nlink-0 fs/jffs/inode-v23.c
--- lxc/fs/jffs/inode-v23.c~B3-unlink-monitor-i_nlink-0	2006-08-08 09:30:58.000000000 -0700
+++ lxc-dave/fs/jffs/inode-v23.c	2006-08-08 10:57:11.000000000 -0700
@@ -1052,9 +1052,8 @@ jffs_remove(struct inode *dir, struct de
 
 	dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
 	mark_inode_dirty(dir);
-	inode->i_nlink--;
 	inode->i_ctime = dir->i_ctime;
-	mark_inode_dirty(inode);
+	inode_dec_link_count(inode);
 
 	d_delete(dentry);	/* This also frees the inode */
 
diff -puN fs/minix/namei.c~B3-unlink-monitor-i_nlink-0 fs/minix/namei.c
--- lxc/fs/minix/namei.c~B3-unlink-monitor-i_nlink-0	2006-08-08 09:30:58.000000000 -0700
+++ lxc-dave/fs/minix/namei.c	2006-08-08 10:57:11.000000000 -0700
@@ -249,7 +249,7 @@ static int minix_rename(struct inode * o
 		minix_set_link(new_de, new_page, old_inode);
 		new_inode->i_ctime = CURRENT_TIME_SEC;
 		if (dir_de)
-			new_inode->i_nlink--;
+			drop_nlink(new_inode);
 		inode_dec_link_count(new_inode);
 	} else {
 		if (dir_de) {
diff -puN fs/msdos/namei.c~B3-unlink-monitor-i_nlink-0 fs/msdos/namei.c
--- lxc/fs/msdos/namei.c~B3-unlink-monitor-i_nlink-0	2006-08-08 09:30:58.000000000 -0700
+++ lxc-dave/fs/msdos/namei.c	2006-08-08 10:57:11.000000000 -0700
@@ -341,7 +341,7 @@ static int msdos_rmdir(struct inode *dir
 	err = fat_remove_entries(dir, &sinfo);	/* and releases bh */
 	if (err)
 		goto out;
-	dir->i_nlink--;
+	drop_nlink(dir);
 
 	inode->i_nlink = 0;
 	inode->i_ctime = CURRENT_TIME_SEC;
@@ -542,7 +542,7 @@ static int do_msdos_rename(struct inode 
 			if (err)
 				goto error_dotdot;
 		}
-		old_dir->i_nlink--;
+		drop_nlink(old_dir);
 		if (!new_inode)
 			new_dir->i_nlink++;
 	}
@@ -559,10 +559,9 @@ static int do_msdos_rename(struct inode 
 		mark_inode_dirty(old_dir);
 
 	if (new_inode) {
+		drop_nlink(new_inode);
 		if (is_dir)
-			new_inode->i_nlink -= 2;
-		else
-			new_inode->i_nlink--;
+			drop_nlink(new_inode);
 		new_inode->i_ctime = ts;
 	}
 out:
_

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

* [PATCH 5/6] clean up OCFS2 nlink handling
  2006-08-09 16:57 [PATCH 0/6] read-only bind mount prep work Dave Hansen
                   ` (3 preceding siblings ...)
  2006-08-09 16:57 ` [PATCH 3/6] unlink: monitor i_nlink Dave Hansen
@ 2006-08-09 16:57 ` Dave Hansen
  2006-08-09 17:12   ` Christoph Hellwig
  2006-08-09 16:57 ` [PATCH 6/6] monitor zeroing of i_nlink Dave Hansen
  5 siblings, 1 reply; 21+ messages in thread
From: Dave Hansen @ 2006-08-09 16:57 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel, hch, Dave Hansen


OCFS2 does some operations on i_nlink, then reverts them if some
of its operations fail to complete.  This does not fit in well
with the drop_nlink() logic where we expect i_nlink to stay at
zero once it gets there.

So, delay all of the nlink operations until we're sure that the
operations have completed.  Also, introduce a small helper to
check whether an inode has proper "unlinkable" i_nlink counts
no matter whether it is a directory or regular inode.

This patch is broken out from the others because it does contain
some logical changes.

Signed-off-by: Dave Hansen <haveblue@us.ibm.com>
Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>
---

 arch/i386/kernel/setup.c  |    0 
 lxc-dave/fs/ocfs2/namei.c |   45 ++++++++++++++++++++++++---------------------
 2 files changed, 24 insertions(+), 21 deletions(-)

diff -puN fs/ocfs2/namei.c~B5-clean_up_OCFS2_nlink_handling fs/ocfs2/namei.c
--- lxc/fs/ocfs2/namei.c~B5-clean_up_OCFS2_nlink_handling	2006-08-08 09:18:54.000000000 -0700
+++ lxc-dave/fs/ocfs2/namei.c	2006-08-08 09:18:56.000000000 -0700
@@ -744,11 +744,23 @@ bail:
 	return err;
 }
 
+static inline int inode_is_unlinkable(struct inode *inode)
+{
+	if (S_ISDIR(inode->i_mode)) {
+	       	if (inode->i_nlink == 2)
+			return 1;
+		return 0;
+	}
+
+	if (inode->i_nlink == 1)
+		return 1;
+	return 0;
+}
+
 static int ocfs2_unlink(struct inode *dir,
 			struct dentry *dentry)
 {
 	int status;
-	unsigned int saved_nlink = 0;
 	struct inode *inode = dentry->d_inode;
 	struct ocfs2_super *osb = OCFS2_SB(dir->i_sb);
 	u64 blkno;
@@ -760,6 +772,7 @@ static int ocfs2_unlink(struct inode *di
 	struct buffer_head *dirent_bh = NULL;
 	char orphan_name[OCFS2_ORPHAN_NAMELEN + 1];
 	struct buffer_head *orphan_entry_bh = NULL;
+	unsigned int future_nlink;
 
 	mlog_entry("(0x%p, 0x%p, '%.*s')\n", dir, dentry,
 		   dentry->d_name.len, dentry->d_name.name);
@@ -823,18 +836,11 @@ static int ocfs2_unlink(struct inode *di
 		}
 	}
 
-	/* There are still a few steps left until we can consider the
-	 * unlink to have succeeded. Save off nlink here before
-	 * modification so we can set it back in case we hit an issue
-	 * before commit. */
-	saved_nlink = inode->i_nlink;
-	if (S_ISDIR(inode->i_mode))
-		inode->i_nlink = 0;
+	if (S_ISDIR(inode->i_mode) && (inode->i_nlink == 2))
+		future_nlink = 0;
 	else
-		inode->i_nlink--;
-
-	status = ocfs2_request_unlink_vote(inode, dentry,
-					   (unsigned int) inode->i_nlink);
+		future_nlink = inode->i_nlink - 1;
+	status = ocfs2_request_unlink_vote(inode, dentry, future_nlink);
 	if (status < 0) {
 		/* This vote should succeed under all normal
 		 * circumstances. */
@@ -842,7 +848,7 @@ static int ocfs2_unlink(struct inode *di
 		goto leave;
 	}
 
-	if (!inode->i_nlink) {
+	if (inode_is_unlinkable(inode)) {
 		status = ocfs2_prepare_orphan_dir(osb, handle, inode,
 						  orphan_name,
 						  &orphan_entry_bh);
@@ -869,7 +875,7 @@ static int ocfs2_unlink(struct inode *di
 
 	fe = (struct ocfs2_dinode *) fe_bh->b_data;
 
-	if (!inode->i_nlink) {
+	if (inode_is_unlinkable(inode)) {
 		status = ocfs2_orphan_add(osb, handle, inode, fe, orphan_name,
 					  orphan_entry_bh);
 		if (status < 0) {
@@ -885,10 +891,10 @@ static int ocfs2_unlink(struct inode *di
 		goto leave;
 	}
 
-	/* We can set nlink on the dinode now. clear the saved version
-	 * so that it doesn't get set later. */
+	if (S_ISDIR(inode->i_mode))
+		drop_nlink(inode);
+	drop_nlink(inode);
 	fe->i_links_count = cpu_to_le16(inode->i_nlink);
-	saved_nlink = 0;
 
 	status = ocfs2_journal_dirty(handle, fe_bh);
 	if (status < 0) {
@@ -897,7 +903,7 @@ static int ocfs2_unlink(struct inode *di
 	}
 
 	if (S_ISDIR(inode->i_mode)) {
-		dir->i_nlink--;
+		drop_nlink(dir);
 		status = ocfs2_mark_inode_dirty(handle, dir,
 						parent_node_bh);
 		if (status < 0) {
@@ -907,9 +913,6 @@ static int ocfs2_unlink(struct inode *di
 	}
 
 leave:
-	if (status < 0 && saved_nlink)
-		inode->i_nlink = saved_nlink;
-
 	if (handle)
 		ocfs2_commit_trans(handle);
 
diff -puN arch/i386/kernel/setup.c~B5-clean_up_OCFS2_nlink_handling arch/i386/kernel/setup.c
_

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

* [PATCH 6/6] monitor zeroing of i_nlink
  2006-08-09 16:57 [PATCH 0/6] read-only bind mount prep work Dave Hansen
                   ` (4 preceding siblings ...)
  2006-08-09 16:57 ` [PATCH 5/6] clean up OCFS2 nlink handling Dave Hansen
@ 2006-08-09 16:57 ` Dave Hansen
  2006-08-09 17:14   ` Christoph Hellwig
  5 siblings, 1 reply; 21+ messages in thread
From: Dave Hansen @ 2006-08-09 16:57 UTC (permalink / raw)
  To: akpm; +Cc: linux-kernel, hch, Dave Hansen


Some filesystems, instead of simply decrementing i_nlink, simply zero
it during an unlink operation.  We need to catch these in addition
to the decrement operations.

Signed-off-by: Dave Hansen <haveblue@us.ibm.com>
---

 kernel/fork.c                |    0 
 lxc-dave/fs/autofs4/root.c   |    4 ++--
 lxc-dave/fs/cifs/inode.c     |    2 +-
 lxc-dave/fs/ext3/namei.c     |    2 +-
 lxc-dave/fs/fuse/dir.c       |    4 ++--
 lxc-dave/fs/hfs/dir.c        |    2 +-
 lxc-dave/fs/hfsplus/dir.c    |    4 ++--
 lxc-dave/fs/hpfs/namei.c     |    4 ++--
 lxc-dave/fs/jfs/namei.c      |    2 +-
 lxc-dave/fs/msdos/namei.c    |    4 ++--
 lxc-dave/fs/nfs/dir.c        |    2 +-
 lxc-dave/fs/qnx4/namei.c     |    2 +-
 lxc-dave/fs/reiserfs/namei.c |    4 ++--
 lxc-dave/fs/udf/namei.c      |    2 +-
 lxc-dave/fs/vfat/namei.c     |    4 ++--
 lxc-dave/include/linux/fs.h  |    5 +++++
 16 files changed, 26 insertions(+), 21 deletions(-)

diff -puN fs/libfs.c~B6-monitor-clear-i_nlink fs/libfs.c
diff -puN fs/cifs/inode.c~B6-monitor-clear-i_nlink fs/cifs/inode.c
--- lxc/fs/cifs/inode.c~B6-monitor-clear-i_nlink	2006-08-08 09:18:54.000000000 -0700
+++ lxc-dave/fs/cifs/inode.c	2006-08-08 09:18:57.000000000 -0700
@@ -819,7 +819,7 @@ int cifs_rmdir(struct inode *inode, stru
 	if (!rc) {
 		drop_nlink(inode);
 		i_size_write(direntry->d_inode,0);
-		direntry->d_inode->i_nlink = 0;
+		clear_nlink(direntry->d_inode);
 	}
 
 	cifsInode = CIFS_I(direntry->d_inode);
diff -puN fs/ext3/namei.c~B6-monitor-clear-i_nlink fs/ext3/namei.c
--- lxc/fs/ext3/namei.c~B6-monitor-clear-i_nlink	2006-08-08 09:18:54.000000000 -0700
+++ lxc-dave/fs/ext3/namei.c	2006-08-08 09:18:57.000000000 -0700
@@ -2045,7 +2045,7 @@ static int ext3_rmdir (struct inode * di
 			      "empty directory has nlink!=2 (%d)",
 			      inode->i_nlink);
 	inode->i_version++;
-	inode->i_nlink = 0;
+	clear_nlink(inode);
 	/* There's no need to set i_disksize: the fact that i_nlink is
 	 * zero will ensure that the right thing happens during any
 	 * recovery. */
diff -puN fs/autofs4/root.c~B6-monitor-clear-i_nlink fs/autofs4/root.c
--- lxc/fs/autofs4/root.c~B6-monitor-clear-i_nlink	2006-08-08 09:18:54.000000000 -0700
+++ lxc-dave/fs/autofs4/root.c	2006-08-08 09:18:57.000000000 -0700
@@ -638,7 +638,7 @@ static int autofs4_dir_unlink(struct ino
 	dput(ino->dentry);
 
 	dentry->d_inode->i_size = 0;
-	dentry->d_inode->i_nlink = 0;
+	clear_nlink(dentry->d_inode);
 
 	dir->i_mtime = CURRENT_TIME;
 
@@ -673,7 +673,7 @@ static int autofs4_dir_rmdir(struct inod
 	}
 	dput(ino->dentry);
 	dentry->d_inode->i_size = 0;
-	dentry->d_inode->i_nlink = 0;
+	clear_nlink(dentry->d_inode);
 
 	if (dir->i_nlink)
 		drop_nlink(dir);
diff -puN fs/fuse/dir.c~B6-monitor-clear-i_nlink fs/fuse/dir.c
--- lxc/fs/fuse/dir.c~B6-monitor-clear-i_nlink	2006-08-06 03:21:02.000000000 -0700
+++ lxc-dave/fs/fuse/dir.c	2006-08-08 09:18:57.000000000 -0700
@@ -508,7 +508,7 @@ static int fuse_unlink(struct inode *dir
 		/* Set nlink to zero so the inode can be cleared, if
                    the inode does have more links this will be
                    discovered at the next lookup/getattr */
-		inode->i_nlink = 0;
+		clear_nlink(inode);
 		fuse_invalidate_attr(inode);
 		fuse_invalidate_attr(dir);
 		fuse_invalidate_entry_cache(entry);
@@ -534,7 +534,7 @@ static int fuse_rmdir(struct inode *dir,
 	err = req->out.h.error;
 	fuse_put_request(fc, req);
 	if (!err) {
-		entry->d_inode->i_nlink = 0;
+		clear_nlink(entry->d_inode);
 		fuse_invalidate_attr(dir);
 		fuse_invalidate_entry_cache(entry);
 	} else if (err == -EINTR)
diff -puN fs/hfs/dir.c~B6-monitor-clear-i_nlink fs/hfs/dir.c
--- lxc/fs/hfs/dir.c~B6-monitor-clear-i_nlink	2006-08-08 09:18:52.000000000 -0700
+++ lxc-dave/fs/hfs/dir.c	2006-08-08 09:18:57.000000000 -0700
@@ -273,7 +273,7 @@ static int hfs_rmdir(struct inode *dir, 
 	res = hfs_cat_delete(inode->i_ino, dir, &dentry->d_name);
 	if (res)
 		return res;
-	inode->i_nlink = 0;
+	clear_nlink(inode);
 	inode->i_ctime = CURRENT_TIME_SEC;
 	hfs_delete_inode(inode);
 	mark_inode_dirty(inode);
diff -puN fs/hfsplus/dir.c~B6-monitor-clear-i_nlink fs/hfsplus/dir.c
--- lxc/fs/hfsplus/dir.c~B6-monitor-clear-i_nlink	2006-08-08 09:18:54.000000000 -0700
+++ lxc-dave/fs/hfsplus/dir.c	2006-08-08 09:18:57.000000000 -0700
@@ -348,7 +348,7 @@ static int hfsplus_unlink(struct inode *
 		} else
 			inode->i_flags |= S_DEAD;
 	} else
-		inode->i_nlink = 0;
+		clear_nlink(inode);
 	inode->i_ctime = CURRENT_TIME_SEC;
 	mark_inode_dirty(inode);
 
@@ -387,7 +387,7 @@ static int hfsplus_rmdir(struct inode *d
 	res = hfsplus_delete_cat(inode->i_ino, dir, &dentry->d_name);
 	if (res)
 		return res;
-	inode->i_nlink = 0;
+	clear_nlink(inode);
 	inode->i_ctime = CURRENT_TIME_SEC;
 	hfsplus_delete_inode(inode);
 	mark_inode_dirty(inode);
diff -puN fs/hpfs/namei.c~B6-monitor-clear-i_nlink fs/hpfs/namei.c
--- lxc/fs/hpfs/namei.c~B6-monitor-clear-i_nlink	2006-08-08 09:18:54.000000000 -0700
+++ lxc-dave/fs/hpfs/namei.c	2006-08-08 09:18:57.000000000 -0700
@@ -495,7 +495,7 @@ static int hpfs_rmdir(struct inode *dir,
 		break;
 	default:
 		drop_nlink(dir);
-		inode->i_nlink = 0;
+		clear_nlink(inode);
 		err = 0;
 	}
 	goto out;
@@ -590,7 +590,7 @@ static int hpfs_rename(struct inode *old
 		int r;
 		if ((r = hpfs_remove_dirent(old_dir, dno, dep, &qbh, 1)) != 2) {
 			if ((nde = map_dirent(new_dir, hpfs_i(new_dir)->i_dno, (char *)new_name, new_len, NULL, &qbh1))) {
-				new_inode->i_nlink = 0;
+				clear_nlink(new_inode);
 				copy_de(nde, &de);
 				memcpy(nde->name, new_name, new_len);
 				hpfs_mark_4buffers_dirty(&qbh1);
diff -puN fs/jfs/namei.c~B6-monitor-clear-i_nlink fs/jfs/namei.c
--- lxc/fs/jfs/namei.c~B6-monitor-clear-i_nlink	2006-08-08 09:18:54.000000000 -0700
+++ lxc-dave/fs/jfs/namei.c	2006-08-08 09:18:57.000000000 -0700
@@ -414,7 +414,7 @@ static int jfs_rmdir(struct inode *dip, 
 	JFS_IP(ip)->acl.flag = 0;
 
 	/* mark the target directory as deleted */
-	ip->i_nlink = 0;
+	clear_nlink(ip);
 	mark_inode_dirty(ip);
 
 	rc = txCommit(tid, 2, &iplist[0], 0);
diff -puN fs/msdos/namei.c~B6-monitor-clear-i_nlink fs/msdos/namei.c
--- lxc/fs/msdos/namei.c~B6-monitor-clear-i_nlink	2006-08-08 09:18:54.000000000 -0700
+++ lxc-dave/fs/msdos/namei.c	2006-08-08 09:18:57.000000000 -0700
@@ -343,7 +343,7 @@ static int msdos_rmdir(struct inode *dir
 		goto out;
 	drop_nlink(dir);
 
-	inode->i_nlink = 0;
+	clear_nlink(inode);
 	inode->i_ctime = CURRENT_TIME_SEC;
 	fat_detach(inode);
 out:
@@ -425,7 +425,7 @@ static int msdos_unlink(struct inode *di
 	err = fat_remove_entries(dir, &sinfo);	/* and releases bh */
 	if (err)
 		goto out;
-	inode->i_nlink = 0;
+	clear_nlink(inode);
 	inode->i_ctime = CURRENT_TIME_SEC;
 	fat_detach(inode);
 out:
diff -puN fs/nfs/dir.c~B6-monitor-clear-i_nlink fs/nfs/dir.c
--- lxc/fs/nfs/dir.c~B6-monitor-clear-i_nlink	2006-08-08 09:18:52.000000000 -0700
+++ lxc-dave/fs/nfs/dir.c	2006-08-08 09:18:57.000000000 -0700
@@ -1280,7 +1280,7 @@ static int nfs_rmdir(struct inode *dir, 
 	error = NFS_PROTO(dir)->rmdir(dir, &dentry->d_name);
 	/* Ensure the VFS deletes this inode */
 	if (error == 0 && dentry->d_inode != NULL)
-		dentry->d_inode->i_nlink = 0;
+		clear_nlink(dentry->d_inode);
 	nfs_end_data_update(dir);
 	unlock_kernel();
 
diff -puN fs/ocfs2/namei.c~B6-monitor-clear-i_nlink fs/ocfs2/namei.c
diff -puN fs/qnx4/namei.c~B6-monitor-clear-i_nlink fs/qnx4/namei.c
--- lxc/fs/qnx4/namei.c~B6-monitor-clear-i_nlink	2006-08-08 09:18:52.000000000 -0700
+++ lxc-dave/fs/qnx4/namei.c	2006-08-08 09:18:57.000000000 -0700
@@ -186,7 +186,7 @@ int qnx4_rmdir(struct inode *dir, struct
 	memset(de->di_fname, 0, sizeof de->di_fname);
 	de->di_mode = 0;
 	mark_buffer_dirty(bh);
-	inode->i_nlink = 0;
+	clear_nlink(inode);
 	mark_inode_dirty(inode);
 	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
 	inode_dec_link_count(dir);
diff -puN fs/reiserfs/namei.c~B6-monitor-clear-i_nlink fs/reiserfs/namei.c
--- lxc/fs/reiserfs/namei.c~B6-monitor-clear-i_nlink	2006-08-08 09:18:54.000000000 -0700
+++ lxc-dave/fs/reiserfs/namei.c	2006-08-08 09:18:57.000000000 -0700
@@ -913,7 +913,7 @@ static int reiserfs_rmdir(struct inode *
 		reiserfs_warning(inode->i_sb, "%s: empty directory has nlink "
 				 "!= 2 (%d)", __FUNCTION__, inode->i_nlink);
 
-	inode->i_nlink = 0;
+	clear_nlink(inode);
 	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
 	reiserfs_update_sd(&th, inode);
 
@@ -1473,7 +1473,7 @@ static int reiserfs_rename(struct inode 
 	if (new_dentry_inode) {
 		// adjust link number of the victim
 		if (S_ISDIR(new_dentry_inode->i_mode)) {
-			new_dentry_inode->i_nlink = 0;
+			clear_nlink(new_dentry_inode);
 		} else {
 			drop_nlink(new_dentry_inode);
 		}
diff -puN fs/udf/namei.c~B6-monitor-clear-i_nlink fs/udf/namei.c
--- lxc/fs/udf/namei.c~B6-monitor-clear-i_nlink	2006-08-08 09:18:54.000000000 -0700
+++ lxc-dave/fs/udf/namei.c	2006-08-08 09:18:57.000000000 -0700
@@ -876,7 +876,7 @@ static int udf_rmdir(struct inode * dir,
 		udf_warning(inode->i_sb, "udf_rmdir",
 			"empty directory has nlink != 2 (%d)",
 			inode->i_nlink);
-	inode->i_nlink = 0;
+	clear_nlink(inode);
 	inode->i_size = 0;
 	inode_dec_link_count(inode);
 	inode->i_ctime = dir->i_ctime = dir->i_mtime = current_fs_time(dir->i_sb);
diff -puN fs/vfat/namei.c~B6-monitor-clear-i_nlink fs/vfat/namei.c
--- lxc/fs/vfat/namei.c~B6-monitor-clear-i_nlink	2006-08-08 09:18:54.000000000 -0700
+++ lxc-dave/fs/vfat/namei.c	2006-08-08 09:18:57.000000000 -0700
@@ -784,7 +784,7 @@ static int vfat_rmdir(struct inode *dir,
 		goto out;
 	drop_nlink(dir);
 
-	inode->i_nlink = 0;
+	clear_nlink(inode);
 	inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
 	fat_detach(inode);
 out:
@@ -808,7 +808,7 @@ static int vfat_unlink(struct inode *dir
 	err = fat_remove_entries(dir, &sinfo);	/* and releases bh */
 	if (err)
 		goto out;
-	inode->i_nlink = 0;
+	clear_nlink(inode);
 	inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
 	fat_detach(inode);
 out:
diff -puN include/linux/fs.h~B6-monitor-clear-i_nlink include/linux/fs.h
--- lxc/include/linux/fs.h~B6-monitor-clear-i_nlink	2006-08-08 09:18:54.000000000 -0700
+++ lxc-dave/include/linux/fs.h	2006-08-08 09:18:57.000000000 -0700
@@ -1272,6 +1272,11 @@ static inline void drop_nlink(struct ino
 	inode->i_nlink--;
 }
 
+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);
diff -puN kernel/fork.c~B6-monitor-clear-i_nlink kernel/fork.c
_

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

* Re: [PATCH 1/6] prepare for write access checks: collapse if()
  2006-08-09 16:57 ` [PATCH 1/6] prepare for write access checks: collapse if() Dave Hansen
@ 2006-08-09 17:09   ` Christoph Hellwig
  2006-08-09 17:18     ` Dave Hansen
  0 siblings, 1 reply; 21+ messages in thread
From: Christoph Hellwig @ 2006-08-09 17:09 UTC (permalink / raw)
  To: Dave Hansen; +Cc: akpm, linux-kernel, hch

On Wed, Aug 09, 2006 at 09:57:30AM -0700, Dave Hansen wrote:
> 
> We're shortly going to be adding a bunch more permission
> checks in these functions.  That requires adding either a
> bunch of new if() conditions, or some gotos.  This patch
> collapses existing if()s and uses gotos instead to
> prepare for the upcoming changes.
> 
> Signed-off-by: Dave Hansen <haveblue@us.ibm.com>


Acked-by: Christoph Hellwig <hch@lst.de>

> +	res = vfs_permission(&nd, mode);
> +	/* SuS v2 requires we report a read only fs too */
> +	if(res || !(mode & S_IWOTH) ||

except that there's a space missing after the if here :)


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

* Re: [PATCH 2/6] r/o bind mount prepwork: move open_namei()'s vfs_create()
  2006-08-09 16:57 ` [PATCH 2/6] r/o bind mount prepwork: move open_namei()'s vfs_create() Dave Hansen
@ 2006-08-09 17:09   ` Christoph Hellwig
  0 siblings, 0 replies; 21+ messages in thread
From: Christoph Hellwig @ 2006-08-09 17:09 UTC (permalink / raw)
  To: Dave Hansen; +Cc: akpm, linux-kernel, hch

On Wed, Aug 09, 2006 at 09:57:31AM -0700, Dave Hansen wrote:
> 
> The code around vfs_create() in open_namei() is getting a
> bit too complex.  Right now, there is at least the reference
> count on the dentry, and the i_mutex to worry about.  Soon,
> we'll also have mnt_writecount.
> 
> So, break the vfs_create() call out of open_namei(), and
> into a helper function.  This duplicates the call to
> may_open(), but that isn't such a bad thing since the
> arguments (acc_mode and flag) were being heavily massaged
> anyway.
> 
> Signed-off-by: Dave Hansen <haveblue@us.ibm.com>

Acked-by: Christoph Hellwig <hch@lst.de>


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

* Re: [PATCH 3/6] unlink: monitor i_nlink
  2006-08-09 16:57 ` [PATCH 3/6] unlink: monitor i_nlink Dave Hansen
@ 2006-08-09 17:11   ` Christoph Hellwig
  2006-08-09 17:17     ` Dave Hansen
  0 siblings, 1 reply; 21+ messages in thread
From: Christoph Hellwig @ 2006-08-09 17:11 UTC (permalink / raw)
  To: Dave Hansen; +Cc: akpm, linux-kernel, hch

On Wed, Aug 09, 2006 at 09:57:32AM -0700, Dave Hansen wrote:
> 
> When a filesystem decrements i_nlink to zero, it means that a
> write must be performed in order to drop the inode from the
> filesystem.
> 
> We're shortly going to have keep filesystems from being remounted
> r/o between the time that this i_nlink decrement and that write
> occurs.  
> 
> So, add a little helper function to do the decrements.  We'll
> tie into it in a bit to note when i_nlink hits zero.
> 
> Signed-off-by: Dave Hansen <haveblue@us.ibm.com>

Acked-by: Christoph Hellwig <hch@lst.de>


Note that we all (and especially Andrew :)) need to be carefull not to
introduce unguarded i_nlink decrements again.  Dave, you'll probably need
to do another audit when you introduce the real functionality.

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

* Re: [PATCH 4/6] r/o bind mount prepwork: inc_nlink() helper
  2006-08-09 16:57 ` [PATCH 4/6] r/o bind mount prepwork: inc_nlink() helper Dave Hansen
@ 2006-08-09 17:11   ` Christoph Hellwig
  0 siblings, 0 replies; 21+ messages in thread
From: Christoph Hellwig @ 2006-08-09 17:11 UTC (permalink / raw)
  To: Dave Hansen; +Cc: akpm, linux-kernel, hch

On Wed, Aug 09, 2006 at 09:57:32AM -0700, Dave Hansen wrote:
> 
> This is mostly included for parity with dec_nlink(), where
> we will have some more hooks.  This one should stay pretty
> darn straightforward for now.

Acked-by: Christoph Hellwig <hch@lst.de>


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

* Re: [PATCH 5/6] clean up OCFS2 nlink handling
  2006-08-09 16:57 ` [PATCH 5/6] clean up OCFS2 nlink handling Dave Hansen
@ 2006-08-09 17:12   ` Christoph Hellwig
  2006-08-09 19:15     ` Dave Hansen
  0 siblings, 1 reply; 21+ messages in thread
From: Christoph Hellwig @ 2006-08-09 17:12 UTC (permalink / raw)
  To: Dave Hansen; +Cc: akpm, linux-kernel, hch

On Wed, Aug 09, 2006 at 09:57:33AM -0700, Dave Hansen wrote:
> 
> OCFS2 does some operations on i_nlink, then reverts them if some
> of its operations fail to complete.  This does not fit in well
> with the drop_nlink() logic where we expect i_nlink to stay at
> zero once it gets there.
> 
> So, delay all of the nlink operations until we're sure that the
> operations have completed.  Also, introduce a small helper to
> check whether an inode has proper "unlinkable" i_nlink counts
> no matter whether it is a directory or regular inode.
> 
> This patch is broken out from the others because it does contain
> some logical changes.

looks good to me, although I probably can't ACK ocfs2 patches.  did you
look whether gfs2 in -mm needs something similar?

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

* Re: [PATCH 6/6] monitor zeroing of i_nlink
  2006-08-09 16:57 ` [PATCH 6/6] monitor zeroing of i_nlink Dave Hansen
@ 2006-08-09 17:14   ` Christoph Hellwig
  0 siblings, 0 replies; 21+ messages in thread
From: Christoph Hellwig @ 2006-08-09 17:14 UTC (permalink / raw)
  To: Dave Hansen; +Cc: akpm, linux-kernel, hch

On Wed, Aug 09, 2006 at 09:57:34AM -0700, Dave Hansen wrote:
> 
> Some filesystems, instead of simply decrementing i_nlink, simply zero
> it during an unlink operation.  We need to catch these in addition
> to the decrement operations.
> 
> Signed-off-by: Dave Hansen <haveblue@us.ibm.com>

Acked-by: Christoph Hellwig <hch@lst.de>


btw, what about adding some nice kerneldoc for all the *_nlink helpers
you added?

> ---
> 
>  kernel/fork.c                |    0 

something is screwed up in your diffstats :)


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

* Re: [PATCH 3/6] unlink: monitor i_nlink
  2006-08-09 17:11   ` Christoph Hellwig
@ 2006-08-09 17:17     ` Dave Hansen
  2006-08-09 18:27       ` Andrew Morton
  0 siblings, 1 reply; 21+ messages in thread
From: Dave Hansen @ 2006-08-09 17:17 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: akpm, linux-kernel

On Wed, 2006-08-09 at 18:11 +0100, Christoph Hellwig wrote:
> On Wed, Aug 09, 2006 at 09:57:32AM -0700, Dave Hansen wrote:
> > 
> > When a filesystem decrements i_nlink to zero, it means that a
> > write must be performed in order to drop the inode from the
> > filesystem.
> > 
> > We're shortly going to have keep filesystems from being remounted
> > r/o between the time that this i_nlink decrement and that write
> > occurs.  
> > 
> > So, add a little helper function to do the decrements.  We'll
> > tie into it in a bit to note when i_nlink hits zero.
> > 
> > Signed-off-by: Dave Hansen <haveblue@us.ibm.com>
> 
> Acked-by: Christoph Hellwig <hch@lst.de>

> Note that we all (and especially Andrew :)) need to be carefull not to
> introduce unguarded i_nlink decrements again.  Dave, you'll probably need
> to do another audit when you introduce the real functionality.

Yup, I have my eyes on it.  git and mm commits should help as well.

-- Dave


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

* Re: [PATCH 1/6] prepare for write access checks: collapse if()
  2006-08-09 17:09   ` Christoph Hellwig
@ 2006-08-09 17:18     ` Dave Hansen
  0 siblings, 0 replies; 21+ messages in thread
From: Dave Hansen @ 2006-08-09 17:18 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: akpm, linux-kernel

On Wed, 2006-08-09 at 18:09 +0100, Christoph Hellwig wrote:
> On Wed, Aug 09, 2006 at 09:57:30AM -0700, Dave Hansen wrote:
> > 
> > We're shortly going to be adding a bunch more permission
> > checks in these functions.  That requires adding either a
> > bunch of new if() conditions, or some gotos.  This patch
> > collapses existing if()s and uses gotos instead to
> > prepare for the upcoming changes.
> > 
> > Signed-off-by: Dave Hansen <haveblue@us.ibm.com>
> 
> 
> Acked-by: Christoph Hellwig <hch@lst.de>
> 
> > +	res = vfs_permission(&nd, mode);
> > +	/* SuS v2 requires we report a read only fs too */
> > +	if(res || !(mode & S_IWOTH) ||
> 
> except that there's a space missing after the if here :)

In my defense, the code I moved sucked, too. ;)

Signed-off-by: Dave Hansen <haveblue@us.ibm.com>
---

 lxc-dave/fs/open.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff -puN fs/namei.c~B1-prepwork-collapse-ifs-spacefix fs/namei.c
diff -puN fs/open.c~B1-prepwork-collapse-ifs-spacefix fs/open.c
--- lxc/fs/open.c~B1-prepwork-collapse-ifs-spacefix	2006-08-09 10:13:18.000000000 -0700
+++ lxc-dave/fs/open.c	2006-08-09 10:14:12.000000000 -0700
@@ -525,11 +525,11 @@ asmlinkage long sys_faccessat(int dfd, c
 
 	res = vfs_permission(&nd, mode);
 	/* SuS v2 requires we report a read only fs too */
-	if(res || !(mode & S_IWOTH) ||
+	if (res || !(mode & S_IWOTH) ||
 	   special_file(nd.dentry->d_inode->i_mode))
 		goto out_path_release;
 
-	if(IS_RDONLY(nd.dentry->d_inode))
+	if (IS_RDONLY(nd.dentry->d_inode))
 		res = -EROFS;
 
 out_path_release:
_


-- Dave


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

* Re: [PATCH 3/6] unlink: monitor i_nlink
  2006-08-09 17:17     ` Dave Hansen
@ 2006-08-09 18:27       ` Andrew Morton
  2006-08-12 14:15         ` Arnd Bergmann
  0 siblings, 1 reply; 21+ messages in thread
From: Andrew Morton @ 2006-08-09 18:27 UTC (permalink / raw)
  To: Dave Hansen; +Cc: Christoph Hellwig, linux-kernel

On Wed, 09 Aug 2006 10:17:19 -0700
Dave Hansen <haveblue@us.ibm.com> wrote:

> On Wed, 2006-08-09 at 18:11 +0100, Christoph Hellwig wrote:
> > On Wed, Aug 09, 2006 at 09:57:32AM -0700, Dave Hansen wrote:
> > > 
> > > When a filesystem decrements i_nlink to zero, it means that a
> > > write must be performed in order to drop the inode from the
> > > filesystem.
> > > 
> > > We're shortly going to have keep filesystems from being remounted
> > > r/o between the time that this i_nlink decrement and that write
> > > occurs.  
> > > 
> > > So, add a little helper function to do the decrements.  We'll
> > > tie into it in a bit to note when i_nlink hits zero.
> > > 
> > > Signed-off-by: Dave Hansen <haveblue@us.ibm.com>
> > 
> > Acked-by: Christoph Hellwig <hch@lst.de>
> 
> > Note that we all (and especially Andrew :)) need to be carefull not to
> > introduce unguarded i_nlink decrements again.  Dave, you'll probably need
> > to do another audit when you introduce the real functionality.
> 
> Yup, I have my eyes on it.  git and mm commits should help as well.
> 

A comprehensive way to do this sort of thing is to rename the field.  We
have >500 references, so one would do:

struct inode {
	...
	union {
		unsigned int i_nlink;
		unsigned int i_nlink_use_the_accessors_please;
	}
	...
};

then, when everything in-tree is migrated, remove `i_nlink'.

It's a bit of a hassle, but it will give the most reliable result for both
in-tree and out-of-tree filesystems.


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

* Re: [PATCH 5/6] clean up OCFS2 nlink handling
  2006-08-09 17:12   ` Christoph Hellwig
@ 2006-08-09 19:15     ` Dave Hansen
  2006-08-10  8:07       ` Steven Whitehouse
  0 siblings, 1 reply; 21+ messages in thread
From: Dave Hansen @ 2006-08-09 19:15 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: akpm, linux-kernel

On Wed, 2006-08-09 at 18:12 +0100, Christoph Hellwig wrote:
> On Wed, Aug 09, 2006 at 09:57:33AM -0700, Dave Hansen wrote:
> > OCFS2 does some operations on i_nlink, then reverts them if some
> > of its operations fail to complete.  This does not fit in well
> > with the drop_nlink() logic where we expect i_nlink to stay at
> > zero once it gets there.
> > 
> > So, delay all of the nlink operations until we're sure that the
> > operations have completed.  Also, introduce a small helper to
> > check whether an inode has proper "unlinkable" i_nlink counts
> > no matter whether it is a directory or regular inode.
> > 
> > This patch is broken out from the others because it does contain
> > some logical changes.
> 
> looks good to me, although I probably can't ACK ocfs2 patches.

That's probably OK.  One of the Oracle guys was nice enough to help me
beat it into shape and sign off on it.

> did you look whether gfs2 in -mm needs something similar?

It doesn't appear to.  It doesn't manipulate i_nlink in the same, direct
manner.

-- Dave


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

* Re: [PATCH 5/6] clean up OCFS2 nlink handling
  2006-08-09 19:15     ` Dave Hansen
@ 2006-08-10  8:07       ` Steven Whitehouse
  2006-08-10 19:06         ` Dave Hansen
  0 siblings, 1 reply; 21+ messages in thread
From: Steven Whitehouse @ 2006-08-10  8:07 UTC (permalink / raw)
  To: Dave Hansen; +Cc: linux-kernel, akpm, Christoph Hellwig

Hi,

On Wed, 2006-08-09 at 12:15 -0700, Dave Hansen wrote:
> On Wed, 2006-08-09 at 18:12 +0100, Christoph Hellwig wrote:
[snip]
> > did you look whether gfs2 in -mm needs something similar?
> 
> It doesn't appear to.  It doesn't manipulate i_nlink in the same, direct
> manner.
> 
> -- Dave

I think it will need something similar. I suspect the required changes
will all be confined to routines in inode.c. If the link count is
changed by (a) remote node(s), then gfs2_inode_attr_in() might change
the link count. Also gfs2_change_nlink() is the other place to look. I
think everywhere else is ok,

Steve.



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

* Re: [PATCH 5/6] clean up OCFS2 nlink handling
  2006-08-10  8:07       ` Steven Whitehouse
@ 2006-08-10 19:06         ` Dave Hansen
  2006-08-11  9:38           ` Steven Whitehouse
  0 siblings, 1 reply; 21+ messages in thread
From: Dave Hansen @ 2006-08-10 19:06 UTC (permalink / raw)
  To: Steven Whitehouse; +Cc: linux-kernel, akpm, Christoph Hellwig

On Thu, 2006-08-10 at 09:07 +0100, Steven Whitehouse wrote:
> On Wed, 2006-08-09 at 12:15 -0700, Dave Hansen wrote:
> > On Wed, 2006-08-09 at 18:12 +0100, Christoph Hellwig wrote:
> [snip]
> > > did you look whether gfs2 in -mm needs something similar?
> > 
> > It doesn't appear to.  It doesn't manipulate i_nlink in the same, direct
> > manner.
> 
> I think it will need something similar. I suspect the required changes
> will all be confined to routines in inode.c. If the link count is
> changed by (a) remote node(s), then gfs2_inode_attr_in() might change
> the link count. Also gfs2_change_nlink() is the other place to look. I
> think everywhere else is ok,

Well, I think this is all that it needs.  I'm trying to decide if we
need a set_nlink() function for users like this, but I'm not sure there
are enough of them.

---

 lxc-dave/fs/gfs2/inode.c |    3 +++
 2 files changed, 3 insertions(+)

diff -puN fs/gfs2/inode.c~gfs fs/gfs2/inode.c
--- lxc/fs/gfs2/inode.c~gfs	2006-08-10 09:52:33.000000000 -0700
+++ lxc-dave/fs/gfs2/inode.c	2006-08-10 12:05:06.000000000 -0700
@@ -332,6 +332,9 @@ int gfs2_change_nlink(struct gfs2_inode 
 	ip->i_di.di_ctime = get_seconds();
 	ip->i_inode.i_nlink = nlink;
 
+	if (!nlink)
+		ip->i_inode.i_state |= I_AWAITING_FINAL_IPUT;
+
 	gfs2_trans_add_bh(ip->i_gl, dibh, 1);
 	gfs2_dinode_out(&ip->i_di, dibh->b_data);
 	brelse(dibh);


-- Dave


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

* Re: [PATCH 5/6] clean up OCFS2 nlink handling
  2006-08-10 19:06         ` Dave Hansen
@ 2006-08-11  9:38           ` Steven Whitehouse
  0 siblings, 0 replies; 21+ messages in thread
From: Steven Whitehouse @ 2006-08-11  9:38 UTC (permalink / raw)
  To: Dave Hansen; +Cc: linux-kernel, akpm, Christoph Hellwig

Hi,

On Thu, 2006-08-10 at 12:06 -0700, Dave Hansen wrote:
> On Thu, 2006-08-10 at 09:07 +0100, Steven Whitehouse wrote:
> > On Wed, 2006-08-09 at 12:15 -0700, Dave Hansen wrote:
> > > On Wed, 2006-08-09 at 18:12 +0100, Christoph Hellwig wrote:
> > [snip]
> > > > did you look whether gfs2 in -mm needs something similar?
> > > 
> > > It doesn't appear to.  It doesn't manipulate i_nlink in the same, direct
> > > manner.
> > 
> > I think it will need something similar. I suspect the required changes
> > will all be confined to routines in inode.c. If the link count is
> > changed by (a) remote node(s), then gfs2_inode_attr_in() might change
> > the link count. Also gfs2_change_nlink() is the other place to look. I
> > think everywhere else is ok,
> 
> Well, I think this is all that it needs.  I'm trying to decide if we
> need a set_nlink() function for users like this, but I'm not sure there
> are enough of them.
> 
I suspect that something is required for gfs2_inode_attr_in() as well.
Here is the scenario... suppose there are two nodes A and B. On node A a
file is opened, on node B the same file is then unlinked such that its
link count hits zero. If node A then does something to the file (read or
write, it doesn't matter) then it will reread the attributes off disk
via gfs2_inode_attr_in() and discover that the link count is then zero.

We don't play any games in that once the link count has hit zero, thats
it, it will never increment above zero again. The node which actually
deals with the deallocation and clean up is the one that performs the
final close (iput). This is dealt with using the iopen lock to ensure
that we are certain of which node is the last to close the file. The
iopen lock is held in a shared state by all nodes having the file open.
On gfs2_delete_inode we attempt to upgrade the iopen lock to exclusive,
if this succeeds we then presume that no other node has the file open
and proceed with deallocation, as per a normal local filesystem.

So if I've understood what you are doing correctly, the adjustment
you've made below needs to be copied into gfs2_inode_attr_in() as well,

Steve.

> ---
> 
>  lxc-dave/fs/gfs2/inode.c |    3 +++
>  2 files changed, 3 insertions(+)
> 
> diff -puN fs/gfs2/inode.c~gfs fs/gfs2/inode.c
> --- lxc/fs/gfs2/inode.c~gfs	2006-08-10 09:52:33.000000000 -0700
> +++ lxc-dave/fs/gfs2/inode.c	2006-08-10 12:05:06.000000000 -0700
> @@ -332,6 +332,9 @@ int gfs2_change_nlink(struct gfs2_inode 
>  	ip->i_di.di_ctime = get_seconds();
>  	ip->i_inode.i_nlink = nlink;
>  
> +	if (!nlink)
> +		ip->i_inode.i_state |= I_AWAITING_FINAL_IPUT;
> +
>  	gfs2_trans_add_bh(ip->i_gl, dibh, 1);
>  	gfs2_dinode_out(&ip->i_di, dibh->b_data);
>  	brelse(dibh);
> 
> 
> -- Dave
> 


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

* Re: [PATCH 3/6] unlink: monitor i_nlink
  2006-08-09 18:27       ` Andrew Morton
@ 2006-08-12 14:15         ` Arnd Bergmann
  0 siblings, 0 replies; 21+ messages in thread
From: Arnd Bergmann @ 2006-08-12 14:15 UTC (permalink / raw)
  To: Andrew Morton; +Cc: Dave Hansen, Christoph Hellwig, linux-kernel

On Wednesday 09 August 2006 20:27, Andrew Morton wrote:
> struct inode {
>         ...
>         union {
>                 unsigned int i_nlink;
>                 unsigned int i_nlink_use_the_accessors_please;
>         }
>         ...
> };
> 
> then, when everything in-tree is migrated, remove `i_nlink'.

You can also mark a union member deprecated:

struct inode {
        ...
        union {
                unsigned int __deprecated i_nlink;
                unsigned int i_nlink_use_the_accessors_please;
        }
        ...
};

So gcc will warn about any newly introduced users.

	Arnd <><

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

end of thread, other threads:[~2006-08-12 14:16 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-08-09 16:57 [PATCH 0/6] read-only bind mount prep work Dave Hansen
2006-08-09 16:57 ` [PATCH 1/6] prepare for write access checks: collapse if() Dave Hansen
2006-08-09 17:09   ` Christoph Hellwig
2006-08-09 17:18     ` Dave Hansen
2006-08-09 16:57 ` [PATCH 2/6] r/o bind mount prepwork: move open_namei()'s vfs_create() Dave Hansen
2006-08-09 17:09   ` Christoph Hellwig
2006-08-09 16:57 ` [PATCH 4/6] r/o bind mount prepwork: inc_nlink() helper Dave Hansen
2006-08-09 17:11   ` Christoph Hellwig
2006-08-09 16:57 ` [PATCH 3/6] unlink: monitor i_nlink Dave Hansen
2006-08-09 17:11   ` Christoph Hellwig
2006-08-09 17:17     ` Dave Hansen
2006-08-09 18:27       ` Andrew Morton
2006-08-12 14:15         ` Arnd Bergmann
2006-08-09 16:57 ` [PATCH 5/6] clean up OCFS2 nlink handling Dave Hansen
2006-08-09 17:12   ` Christoph Hellwig
2006-08-09 19:15     ` Dave Hansen
2006-08-10  8:07       ` Steven Whitehouse
2006-08-10 19:06         ` Dave Hansen
2006-08-11  9:38           ` Steven Whitehouse
2006-08-09 16:57 ` [PATCH 6/6] monitor zeroing of i_nlink Dave Hansen
2006-08-09 17:14   ` Christoph Hellwig

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox