2004-09-13 18:54:09

by Sridhar Samudrala

[permalink] [raw]
Subject: [RFC/PATCH] NFS file locking for clustered filesystems

Following the recent discussion on NFS file locking for clustered filesystems,
we have come up with a patch that introduces asynchronous lock request
mechanism so that the underlying filesystem lock operation can be called
without blocking lockd.

Changes to filesystem lock call: f_op->lock()
---------------------------------------------
- The calls to the filesystem will return immediately with 0 or an appropriate
error if they can perform the operation without involving any network IO.
- If the filesystem has to do any network io to perform the operation, it
should return EINPROGRESS, start the operation in background and return the
result asynchronously using a callback once the operation is completed.
- The following new callback is added to struct lock_manager_operations
int (*fl_vfs_callback)(struct file_lock *fl, struct file_lock *conf_lock,
int result);

Changes to lock manager:
------------------------
- Replace posix_lock_file() and posix_test_lock() calls in lockd with new
routines vfs_lock_file() and vfs_test_lock() that make calls to the
underlying filesystem.
- For a blocking call(F_SETLKW), if the filesystem returns EINPROGRESS, the
lock manager will return NLM_LCK_BLOCKED to the client and adds the
deferred request to the nlm_blocked list. Once the filesystem completes the
asynchronous operation, it invokes fl_vfs_callback() with the appropriate
result. Based on the result, the callback will update the deferred request,
moves it to the head of nlm_blocked and wakes up lockd.
nlmsvc_retry_blocked() will find the deferred block and send a GRANTED_MSG
to the client with NLM_LCK_GRANTED/NLM_LCK_DENIED when the request is
retried.
- For a non-blocking call(F_SETLK, F_GETLK), if the fileystem returns
EINPROGRESS, the lock manager defers the lock request for 7secs and adds it
to the nlm_blocked list. If the callback is not invoked before the deferred
duration, NLM_LCK_DENIED is sent to the client when it is revisited. If the
callback is invoked before the deferred duration, it updates the blocked
request, moves it to the head of nlm_blocked and wakes up lockd.
nlmsvc_retry_blocked() will find the deferred block and revists the
request causing NLM_LCK_GRANTED/NLM_LCK_DENIED to be sent to the client
based on the result.

I would appreciate any feedback and suggestions for improvements.

Thanks
Sridhar


