public inbox for linux-fsdevel@vger.kernel.org
 help / color / mirror / Atom feed
* lockd's interactions with locks.c
@ 2002-08-01  1:28 Matthew Wilcox
  2002-08-02 15:56 ` Trond Myklebust
  0 siblings, 1 reply; 3+ messages in thread
From: Matthew Wilcox @ 2002-08-01  1:28 UTC (permalink / raw)
  To: linux-fsdevel, neilb, nfs-devel, trond.myklebust, okir


There's no-one specifically listed as maintaining lockd, so i'm cc'ing
everyone involved with NFS.

It's clearly a good idea to remove the BKL from the file locking code
-- we have user-provokable O(n^2) behaviour in there; let's limit the
damage to this subsystem.  There are other good cleanups I want to do
that influence this too.

Let's look at the current code in nlmsvc_lock().  We do (paraphrased):

        if (!(conflock = posix_test_lock(&file->f_file, &lock->fl))) {
                error = posix_lock_file(&file->f_file, &lock->fl, 0);
		...
	}

	if (posix_locks_deadlock(&lock->fl, conflock))
		return nlm_deadlock;

	nlmsvc_insert_block(block, NLM_NEVER);
	
	if (list_empty(&block->b_call.a_args.lock.fl.fl_block))
		posix_block_lock(conflock, &block->b_call.a_args.lock.fl);

Now, unless we export a lock from locks.c that lockd can grab around
all this, we're pretty much hosed.  I believe that lockd runs with the
BKL at this point, so there's no race currently.  Here's my preferred
alternative (untested, i want to get comments on the idea):

	if (wait)
		lock->fl.fl_flags |= FL_SLEEP;

 again:
	error = posix_lock_file(&file->f_file, &lock->fl, 0);

	if (!error)
		return 0;
	if (!wait && error != -EAGAIN)
		return error;

	grab_lockd_blocking_lock();
	nlmsvc_insert_block(block, NLM_NEVER);
	have_been_woken_up_already = ...;
	release_lockd_blocking_lock();
	if (have_been_woken_up_already)
		goto again;

	return error;

notice we've now got _one_ call into locks.c instead of 4.  comments?

you can see a modified locks.c (which is also known-buggy) which supports
the FL_SLEEP semantics at
http://ftp.linux.org.uk/pub/linux/willy/patches/flock-2.5.22/flock-A.diff

-- 
Revolutions do not require corporate support.

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: lockd's interactions with locks.c
  2002-08-01  1:28 lockd's interactions with locks.c Matthew Wilcox
@ 2002-08-02 15:56 ` Trond Myklebust
  2002-08-02 17:21   ` Matthew Wilcox
  0 siblings, 1 reply; 3+ messages in thread
From: Trond Myklebust @ 2002-08-02 15:56 UTC (permalink / raw)
  To: Matthew Wilcox; +Cc: linux-fsdevel, neilb, nfs-devel, trond.myklebust, okir

>>>>> " " == Matthew Wilcox <willy@debian.org> writes:

     > There's no-one specifically listed as maintaining lockd, so i'm
     > cc'ing everyone involved with NFS.

<snip>

     > Now, unless we export a lock from locks.c that lockd can grab
     > around all this, we're pretty much hosed.  I believe that lockd
     > runs with the BKL at this point, so there's no race currently.
     > Here's my preferred alternative (untested, i want to get
     > comments on the idea):

I'm not sure I understand how are you are planning on protecting
against races with the blocking code? For instance

     lockd:                                 Another process:

                                            posix_lock_file();
   posix_lock_file();

                                           releases file lock;

  grab_lockd_blocking_lock();
  nlmsvc_insert_block();
  have_been_woken_up_already = ...;
  release_lockd_blocking_lock();


Is this a situation where the mysterious 'have_been_woken_up_already'
kicks in in order to tell lockd not to block after all? If so, how do
you see that part being implemented?

Cheers,
  Trond

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: lockd's interactions with locks.c
  2002-08-02 15:56 ` Trond Myklebust
