netfid, length,
pfLock->fl_start, numUnlock, numLock, lockType,
wait_flag);
+ if (rc == 0 && (pfLock->fl_flags & FL_POSIX))
+ posix_lock_file(file, pfLock);
FreeXid(xid);
return rc;
}
if (resp->status == NLM_LCK_GRANTED) {
fl->fl_u.nfs_fl.state = host->h_state;
fl->fl_u.nfs_fl.flags |= NFS_LCK_GRANTED;
+ fl->fl_flags |= FL_SLEEP;
+ if (posix_lock_file_wait(fl->fl_file, fl) < 0)
+ printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n",
+ __FUNCTION__);
}
status = nlm_stat_to_errno(resp->status);
out:
if (req->a_flags & RPC_TASK_ASYNC) {
status = nlmclnt_async_call(req, NLMPROC_UNLOCK,
nlmclnt_unlock_callback);
+ /* Hrmf... Do the unlock early since locks_remove_posix()
+ * really expects us to free the lock synchronously */
+ posix_lock_file(fl->fl_file, fl);
if (status < 0) {
nlmclnt_release_lockargs(req);
kfree(req);
if (status < 0)
return status;
+ posix_lock_file(fl->fl_file, fl);
if (resp->status == NLM_LCK_GRANTED)
return 0;
}
if (status != NLM_LCK_GRANTED)
printk(KERN_WARNING "lockd: unexpected unlock status: %d\n", status);
-
die:
nlm_release_host(req->a_host);
nlmclnt_release_lockargs(req);
return __posix_lock_file(filp->f_dentry->d_inode, fl);
}
+/**
+ * posix_lock_file_wait - Apply a POSIX-style lock to a file
+ * @filp: The file to apply the lock to
+ * @fl: The lock to be applied
+ *
+ * Add a POSIX style lock to a file.
+ * We merge adjacent & overlapping locks whenever possible.
+ * POSIX locks are sorted by owner task, then by starting address
+ */
+int posix_lock_file_wait(struct file *filp, struct file_lock *fl)
+{
+ int error;
+ might_sleep ();
+ for (;;) {
+ error = __posix_lock_file(filp->f_dentry->d_inode, fl);
+ if ((error != -EAGAIN) || !(fl->fl_flags & FL_SLEEP))
+ break;
+ error = wait_event_interruptible(fl->fl_wait, !fl->fl_next);
+ if (!error)
+ continue;
+
+ locks_delete_block(fl);
+ break;
+ }
+ return error;
+}
+EXPORT_SYMBOL(posix_lock_file_wait);
+
/**
* locks_mandatory_locked - Check for an active lock
* @inode: the file to check
if (filp->f_op && filp->f_op->lock != NULL) {
error = filp->f_op->lock(filp, cmd, file_lock);
- if (error < 0)
- goto out;
+ goto out;
}
for (;;) {
if (filp->f_op && filp->f_op->lock != NULL) {
error = filp->f_op->lock(filp, cmd, file_lock);
- if (error < 0)
- goto out;
+ goto out;
}
for (;;) {
if (filp->f_op && filp->f_op->lock != NULL) {
filp->f_op->lock(filp, F_SETLK, &lock);
- /* Ignore any error -- we must remove the locks anyway */
+ goto out;
}
/* Can't use posix_lock_file here; we need to remove it no matter
before = &fl->fl_next;
}
unlock_kernel();
+out:
if (lock.fl_ops && lock.fl_ops->fl_release_private)
lock.fl_ops->fl_release_private(&lock);
}
nfs4_put_lock_state(lsp);
out:
up(&state->lock_sema);
+ if (status == 0)
+ posix_lock_file(request->fl_file, request);
return nfs4_map_errors(status);
}
nfs4_put_lock_state(lsp);
out:
up(&state->lock_sema);
+ if (status == 0) {
+ /* Note: we always want to sleep here! */
+ request->fl_flags |= FL_SLEEP;
+ if (posix_lock_file_wait(request->fl_file, request) < 0)
+ printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __FUNCTION__);
+ }
return nfs4_map_errors(status);
}
extern void locks_remove_flock(struct file *);
extern struct file_lock *posix_test_lock(struct file *, struct file_lock *);
extern int posix_lock_file(struct file *, struct file_lock *);
+extern int posix_lock_file_wait(struct file *, struct file_lock *);
extern void posix_block_lock(struct file_lock *, struct file_lock *);
extern void posix_unblock_lock(struct file *, struct file_lock *);
extern int posix_locks_deadlock(struct file_lock *, struct file_lock *);