afs: Fix AFS file locking to allow fine grained locks
authorDavid Howells <dhowells@redhat.com>
Thu, 25 Apr 2019 13:26:50 +0000 (14:26 +0100)
committerDavid Howells <dhowells@redhat.com>
Thu, 25 Apr 2019 13:26:50 +0000 (14:26 +0100)
Fix AFS file locking to allow fine grained locks as some applications, such
as firefox, won't work if they can't take such locks on certain state files
- thereby preventing the use of kAFS to distribute a home directory.

Note that this cannot be made completely functional as the protocol only
has provision for whole-file locks, so there exists the possibility of a
process deadlocking itself by getting a partial read-lock on a file first
and then trying to get a non-overlapping write-lock - but we got the
server's read lock with the first lock, so we're now stuck.

OpenAFS solves this by just granting any partial-range lock directly
without consulting the server - and hoping there's no remote collision.  I
want to implement that in a separate patch and it requires a bit more
thought.

Fixes: 8d6c554126b8 ("AFS: implement file locking")
Reported-by: Jonathan Billings <jsbillings@jsbillings.org>
Signed-off-by: David Howells <dhowells@redhat.com>
fs/afs/flock.c

index 8b02f0056d54340efc74177ce893a0473f4c1469..6919f53ed4ad90481cca3578aa5bd6c1f8f4bb04 100644 (file)
@@ -458,10 +458,6 @@ static int afs_do_setlk(struct file *file, struct file_lock *fl)
 
        _enter("{%llx:%llu},%u", vnode->fid.vid, vnode->fid.vnode, fl->fl_type);
 
-       /* only whole-file locks are supported */
-       if (fl->fl_start != 0 || fl->fl_end != OFFSET_MAX)
-               return -EINVAL;
-
        fl->fl_ops = &afs_lock_ops;
        INIT_LIST_HEAD(&fl->fl_u.afs.link);
        fl->fl_u.afs.state = AFS_LOCK_PENDING;
@@ -613,10 +609,6 @@ static int afs_do_unlk(struct file *file, struct file_lock *fl)
        /* Flush all pending writes before doing anything with locks. */
        vfs_fsync(file, 0);
 
-       /* only whole-file unlocks are supported */
-       if (fl->fl_start != 0 || fl->fl_end != OFFSET_MAX)
-               return -EINVAL;
-
        ret = posix_lock_file(file, fl, NULL);
        _leave(" = %d [%u]", ret, vnode->lock_state);
        return ret;
@@ -644,12 +636,15 @@ static int afs_do_getlk(struct file *file, struct file_lock *fl)
                        goto error;
 
                lock_count = READ_ONCE(vnode->status.lock_count);
-               if (lock_count > 0)
-                       fl->fl_type = F_RDLCK;
-               else
-                       fl->fl_type = F_WRLCK;
-               fl->fl_start = 0;
-               fl->fl_end = OFFSET_MAX;
+               if (lock_count != 0) {
+                       if (lock_count > 0)
+                               fl->fl_type = F_RDLCK;
+                       else
+                               fl->fl_type = F_WRLCK;
+                       fl->fl_start = 0;
+                       fl->fl_end = OFFSET_MAX;
+                       fl->fl_pid = 0;
+               }
        }
 
        ret = 0;