From mboxrd@z Thu Jan 1 00:00:00 1970 From: Dave Hansen Subject: [PATCH 06/26] elevate write count open()'d files Date: Fri, 22 Jun 2007 13:03:10 -0700 Message-ID: <20070622200310.CD377780@kernel> References: <20070622200303.82D9CC3A@kernel> Cc: linux-fsdevel@vger.kernel.org, hch@infradead.org, viro@ftp.linux.org.uk, Dave Hansen To: akpm@osdl.org Return-path: Received: from e33.co.us.ibm.com ([32.97.110.151]:47979 "EHLO e33.co.us.ibm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751157AbXFVUDY (ORCPT ); Fri, 22 Jun 2007 16:03:24 -0400 Received: from d03relay02.boulder.ibm.com (d03relay02.boulder.ibm.com [9.17.195.227]) by e33.co.us.ibm.com (8.13.8/8.13.8) with ESMTP id l5MK3NwL017782 for ; Fri, 22 Jun 2007 16:03:23 -0400 Received: from d03av01.boulder.ibm.com (d03av01.boulder.ibm.com [9.17.195.167]) by d03relay02.boulder.ibm.com (8.13.8/8.13.8/NCO v8.3) with ESMTP id l5MK3Dlg224512 for ; Fri, 22 Jun 2007 14:03:18 -0600 Received: from d03av01.boulder.ibm.com (loopback [127.0.0.1]) by d03av01.boulder.ibm.com (8.12.11.20060308/8.13.3) with ESMTP id l5MK3CxV028699 for ; Fri, 22 Jun 2007 14:03:13 -0600 In-Reply-To: <20070622200303.82D9CC3A@kernel> Sender: linux-fsdevel-owner@vger.kernel.org List-Id: linux-fsdevel.vger.kernel.org This is the first really tricky patch in the series. It elevates the writer count on a mount each time a non-special file is opened for write. This is not completely apparent in the patch because the two if() conditions in may_open() above the mnt_want_write() call are, combined, equivalent to special_file(). There is also an elevated count around the vfs_create() call in open_namei(). The count needs to be kept elevated all the way into the may_open() call. Otherwise, when the write is dropped, a ro->rw transisition could occur. This would lead to having rw access on the newly created file, while the vfsmount is ro. That is bad. Some filesystems forego the use of normal vfs calls to create struct files. Make sure that these users elevate the mnt writer count because they will get __fput(), and we need to make sure they're balanced. Signed-off-by: Dave Hansen --- lxc-dave/fs/file_table.c | 9 ++++++++- lxc-dave/fs/namei.c | 20 ++++++++++++++++---- lxc-dave/ipc/mqueue.c | 3 +++ 3 files changed, 27 insertions(+), 5 deletions(-) diff -puN fs/file_table.c~14-24-tricky-elevate-write-count-files-are-open-ed fs/file_table.c --- lxc/fs/file_table.c~14-24-tricky-elevate-write-count-files-are-open-ed 2007-06-22 10:00:02.000000000 -0700 +++ lxc-dave/fs/file_table.c 2007-06-22 10:00:02.000000000 -0700 @@ -169,6 +169,10 @@ int init_file(struct file *file, struct file->f_mapping = dentry->d_inode->i_mapping; file->f_mode = mode; file->f_op = fop; + if (mode & FMODE_WRITE) { + error = mnt_want_write(mnt); + WARN_ON(error); + } return error; } EXPORT_SYMBOL(init_file); @@ -206,8 +210,11 @@ void fastcall __fput(struct file *file) if (unlikely(S_ISCHR(inode->i_mode) && inode->i_cdev != NULL)) cdev_put(inode->i_cdev); fops_put(file->f_op); - if (file->f_mode & FMODE_WRITE) + if (file->f_mode & FMODE_WRITE) { put_write_access(inode); + if (!special_file(inode->i_mode)) + mnt_drop_write(mnt); + } put_pid(file->f_owner.pid); file_kill(file); file->f_path.dentry = NULL; diff -puN fs/namei.c~14-24-tricky-elevate-write-count-files-are-open-ed fs/namei.c --- lxc/fs/namei.c~14-24-tricky-elevate-write-count-files-are-open-ed 2007-06-22 10:00:02.000000000 -0700 +++ lxc-dave/fs/namei.c 2007-06-22 10:00:02.000000000 -0700 @@ -1544,8 +1544,15 @@ int may_open(struct nameidata *nd, int a return -EACCES; flag &= ~O_TRUNC; - } else if (IS_RDONLY(inode) && (flag & FMODE_WRITE)) - return -EROFS; + } else if (flag & FMODE_WRITE) { + /* + * effectively: !special_file() + * balanced by __fput() + */ + error = mnt_want_write(nd->mnt); + if (error) + return error; + } /* * An append-only file must be opened in append mode for writing. */ @@ -1684,14 +1691,17 @@ do_last: } if (IS_ERR(nd->intent.open.file)) { - mutex_unlock(&dir->d_inode->i_mutex); error = PTR_ERR(nd->intent.open.file); - goto exit_dput; + goto exit_mutex_unlock; } /* Negative dentry, just create the file */ if (!path.dentry->d_inode) { + error = mnt_want_write(nd->mnt); + if (error) + goto exit_mutex_unlock; error = open_namei_create(nd, &path, flag, mode); + mnt_drop_write(nd->mnt); if (error) goto exit; return 0; @@ -1729,6 +1739,8 @@ ok: goto exit; return 0; +exit_mutex_unlock: + mutex_unlock(&dir->d_inode->i_mutex); exit_dput: dput_path(&path, nd); exit: diff -puN ipc/mqueue.c~14-24-tricky-elevate-write-count-files-are-open-ed ipc/mqueue.c --- lxc/ipc/mqueue.c~14-24-tricky-elevate-write-count-files-are-open-ed 2007-06-22 10:00:02.000000000 -0700 +++ lxc-dave/ipc/mqueue.c 2007-06-22 10:00:02.000000000 -0700 @@ -687,6 +687,9 @@ asmlinkage long sys_mq_open(const char _ goto out; filp = do_open(dentry, oflag); } else { + error = mnt_want_write(mqueue_mnt); + if (error) + goto out; filp = do_create(mqueue_mnt->mnt_root, dentry, oflag, mode, u_attr); } diff -puN fs/ext2/ioctl.c~14-24-tricky-elevate-write-count-files-are-open-ed fs/ext2/ioctl.c _