From: David Howells dhowells@redhat.com
[ Upstream commit 68ce801ffd82e72d5005ab5458e8b9e59f24d9cc ]
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 Signed-off-by: Sasha Levin sashal@kernel.org Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- fs/afs/flock.c | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-)
diff --git a/fs/afs/flock.c b/fs/afs/flock.c index 1bb300e..dffbb45 100644 --- a/fs/afs/flock.c +++ b/fs/afs/flock.c @@ -432,10 +432,6 @@ static int afs_do_setlk(struct file *file, struct file_lock *fl)
_enter("{%x:%u},%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; @@ -587,10 +583,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; @@ -618,12 +610,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;