--- /nas/linux-2.6.8+kdb+nfsv4/fs/locks.c 2004-08-17 14:35:33.000000000 -0700
+++ /nas/linux-2.6.8-locks/fs/locks.c 2004-09-10 15:28:18.497574176 -0700
@@ -443,6 +443,8 @@ static void locks_delete_block(struct fi
{
lock_kernel();
__locks_delete_block(waiter);
+ if (waiter->fl_flags & FL_FREE)
+ kfree(waiter);
unlock_kernel();
}

@@ -554,6 +556,21 @@ static int posix_locks_conflict(struct f
return (locks_conflict(caller_fl, sys_fl));
}

+int posix_locks_same(struct file_lock *caller_fl, struct file_lock *sys_fl)
+{
+ /* POSIX locks owned by the same process do not conflict with
+ * each other.
+ */
+ if (IS_POSIX(sys_fl) &&
+ posix_same_owner(caller_fl, sys_fl) &&
+ caller_fl->fl_type == sys_fl->fl_type &&
+ caller_fl->fl_start <= sys_fl->fl_start &&
+ caller_fl->fl_end >= sys_fl->fl_end)
+ return 1;
+ else
+ return 0;
+}
+
/* Determine if lock sys_fl blocks lock caller_fl. FLOCK specific
* checking before calling the locks_conflict().
*/
@@ -614,7 +631,51 @@ posix_test_lock(struct file *filp, struc
return (cfl);
}

+int
+vfs_test_lock(struct file *filp, struct file_lock *fl, struct file_lock **conf)
+{
+ struct file_lock *cfl;
+ int result = 0;
+ int samelock = 0;
+
+ lock_kernel();
+ for (cfl = filp->f_dentry->d_inode->i_flock; cfl; cfl = cfl->fl_next) {
+ if (!IS_POSIX(cfl))
+ continue;
+ if (posix_locks_same(cfl, fl))
+ samelock = 1;
+ if (posix_locks_conflict(cfl, fl))
+ break;
+ }
+ unlock_kernel();
+
+ if (cfl || samelock)
+ goto out;
+
+ if (filp->f_op && filp->f_op->lock) {
+ struct file_lock fl1;
+ memcpy(&fl1, fl, sizeof(struct file_lock));
+ result = filp->f_op->lock(filp, F_GETLK, &fl1);
+ if (result == 0 && fl1.fl_type != F_UNLCK) {
+ cfl = (struct file_lock *)kmalloc(sizeof(struct file_lock), GFP_KERNEL);
+ if (cfl) {
+ memcpy(cfl, &fl1, sizeof(struct file_lock));
+ cfl->fl_flags |= FL_FREE;
+ }
+ }
+ }
+out:
+ if (cfl) {
+ *conf = cfl;
+ return 0;
+ }
+ if (result == 0)
+ return -ENOLCK;
+ return result;
+}
+
EXPORT_SYMBOL(posix_test_lock);
+EXPORT_SYMBOL(vfs_test_lock);

/* This function tests for deadlock condition before putting a process to
* sleep. The detection scheme is no longer recursive. Recursive was neat,
@@ -713,6 +774,7 @@ out:
}

EXPORT_SYMBOL(posix_lock_file);
+EXPORT_SYMBOL(vfs_lock_file);

static int __posix_lock_file(struct inode *inode, struct file_lock *request)
{
@@ -905,6 +967,28 @@ int posix_lock_file(struct file *filp, s
return __posix_lock_file(filp->f_dentry->d_inode, fl);
}

+int vfs_lock_file(struct file *filp, struct file_lock *fl)
+{
+ int rc = 0;
+
+ if (fl->fl_type != F_UNLCK) {
+ /* Check the underlying filesystem will allow us to lock */
+ if (filp->f_op && filp->f_op->lock) {
+ rc = filp->f_op->lock(filp, F_SETLK, fl);
+ }
+ if (rc == 0)
+ rc = __posix_lock_file(filp->f_dentry->d_inode, fl);
+ }
+ else {
+ rc = __posix_lock_file(filp->f_dentry->d_inode, fl);
+ /* Check the underlying filesystem will allow us to (un)lock */
+ if (!rc && filp->f_op && filp->f_op->lock) {
+ rc = filp->f_op->lock(filp, F_SETLK, fl);
+ }
+ }
+ return rc;
+}
+
/**
* posix_lock_file_wait - Apply a POSIX-style lock to a file
* @filp: The file to apply the lock to
@@ -1761,12 +1845,18 @@ void locks_remove_flock(struct file *fil
* @blocker: the lock which is blocking
* @waiter: the lock which conflicts and has to wait
*
- * lockd needs to block waiting for locks.
+ * This routine is for the use of lockd alone. It allows lockd to block
+ * waiting for locks by putting the lock in the list of blocking locks
+ * without actually going to sleep itself.
*/
-void
+int
posix_block_lock(struct file_lock *blocker, struct file_lock *waiter)
{
- locks_insert_block(blocker, waiter);
+ int error;
+ error = posix_locks_deadlock(waiter, blocker);
+ if (!error)
+ locks_insert_block(blocker, waiter);
+ return error;
}

EXPORT_SYMBOL(posix_block_lock);
@@ -1792,7 +1882,7 @@ posix_unblock_lock(struct file *filp, st
} else {
unlock_kernel();
waiter->fl_type = F_UNLCK;
- posix_lock_file(filp, waiter);
+ vfs_lock_file(filp, waiter);
}
}

--- /nas/linux-2.6.8+kdb+nfsv4/fs/lockd/svc.c 2004-08-14 03:55:35.000000000 -0700
+++ /nas/linux-2.6.8-locks/fs/lockd/svc.c 2004-09-08 21:26:18.000000000 -0700
@@ -312,6 +312,45 @@ out:
up(&nlmsvc_sema);
}

+int
+nlmsvc_dispatch(struct svc_rqst *rqstp, u32 *statp)
+{
+ u32 *statp;
+ struct svc_procedure *procp;
+ kxdrproc_t xdr;
+ struct kvec * argv = &rqstp->rq_arg.head[0];
+ struct kvec * resv = &rqstp->rq_res.head[0];
+
+ dprintk("lockd: nlmsvc_dispatch vers %d proc %d\n",
+ rqstp->rq_vers, rqstp->rq_proc);
+
+ procp = rqstp->rq_procinfo;
+ statp = resv->iov_base +resv->iov_len;
+
+ /* Decode arguments */
+ xdr = procp->pc_decode;
+
+ if (xdr && !xdr(rqstp, argv->iov_base, rqstp->rq_argp)) {
+ dprintk("lockd: failed to decode arguments!\n");
+ *statp = rpc_garbage_args;
+ return 1;
+ }
+ /* Now call the procedure handler, and encode status. */
+ *statp = procp->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp);
+ if (((struct nlm_res *)(rqstp->rq_resp))->status == EINPROGRESS) {
+ dprintk("lockd: Deferring request!\n");
+ return 0;
+ }
+ /* Encode reply */
+ if (*statp == rpc_success && (xdr = procp->pc_encode)
+ && !xdr(rqstp, resv->iov_base+resv->iov_len, rqstp->rq_resp)) {
+ dprintk("lockd: failed to encode reply\n");
+ /* serv->sv_stats->rpcsystemerr++; */
+ *statp = rpc_system_err;
+ }
+ return 1;
+}
+
/*
* Sysctl parameters (same as module parameters, different interface).
*/
@@ -444,12 +483,14 @@ static struct svc_version nlmsvc_version
.vs_vers = 1,
.vs_nproc = 17,
.vs_proc = nlmsvc_procedures,
+ .vs_dispatch = nlmsvc_dispatch,
.vs_xdrsize = NLMSVC_XDRSIZE,
};
static struct svc_version nlmsvc_version3 = {
.vs_vers = 3,
.vs_nproc = 24,
.vs_proc = nlmsvc_procedures,
+ .vs_dispatch = nlmsvc_dispatch,
.vs_xdrsize = NLMSVC_XDRSIZE,
};
#ifdef CONFIG_LOCKD_V4
@@ -457,6 +498,7 @@ static struct svc_version nlmsvc_version
.vs_vers = 4,
.vs_nproc = 24,
.vs_proc = nlmsvc_procedures4,
+ .vs_dispatch = nlmsvc_dispatch,
.vs_xdrsize = NLMSVC_XDRSIZE,
};
#endif
--- /nas/linux-2.6.8+kdb+nfsv4/fs/lockd/svclock.c 2004-08-17 14:35:33.000000000 -0700
+++ /nas/linux-2.6.8-locks/fs/lockd/svclock.c 2004-09-08 21:00:21.000000000 -0700
@@ -237,8 +237,18 @@ nlmsvc_delete_block(struct nlm_block *bl

/* Remove block from list */
nlmsvc_remove_block(block);
+#if 0
posix_unblock_lock(&file->f_file, fl);
block->b_granted = 0;
+#else // this fix is from Trond
+ if (fl->fl_next)
+ posix_unblock_lock(&file->f_file, fl);
+ if (unlock) {
+ fl->fl_type = F_UNLCK;
+ posix_lock_file(&file->f_file, fl);
+ block->b_granted = 0;
+ }
+#endif

/* If the block is in the middle of a GRANT callback,
* don't kill it yet. */
@@ -259,6 +269,8 @@ nlmsvc_delete_block(struct nlm_block *bl
if (block->b_host)
nlm_release_host(block->b_host);
nlmclnt_freegrantargs(&block->b_call);
+ if (block->b_fl)
+ kfree(block->b_fl);
kfree(block);
}

@@ -286,6 +298,29 @@ nlmsvc_traverse_blocks(struct nlm_host *
}

/*
+ * Deferred lock request handling
+ */
+
+static u32
+nlmsvc_defer_lock_rqst(struct svc_rqst *rqstp, struct nlm_block *block)
+{
+ u32 status = nlm_lck_denied_nolocks;
+
+ block->b_flags |= B_DEFERRED;
+ block->b_done = 1;
+ nlmsvc_insert_block(block, 7 * HZ);
+ block->b_cache_req = &rqstp->rq_chandle;
+ if (rqstp->rq_chandle.defer) {
+ block->b_deferred_req = rqstp->rq_chandle.defer(block->b_cache_req);
+ if (block->b_deferred_req != NULL)
+ status = EINPROGRESS;
+ }
+ dprintk("lockd: nlmsvc_defer_lock_rqst block %p flags %ld status %d\n",
+ block, block->b_flags, status);
+ return status;
+}
+
+/*
* Attempt to establish a lock, and if it can't be granted, block it
* if required.
*/
@@ -295,7 +330,7 @@ nlmsvc_lock(struct svc_rqst *rqstp, stru
{
struct file_lock *conflock;
struct nlm_block *block;
- int error;
+ u32 error;

dprintk("lockd: nlmsvc_lock(%s/%ld, ty=%d, pi=%d, %Ld-%Ld, bl=%d)\n",
file->f_file.f_dentry->d_inode->i_sb->s_id,
@@ -315,11 +350,76 @@ again:
/* Lock file against concurrent access */
down(&file->f_sema);

+ if (block && (block->b_flags & B_DEFERRED)) {
+ if (block->b_flags & B_WAIT) { /* blocking */
+ if (!(block->b_flags & B_GOT_CALLBACK) &&
+ !(block->b_flags & B_TOO_LATE)) {
+ dprintk("lockd: nlmsvc_lock wait block %p flags %ld\n",
+ block, block->b_flags);
+ up(&file->f_sema);
+ return nlm_lck_blocked;
+ }
+ if (block->b_flags & B_GOT_LOCK) {
+ error = nlm_granted;
+ nlmsvc_delete_block(block, 0);
+ }
+ else {
+ nlmsvc_insert_block(block, 30 * HZ);
+ error = nlm_lck_blocked;
+ }
+ dprintk("lockd: nlmsvc_lock wait block %p error %d\n",
+ block, -error);
+ up(&file->f_sema);
+ return error;
+ }
+ else {
+ if (!(block->b_flags & B_GOT_CALLBACK) &&
+ !(block->b_flags & B_TOO_LATE)) {
+ dprintk("lockd: nlmsvc_lock again block %p flags %ld\n",
+ block, block->b_flags);
+ up(&file->f_sema);
+ return EINPROGRESS;
+ }
+ if (block->b_flags & B_GOT_LOCK) {
+ nlmsvc_delete_block(block, 0);
+ error = nlm_granted;
+ }
+ else {
+ nlmsvc_delete_block(block, 1);
+ error = nlm_lck_denied;
+ }
+ dprintk("lockd: nlmsvc_lock deferred block %p error %d\n",
+ block, -error);
+ up(&file->f_sema);
+ return error;
+ }
+ }
if (!(conflock = posix_test_lock(&file->f_file, &lock->fl))) {
- error = posix_lock_file(&file->f_file, &lock->fl);
+ error = vfs_lock_file(&file->f_file, &lock->fl);

- if (block)
+ /* check for callback on non blocking request */
+ dprintk("lockd: vfs_lock_file rc %d block %p wait %d\n",
+ -error, block, wait);
+ if ((block == NULL) && (error == -EINPROGRESS) && !wait) {
+ if (!(block = nlmsvc_create_block(rqstp, file, lock, cookie)))
+ return nlm_lck_denied_nolocks;
+ error = nlmsvc_defer_lock_rqst(rqstp, block);
+ up(&file->f_sema);
+ return error;
+ }
+ if ((block == NULL) && (error == -EINPROGRESS) && wait) {
+ if (!(block = nlmsvc_create_block(rqstp, file, lock, cookie)))
+ return nlm_lck_denied_nolocks;
+ block->b_flags |= B_DEFERRED;
+ block->b_flags |= B_WAIT;
+ block->b_done = 1;
+ nlmsvc_insert_block(block, NLM_NEVER);
+ up(&file->f_sema);
+ return nlm_lck_blocked;
+ }
+ if (block && !(block->b_flags & B_DEFERRED))
nlmsvc_delete_block(block, 0);
+
up(&file->f_sema);

dprintk("lockd: posix_lock_file returned %d\n", -error);
@@ -375,10 +475,13 @@ again:
* Test for presence of a conflicting lock.
*/
u32
-nlmsvc_testlock(struct nlm_file *file, struct nlm_lock *lock,
- struct nlm_lock *conflock)
+nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file,
+ struct nlm_lock *lock, struct nlm_lock *conflock,
+ struct nlm_cookie *cookie)
{
struct file_lock *fl;
+ struct nlm_block *block;
+ u32 error;

dprintk("lockd: nlmsvc_testlock(%s/%ld, ty=%d, %Ld-%Ld)\n",
file->f_file.f_dentry->d_inode->i_sb->s_id,
@@ -387,7 +490,38 @@ nlmsvc_testlock(struct nlm_file *file, s
(long long)lock->fl.fl_start,
(long long)lock->fl.fl_end);

- if ((fl = posix_test_lock(&file->f_file, &lock->fl)) != NULL) {
+ lock->fl.fl_flags |= FL_LOCKD;
+
+ /* Get existing block (in case client is busy-waiting) */
+ block = nlmsvc_lookup_block(file, lock, 0);
+
+ if (block && (block->b_flags & B_DEFERRED)) {
+ if (!(block->b_flags & B_GOT_CALLBACK) &&
+ !(block->b_flags & B_TOO_LATE)) {
+ dprintk("lockd: nlmsvc_testlock block %p flags %ld\n",
+ block, block->b_flags);
+ return EINPROGRESS;
+ }
+ fl = block->b_fl;
+ if (block->b_flags & B_GOT_LOCK && fl != NULL) {
+ dprintk("lockd: nlmsvc_testlock conflicting lock(ty=%d, %Ld-%Ld)\n",
+ fl->fl_type, (long long)fl->fl_start,
+ (long long)fl->fl_end);
+ conflock->caller = "somehost"; /* FIXME */
+ conflock->oh.len = 0; /* don't return OH info */
+ memcpy(&conflock->fl, fl, sizeof(struct file_lock));
+ error = nlm_lck_denied;
+ }
+ else {
+ error = nlm_granted;
+ }
+ nlmsvc_delete_block(block, 0);
+ dprintk("lockd: nlmsvc_testlock deferred block %p error %d\n",
+ block, error);
+ return error;
+ }
+ error = vfs_test_lock(&file->f_file, &lock->fl, &fl);
+ if (error == 0 && fl) {
dprintk("lockd: conflicting lock(ty=%d, %Ld-%Ld)\n",
fl->fl_type, (long long)fl->fl_start,
(long long)fl->fl_end);
@@ -396,7 +530,13 @@ nlmsvc_testlock(struct nlm_file *file, s
conflock->fl = *fl;
return nlm_lck_denied;
}
-
+ if (error == -EINPROGRESS && block == NULL) {
+ if (!(block = nlmsvc_create_block(rqstp, file, lock, cookie)))
+ return nlm_granted;
+ block->b_flags |= B_TEST;
+ error = nlmsvc_defer_lock_rqst(rqstp, block);
+ return error;
+ }
return nlm_granted;
}

@@ -423,7 +563,7 @@ nlmsvc_unlock(struct nlm_file *file, str
nlmsvc_cancel_blocked(file, lock);

lock->fl.fl_type = F_UNLCK;
- error = posix_lock_file(&file->f_file, &lock->fl);
+ error = vfs_lock_file(&file->f_file, &lock->fl);

return (error < 0)? nlm_lck_denied_nolocks : nlm_granted;
}
@@ -478,6 +618,68 @@ nlmsvc_notify_blocked(struct file_lock *
printk(KERN_WARNING "lockd: notification for unknown block!\n");
}

+/*
+ * This is a callback from the filesystem for VFS file lock requests.
+ * It will be used if fl_vfs_callback is defined and the filesystem can not
+ * respond to the request immediately.
+ * For GETLK request it will copy the reply to the nlm_block.
+ * For SETLK or SETLKW request it will get the local posix lock.
+ * In all cases it will move the block to the head of nlm_blocked q where
+ * nlmsvc_retry_blocked() can send back a reply for SETLKW or revisit the
+ * deferred rpc for GETLK and SETLK.
+ */
+static int
+nlmsvc_vfs_lock_callback(struct file_lock *fl, struct file_lock *conf, int result)
+{
+ struct nlm_block **bp, *block;
+ struct nlm_file *file;
+ int rc = 0;
+
+ dprintk("lockd: nlmsvc_vfs_lock_callback for lock %p conf %p result %d\n",
+ fl, conf, result);
+ lock_kernel();
+ for (bp = &nlm_blocked; (block = *bp) != 0; bp = &block->b_next) {
+ if (nlm_compare_locks(&block->b_call.a_args.lock.fl, fl)) {
+ if (block->b_flags & B_DEFERRED) {
+ block->b_flags |= B_GOT_CALLBACK;
+ if (block->b_flags & B_TOO_LATE) {
+ rc = 1;
+ break;
+ }
+ if (block->b_flags & B_TEST) {
+ if (result == EBUSY && conf && conf->fl_type != F_UNLCK) {
+ block->b_fl = (struct file_loc *)
+ kmalloc(sizeof(*block), GFP_KERNEL);
+ if (block->b_fl) {
+ memcpy(block->b_fl, conf,
+ sizeof(struct file_lock));
+ block->b_flags |= B_GOT_LOCK;
+ }
+ }
+ }
+ else {
+ if (result == 0) {
+ file = block->b_file;
+ rc = posix_lock_file(&file->f_file,
+ &block->b_call.a_args.lock.fl);
+ if (rc == 0) {
+ block->b_flags |= B_GOT_LOCK;
+ block->b_granted = 1;
+ }
+ }
+ }
+ nlmsvc_insert_block(block, 0);
+ svc_wake_up(block->b_daemon);
+ break;
+ }
+ }
+ }
+ unlock_kernel();
+ dprintk("lockd: nlmsvc_vfs_lock_callback done block %p flags %ld\n",
+ block, block ? block->b_flags : 0);
+ return rc;
+}
+
static int nlmsvc_same_owner(struct file_lock *fl1, struct file_lock *fl2)
{
return fl1->fl_owner == fl2->fl_owner && fl1->fl_pid == fl2->fl_pid;
@@ -486,6 +688,7 @@ static int nlmsvc_same_owner(struct file
struct lock_manager_operations nlmsvc_lock_operations = {
.fl_compare_owner = nlmsvc_same_owner,
.fl_notify = nlmsvc_notify_blocked,
+ .fl_vfs_callback = nlmsvc_vfs_lock_callback,
};

/*
@@ -537,7 +740,7 @@ nlmsvc_grant_blocked(struct nlm_block *b
* following yields an error, this is most probably due to low
* memory. Retry the lock in a few seconds.
*/
- if ((error = posix_lock_file(&file->f_file, &lock->fl)) < 0) {
+ if ((error = vfs_lock_file(&file->f_file, &lock->fl)) < 0) {
printk(KERN_WARNING "lockd: unexpected error %d in %s!\n",
-error, __FUNCTION__);
nlmsvc_insert_block(block, 10 * HZ);
@@ -669,8 +872,27 @@ nlmsvc_retry_blocked(void)
break;
dprintk("nlmsvc_retry_blocked(%p, when=%ld, done=%d)\n",
block, block->b_when, block->b_done);
- if (block->b_done)
- nlmsvc_delete_block(block, 0);
+ if (block->b_done) {
+ if (block->b_flags & B_DEFERRED) {
+ if (!(block->b_flags & B_GOT_CALLBACK) &&
+ !(block->b_flags & B_WAIT)) {
+ block->b_flags |= B_TOO_LATE;
+ }
+ if (block->b_flags & B_WAIT) {
+ if (block->b_granted)
+ nlmsvc_grant_blocked(block);
+ nlmsvc_delete_block(block, 0);
+ }
+ else {
+ nlmsvc_insert_block(block, NLM_NEVER);
+ dprintk("lockd: nlmsvc_retry_blocked revisit block %p flags %ld\n",
+ block, block->b_flags);
+ block->b_deferred_req->revisit(block->b_deferred_req, 0);
+ }
+ }
+ else
+ nlmsvc_delete_block(block, 0);
+ }
else
nlmsvc_grant_blocked(block);
}
--- /nas/linux-2.6.8+kdb+nfsv4/fs/lockd/svcproc.c 2004-08-17 14:35:33.000000000 -0700
+++ /nas/linux-2.6.8-locks/fs/lockd/svcproc.c 2004-09-08 22:23:17.000000000 -0700
@@ -129,7 +129,9 @@ nlmsvc_proc_test(struct svc_rqst *rqstp,
return rpc_success;

/* Now check for conflicting locks */
- resp->status = cast_status(nlmsvc_testlock(file, &argp->lock, &resp->lock));
+ resp->status = nlmsvc_testlock(rqstp, file, &argp->lock, &resp->lock, &resp->cookie);
+ if (resp->status != EINPROGRESS)
+ resp->status = cast_status(resp->status);

dprintk("lockd: TEST status %d vers %d\n",
ntohl(resp->status), rqstp->rq_vers);
@@ -172,8 +174,9 @@ nlmsvc_proc_lock(struct svc_rqst *rqstp,
#endif

/* Now try to lock the file */
- resp->status = cast_status(nlmsvc_lock(rqstp, file, &argp->lock,
- argp->block, &argp->cookie));
+ resp->status = nlmsvc_lock(rqstp, file, &argp->lock, argp->block, &argp->cookie);
+ if (resp->status != EINPROGRESS)
+ resp->status = cast_status(resp->status);

dprintk("lockd: LOCK status %d\n", ntohl(resp->status));
nlm_release_host(host);
--- /nas/linux-2.6.8+kdb+nfsv4/fs/lockd/svc4proc.c 2004-08-17 14:35:33.000000000 -0700
+++ /nas/linux-2.6.8-locks/fs/lockd/svc4proc.c 2004-09-08 20:20:27.000000000 -0700
@@ -102,7 +102,7 @@ nlm4svc_proc_test(struct svc_rqst *rqstp
return rpc_success;

/* Now check for conflicting locks */
- resp->status = nlmsvc_testlock(file, &argp->lock, &resp->lock);
+ resp->status = nlmsvc_testlock(rqstp, file, &argp->lock, &resp->lock, &resp->cookie);

dprintk("lockd: TEST4 status %d\n", ntohl(resp->status));
nlm_release_host(host);
@@ -144,8 +144,7 @@ nlm4svc_proc_lock(struct svc_rqst *rqstp
#endif

/* Now try to lock the file */
- resp->status = nlmsvc_lock(rqstp, file, &argp->lock,
- argp->block, &argp->cookie);
+ resp->status = nlmsvc_lock(rqstp, file, &argp->lock, argp->block, &argp->cookie);

dprintk("lockd: LOCK status %d\n", ntohl(resp->status));
nlm_release_host(host);
--- /nas/linux-2.6.8+kdb+nfsv4/fs/lockd/svcsubs.c 2004-08-17 14:35:33.000000000 -0700
+++ /nas/linux-2.6.8-locks/fs/lockd/svcsubs.c 2004-08-20 14:47:47.000000000 -0700
@@ -176,7 +176,7 @@ again:
lock.fl_type = F_UNLCK;
lock.fl_start = 0;
lock.fl_end = OFFSET_MAX;
- if (posix_lock_file(&file->f_file, &lock) < 0) {
+ if (vfs_lock_file(&file->f_file, &lock) < 0) {
printk("lockd: unlock failure in %s:%d\n",
__FILE__, __LINE__);
return 1;
--- /nas/linux-2.6.8+kdb+nfsv4/include/linux/fs.h 2004-08-17 14:35:33.000000000 -0700
+++ /nas/linux-2.6.8-locks/include/linux/fs.h 2004-09-10 15:20:57.901554952 -0700
@@ -617,6 +617,7 @@ extern void close_private_file(struct fi
#define FL_LEASE 32 /* lease held on this file */
#define FL_SLEEP 128 /* A blocking lock */
#define FL_NFSD 256 /* lock held by nfsd v4 */
+#define FL_FREE 512 /* file lock should be freed */

/*
* The POSIX file lock owner is determined by
@@ -638,6 +639,7 @@ struct file_lock_operations {
struct lock_manager_operations {
int (*fl_compare_owner)(struct file_lock *, struct file_lock *);
void (*fl_notify)(struct file_lock *); /* unblock callback */
+ int (*fl_vfs_callback)(struct file_lock *, struct file_lock *, int result);
};

/* that will die - we need it for nfs_lock_info */
@@ -697,7 +699,9 @@ extern void locks_remove_flock(struct fi
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 int vfs_lock_file(struct file *, struct file_lock *);
+extern int vfs_test_lock(struct file *, struct file_lock *, struct file_lock **);
+extern int 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 *);
extern int __break_lease(struct inode *inode, unsigned int flags);
--- /nas/linux-2.6.8+kdb+nfsv4/include/linux/lockd/lockd.h 2004-08-17 14:35:33.000000000 -0700
+++ /nas/linux-2.6.8-locks/include/linux/lockd/lockd.h 2004-09-08 17:09:26.000000000 -0700
@@ -119,6 +119,16 @@ struct nlm_block {
unsigned char b_incall; /* doing callback */
unsigned char b_done; /* callback complete */
struct nlm_file * b_file; /* file in question */
+ struct cache_req * b_cache_req; /* deferred request handling */
+ struct file_lock * b_fl; /* set for GETLK */
+ struct cache_deferred_req * b_deferred_req;
+ unsigned long b_flags; /* block flags */
+#define B_DEFERRED 1 /* Deferred lock */
+#define B_GOT_LOCK 2 /* Got deferred lock */
+#define B_TOO_LATE 4 /* Too late for deferred lock */
+#define B_GOT_CALLBACK 8 /* Got filesystem callback */
+#define B_WAIT 16 /* Deferred Blocking lock */
+#define B_TEST 32 /* Deferred Test lock */
};

/*
@@ -174,8 +184,8 @@ int nlmsvc_async_call(struct nlm_rqst
u32 nlmsvc_lock(struct svc_rqst *, struct nlm_file *,
struct nlm_lock *, int, struct nlm_cookie *);
u32 nlmsvc_unlock(struct nlm_file *, struct nlm_lock *);
-u32 nlmsvc_testlock(struct nlm_file *, struct nlm_lock *,
- struct nlm_lock *);
+u32 nlmsvc_testlock(struct svc_rqst *, struct nlm_file *,
+ struct nlm_lock *, struct nlm_lock *, struct nlm_cookie *);
u32 nlmsvc_cancel_blocked(struct nlm_file *, struct nlm_lock *);
unsigned long nlmsvc_retry_blocked(void);
int nlmsvc_traverse_blocks(struct nlm_host *, struct nlm_file *,



-------------------------------------------------------
This SF.Net email is sponsored by: YOU BE THE JUDGE. Be one of 170
Project Admins to receive an Apple iPod Mini FREE for your judgement on
who ports your project to Linux PPC the best. Sponsored by IBM.
Deadline: Sept. 13. Go here: http://sf.net/ppc_contest.php
_______________________________________________
NFS maillist - [email protected]
https://lists.sourceforge.net/lists/listinfo/nfs