summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/afs/flock.c62
-rw-r--r--fs/afs/internal.h1
-rw-r--r--include/trace/events/afs.h7
3 files changed, 66 insertions, 4 deletions
diff --git a/fs/afs/flock.c b/fs/afs/flock.c
index 3e06a560f66b..742038a21ef7 100644
--- a/fs/afs/flock.c
+++ b/fs/afs/flock.c
@@ -158,6 +158,28 @@ static void afs_next_locker(struct afs_vnode *vnode, int error)
}
/*
+ * Kill off all waiters in the the pending lock queue due to the vnode being
+ * deleted.
+ */
+static void afs_kill_lockers_enoent(struct afs_vnode *vnode)
+{
+ struct file_lock *p;
+
+ afs_set_lock_state(vnode, AFS_VNODE_LOCK_DELETED);
+
+ while (!list_empty(&vnode->pending_locks)) {
+ p = list_entry(vnode->pending_locks.next,
+ struct file_lock, fl_u.afs.link);
+ list_del_init(&p->fl_u.afs.link);
+ p->fl_u.afs.state = -ENOENT;
+ wake_up(&p->fl_wait);
+ }
+
+ key_put(vnode->lock_key);
+ vnode->lock_key = NULL;
+}
+
+/*
* Get a lock on a file
*/
static int afs_set_lock(struct afs_vnode *vnode, struct key *key,
@@ -278,13 +300,19 @@ again:
/* attempt to release the server lock; if it fails, we just
* wait 5 minutes and it'll expire anyway */
ret = afs_release_lock(vnode, vnode->lock_key);
- if (ret < 0)
+ if (ret < 0) {
+ trace_afs_flock_ev(vnode, NULL, afs_flock_release_fail,
+ ret);
printk(KERN_WARNING "AFS:"
" Failed to release lock on {%llx:%llx} error %d\n",
vnode->fid.vid, vnode->fid.vnode, ret);
+ }
spin_lock(&vnode->lock);
- afs_next_locker(vnode, 0);
+ if (ret == -ENOENT)
+ afs_kill_lockers_enoent(vnode);
+ else
+ afs_next_locker(vnode, 0);
spin_unlock(&vnode->lock);
return;
@@ -304,12 +332,21 @@ again:
ret = afs_extend_lock(vnode, key); /* RPC */
key_put(key);
- if (ret < 0)
+ if (ret < 0) {
+ trace_afs_flock_ev(vnode, NULL, afs_flock_extend_fail,
+ ret);
pr_warning("AFS: Failed to extend lock on {%llx:%llx} error %d\n",
vnode->fid.vid, vnode->fid.vnode, ret);
+ }
spin_lock(&vnode->lock);
+ if (ret == -ENOENT) {
+ afs_kill_lockers_enoent(vnode);
+ spin_unlock(&vnode->lock);
+ return;
+ }
+
if (vnode->lock_state != AFS_VNODE_LOCK_EXTENDING)
goto again;
afs_set_lock_state(vnode, AFS_VNODE_LOCK_GRANTED);
@@ -333,6 +370,11 @@ again:
spin_unlock(&vnode->lock);
return;
+ case AFS_VNODE_LOCK_DELETED:
+ afs_kill_lockers_enoent(vnode);
+ spin_unlock(&vnode->lock);
+ return;
+
default:
/* Looks like a lock request was withdrawn. */
spin_unlock(&vnode->lock);
@@ -435,6 +477,10 @@ static int afs_do_setlk(struct file *file, struct file_lock *fl)
spin_lock(&vnode->lock);
list_add_tail(&fl->fl_u.afs.link, &vnode->pending_locks);
+ ret = -ENOENT;
+ if (vnode->lock_state == AFS_VNODE_LOCK_DELETED)
+ goto error_unlock;
+
/* If we've already got a lock on the server then try to move to having
* the VFS grant the requested lock. Note that this means that other
* clients may get starved out.
@@ -489,6 +535,13 @@ try_to_lock:
afs_next_locker(vnode, ret);
goto error_unlock;
+ case -ENOENT:
+ fl->fl_u.afs.state = ret;
+ trace_afs_flock_ev(vnode, fl, afs_flock_fail_other, ret);
+ list_del_init(&fl->fl_u.afs.link);
+ afs_kill_lockers_enoent(vnode);
+ goto error_unlock;
+
default:
fl->fl_u.afs.state = ret;
trace_afs_flock_ev(vnode, fl, afs_flock_fail_other, ret);
@@ -638,6 +691,9 @@ static int afs_do_getlk(struct file *file, struct file_lock *fl)
_enter("");
+ if (vnode->lock_state == AFS_VNODE_LOCK_DELETED)
+ return -ENOENT;
+
fl->fl_type = F_UNLCK;
/* check local lock records first */
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index 6e680783f59f..5eb6be3f73b2 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -599,6 +599,7 @@ enum afs_lock_state {
AFS_VNODE_LOCK_EXTENDING, /* We're extending a lock on the server */
AFS_VNODE_LOCK_NEED_UNLOCK, /* We need to unlock on the server */
AFS_VNODE_LOCK_UNLOCKING, /* We're telling the server to unlock */
+ AFS_VNODE_LOCK_DELETED, /* The vnode has been deleted whilst we have a lock */
};
/*
diff --git a/include/trace/events/afs.h b/include/trace/events/afs.h
index 24c058a93e8f..21b896fabb2f 100644
--- a/include/trace/events/afs.h
+++ b/include/trace/events/afs.h
@@ -156,9 +156,11 @@ enum afs_flock_event {
afs_flock_acquired,
afs_flock_callback_break,
afs_flock_defer_unlock,
+ afs_flock_extend_fail,
afs_flock_fail_other,
afs_flock_fail_perm,
afs_flock_no_lockers,
+ afs_flock_release_fail,
afs_flock_timestamp,
afs_flock_try_to_lock,
afs_flock_vfs_lock,
@@ -323,15 +325,18 @@ enum afs_flock_operation {
EM(AFS_VNODE_LOCK_GRANTED, "GRANTED") \
EM(AFS_VNODE_LOCK_EXTENDING, "EXTENDING") \
EM(AFS_VNODE_LOCK_NEED_UNLOCK, "NEED_UNLOCK") \
- E_(AFS_VNODE_LOCK_UNLOCKING, "UNLOCKING") \
+ EM(AFS_VNODE_LOCK_UNLOCKING, "UNLOCKING") \
+ E_(AFS_VNODE_LOCK_DELETED, "DELETED")
#define afs_flock_events \
EM(afs_flock_acquired, "Acquired") \
EM(afs_flock_callback_break, "Callback") \
EM(afs_flock_defer_unlock, "D-Unlock") \
+ EM(afs_flock_extend_fail, "Ext_Fail") \
EM(afs_flock_fail_other, "ErrOther") \
EM(afs_flock_fail_perm, "ErrPerm ") \
EM(afs_flock_no_lockers, "NoLocker") \
+ EM(afs_flock_release_fail, "Rel_Fail") \
EM(afs_flock_timestamp, "Timestmp") \
EM(afs_flock_try_to_lock, "TryToLck") \
EM(afs_flock_vfs_lock, "VFSLock ") \