diff --git a/fs/afs/flock.c b/fs/afs/flock.c index e432bd27a2e7..8b02f0056d54 100644 --- a/fs/afs/flock.c +++ b/fs/afs/flock.c @@ -40,8 +40,34 @@ void afs_lock_may_be_available(struct afs_vnode *vnode) */ static void afs_schedule_lock_extension(struct afs_vnode *vnode) { - queue_delayed_work(afs_lock_manager, &vnode->lock_work, - AFS_LOCKWAIT * HZ / 2); + ktime_t expires_at, now, duration; + u64 duration_j; + + expires_at = ktime_add_ms(vnode->locked_at, AFS_LOCKWAIT * 1000 / 2); + now = ktime_get_real(); + duration = ktime_sub(expires_at, now); + if (duration <= 0) + duration_j = 0; + else + duration_j = nsecs_to_jiffies(ktime_to_ns(duration)); + + queue_delayed_work(afs_lock_manager, &vnode->lock_work, duration_j); +} + +/* + * In the case of successful completion of a lock operation, record the time + * the reply appeared and start the lock extension timer. + */ +void afs_lock_op_done(struct afs_call *call) +{ + struct afs_vnode *vnode = call->reply[0]; + + if (call->error == 0) { + spin_lock(&vnode->lock); + vnode->locked_at = call->reply_time; + afs_schedule_lock_extension(vnode); + spin_unlock(&vnode->lock); + } } /* diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c index 5eefcf35d73d..9d405f96cc91 100644 --- a/fs/afs/fsclient.c +++ b/fs/afs/fsclient.c @@ -1845,6 +1845,7 @@ static const struct afs_call_type afs_RXFSSetLock = { .name = "FS.SetLock", .op = afs_FS_SetLock, .deliver = afs_deliver_fs_xxxx_lock, + .done = afs_lock_op_done, .destructor = afs_flat_call_destructor, }; @@ -1855,6 +1856,7 @@ static const struct afs_call_type afs_RXFSExtendLock = { .name = "FS.ExtendLock", .op = afs_FS_ExtendLock, .deliver = afs_deliver_fs_xxxx_lock, + .done = afs_lock_op_done, .destructor = afs_flat_call_destructor, }; @@ -1889,6 +1891,7 @@ int afs_fs_set_lock(struct afs_fs_cursor *fc, afs_lock_type_t type) call->key = fc->key; call->reply[0] = vnode; + call->want_reply_time = true; /* marshall the parameters */ bp = call->request; @@ -1925,6 +1928,7 @@ int afs_fs_extend_lock(struct afs_fs_cursor *fc) call->key = fc->key; call->reply[0] = vnode; + call->want_reply_time = true; /* marshall the parameters */ bp = call->request; diff --git a/fs/afs/internal.h b/fs/afs/internal.h index 61e24551574d..6e680783f59f 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -638,6 +638,7 @@ struct afs_vnode { struct list_head granted_locks; /* locks granted on this file */ struct delayed_work lock_work; /* work to be done in locking */ struct key *lock_key; /* Key to be used in lock ops */ + ktime_t locked_at; /* Time at which lock obtained */ enum afs_lock_state lock_state : 8; afs_lock_type_t lock_type : 8; @@ -905,6 +906,7 @@ extern void afs_put_read(struct afs_read *); */ extern struct workqueue_struct *afs_lock_manager; +extern void afs_lock_op_done(struct afs_call *); extern void afs_lock_work(struct work_struct *); extern void afs_lock_may_be_available(struct afs_vnode *); extern int afs_lock(struct file *, int, struct file_lock *); diff --git a/fs/afs/yfsclient.c b/fs/afs/yfsclient.c index 95b04cb76c8c..73546c2d89ee 100644 --- a/fs/afs/yfsclient.c +++ b/fs/afs/yfsclient.c @@ -1801,6 +1801,7 @@ static const struct afs_call_type yfs_RXYFSSetLock = { .name = "YFS.SetLock", .op = yfs_FS_SetLock, .deliver = yfs_deliver_fs_xxxx_lock, + .done = afs_lock_op_done, .destructor = afs_flat_call_destructor, }; @@ -1811,6 +1812,7 @@ static const struct afs_call_type yfs_RXYFSExtendLock = { .name = "YFS.ExtendLock", .op = yfs_FS_ExtendLock, .deliver = yfs_deliver_fs_xxxx_lock, + .done = afs_lock_op_done, .destructor = afs_flat_call_destructor, }; @@ -1847,6 +1849,7 @@ int yfs_fs_set_lock(struct afs_fs_cursor *fc, afs_lock_type_t type) call->key = fc->key; call->reply[0] = vnode; + call->want_reply_time = true; /* marshall the parameters */ bp = call->request; @@ -1884,6 +1887,7 @@ int yfs_fs_extend_lock(struct afs_fs_cursor *fc) call->key = fc->key; call->reply[0] = vnode; + call->want_reply_time = true; /* marshall the parameters */ bp = call->request;