@ 2002-08-02 17:21   ` Matthew Wilcox
  0 siblings, 0 replies; 3+ messages in thread
From: Matthew Wilcox @ 2002-08-02 17:21 UTC (permalink / raw)
  To: Trond Myklebust; +Cc: Matthew Wilcox, linux-fsdevel, neilb, okir


[nfs-devel trimmed from recipient list as it appears to be an unmaintained
email alias]

On Fri, Aug 02, 2002 at 05:56:49PM +0200, Trond Myklebust wrote:
> I'm not sure I understand how are you are planning on protecting
> against races with the blocking code? For instance
> 
>      lockd:                                 Another process:
> 
>                                             posix_lock_file();
>    posix_lock_file();
> 
>                                            releases file lock;
> 
>   grab_lockd_blocking_lock();
>   nlmsvc_insert_block();
>   have_been_woken_up_already = ...;
>   release_lockd_blocking_lock();
> 
> 
> Is this a situation where the mysterious 'have_been_woken_up_already'
> kicks in in order to tell lockd not to block after all? If so, how do
> you see that part being implemented?

Yes, that's exactly where it kicks in.  I did some hacking on the plane
yesterday and now I think I understand how it should work.  Also, I now
understand that the model I had in mind for posix_lock_file() cannot
work for lockd without a major overhaul (and I don't particularly want
to start hacking on lockd).  So consider the flock-A patch I pointed at
as nothing more than a proof-of-concept.  Anyway... here's what I have:

u32 nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
			struct nlm_lock *lock, int wait,
			struct nlm_cookie *cookie)
{
	struct file_lock	*conflock;
	struct nlm_block	*block;
	int			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,
				file->f_file.f_dentry->d_inode->i_ino,
				lock->fl.fl_type, lock->fl.fl_pid,
				(long long)lock->fl.fl_start,
				(long long)lock->fl.fl_end,
				wait);

	/* Lock file against concurrent access */
	down(&file->f_sema);

	/* Get existing block (in case client is busy-waiting) */
	block = nlmsvc_lookup_block(file, lock, 0);

	lock->fl.fl_flags |= FL_LOCKD;
	if (wait)
		lock->fl.fl_flags |= FL_SLEEP;

	error = posix_lock_file(&file->f_file, &lock->fl);
	if (!error)
		goto out;

	if (!wait || (error != -EAGAIN))
		goto out;

	/* If we don't have a block, create and initialize it. */
	if (!block) {
		dprintk("lockd: blocking on this lock (allocating).\n");
		block = nlmsvc_create_block(rqstp, file, lock, cookie);
		error = -ENOLCK
		if (!block)
			goto out;
	}

	/* Append to list of blocked */
	nlmsvc_insert_block(block, NLM_NEVER);

	/* A wakeup may have come in between returning from posix_lock_file
	 * and nlmsvc_insert_block.  If it has, we have to move the block
	 * to the head of the list and kick lockd to retry the lock.  If a
	 * wakeup comes in between insert_block and the test, we wake up
	 * the daemon twice.  No big deal.
	 */
	if (!block->b_call.a_args.lock.fl.fl_next) {
		nlmsvc_insert_block(block, 0);
		svc_wake_up(block->b_daemon);
	}

	up(&file->f_sema);
	return nlm_lck_blocked;

 out:
	if (block)
		nlmsvc_delete_block(block, 0);
 unlock:
	up(&file->f_sema);
	switch (error) {
	case 0:
		return nlm_granted;
	case -EDEADLK:
		return nlm_deadlock;
	case -EAGAIN:
		return nlm_lck_denied;
	case -ENOLCK:
		return nlm_lck_denied_nolocks;
	}
}

Note I haven't even tried compiling this yet.

-- 
Revolutions do not require corporate support.

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2002-08-02 17:21 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2002-08-01  1:28 lockd's interactions with locks.c Matthew Wilcox
2002-08-02 15:56 ` Trond Myklebust
2002-08-02 17:21   ` Matthew Wilcox

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox