leases: fix write-open/read-lease race
authorJ. Bruce Fields <bfields@redhat.com>
Wed, 21 Sep 2011 14:58:13 +0000 (10:58 -0400)
committerroot <root@serles.lst.de>
Fri, 28 Oct 2011 12:59:00 +0000 (14:59 +0200)
In setlease, we use i_writecount to decide whether we can give out a
read lease.

In open, we break leases before incrementing i_writecount.

There is therefore a window between the break lease and the i_writecount
increment when setlease could add a new read lease.

This would leave us with a simultaneous write open and read lease, which
shouldn't happen.

Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Signed-off-by: Christoph Hellwig <hch@lst.de>
fs/namei.c
fs/open.c

index 9061157e39d6e7bb87c36806ecdee29325d59be6..7657be4352bf641aac7590ca388ec20133add227 100644 (file)
@@ -2035,10 +2035,7 @@ static int may_open(struct path *path, int acc_mode, int flag)
        if (flag & O_NOATIME && !inode_owner_or_capable(inode))
                return -EPERM;
 
-       /*
-        * Ensure there are no outstanding leases on the file.
-        */
-       return break_lease(inode, flag);
+       return 0;
 }
 
 static int handle_truncate(struct file *filp)
index f711921094576c8b46f2aefe50d76da75bfe1c68..22c41b543f2dfc00ce74665e4fdf24db1d8321ac 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -685,6 +685,10 @@ static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
        if (error)
                goto cleanup_all;
 
+       error = break_lease(inode, f->f_flags);
+       if (error)
+               goto cleanup_all;
+
        if (!open && f->f_op)
                open = f->f_op->open;
        if (open) {