2004-12-15 18:22:05

by Marc Eshel

[permalink] [raw]
Subject: [patch] flock/fcntl bug

To fs/locks.c owner

There is a bug in the unlock of posix locks. If there is an flock held on a
file that is being closed an unneeded call is made to the file system to do
an fcntl unlock. In the case of NFS it will be a call to the NFS server
which is expensive. This patch just checks that it is a posix lock before
calling the file system.

Marc.


--- linux-2.6.10-rc2.orig/fs/locks.c 2004-11-14 17:28:31.000000000
-0800
+++ linux-2.6.10-rc2-locks/fs/locks.c 2004-12-15 09:44:25.857512320
-0800
@@ -1846,11 +1962,6 @@ void locks_remove_posix(struct file *fil
lock.fl_ops = NULL;
lock.fl_lmops = NULL;

- if (filp->f_op && filp->f_op->lock != NULL) {
- filp->f_op->lock(filp, F_SETLK, &lock);
- goto out;
- }
-
/* Can't use posix_lock_file here; we need to remove it no matter
* which pid we have.
*/
@@ -1858,6 +1969,11 @@ void locks_remove_posix(struct file *fil
while (*before != NULL) {
struct file_lock *fl = *before;
if (IS_POSIX(fl) && posix_same_owner(fl, &lock)) {
+ if (filp->f_op && filp->f_op->lock != NULL) {
+ unlock_kernel();
+ filp->f_op->lock(filp, F_SETLK, &lock);
+ goto out;
+ }
locks_delete_lock(before);
continue;
}



-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://productguide.itmanagersjournal.com/
_______________________________________________
NFS maillist - [email protected]
https://lists.sourceforge.net/lists/listinfo/nfs


2004-12-15 21:49:30

by Trond Myklebust

[permalink] [raw]
Subject: Re: [patch] flock/fcntl bug

on den 15.12.2004 Klokka 10:15 (-0800) skreiv Marc Eshel:
> To fs/locks.c owner
>
> There is a bug in the unlock of posix locks. If there is an flock held on a
> file that is being closed an unneeded call is made to the file system to do
> an fcntl unlock. In the case of NFS it will be a call to the NFS server
> which is expensive. This patch just checks that it is a posix lock before
> calling the file system.

Hmm... Not sure this is right.

What if the filesystem doesn't use inode->i_flock to bookkeep its locks?
It isn't obliged to do so now...

Cheers,
Trond

--
Trond Myklebust <[email protected]>



-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://productguide.itmanagersjournal.com/
_______________________________________________
NFS maillist - [email protected]
https://lists.sourceforge.net/lists/listinfo/nfs

2004-12-15 22:34:23

by Marc Eshel

[permalink] [raw]
Subject: Re: [patch] flock/fcntl bug



Trond Myklebust wrote on 12/15/2004 01:48:16 PM:

> on den 15.12.2004 Klokka 10:15 (-0800) skreiv Marc Eshel:
> > To fs/locks.c owner
> >
> > There is a bug in the unlock of posix locks. If there is an flock held
on a
> > file that is being closed an unneeded call is made to the file system
to do
> > an fcntl unlock. In the case of NFS it will be a call to the NFS server
> > which is expensive. This patch just checks that it is a posix lock
before
> > calling the file system.

> Hmm... Not sure this is right.

> What if the filesystem doesn't use inode->i_flock to bookkeep its locks?
> It isn't obliged to do so now...

If the filesystem doesn't use inode->i_flock than there will not be a call
to the filesystem anyhow because locks_remove_posix() return immediately if
i_flock is NULL.

In general I believe that if the filesystem doesn't get the local lock on
top of what it needs to do for it own book keeping things will not work.
For example when you kill lockd it need to free all the locks, and it does
it by going through the local lock list and call the filesystem to release
its locks.

I know that we have changed the code to call either the local lock or the
filesystem but it is required that the filesystem call the local lock. The
only reason that we don't make both call to the filesystem and to get the
local call is that it needs to be done atomically and only the filesystem
can make sure that both it state and the local lock are in sync.

Marc.



-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://productguide.itmanagersjournal.com/
_______________________________________________
NFS maillist - [email protected]
https://lists.sourceforge.net/lists/listinfo/nfs

2004-12-15 22:53:35

by Trond Myklebust

[permalink] [raw]
Subject: Re: [patch] flock/fcntl bug

on den 15.12.2004 Klokka 14:34 (-0800) skreiv Marc Eshel:

> If the filesystem doesn't use inode->i_flock than there will not be a call
> to the filesystem anyhow because locks_remove_posix() return immediately if
> i_flock is NULL.

Right. Which may now be a bug...

> In general I believe that if the filesystem doesn't get the local lock on
> top of what it needs to do for it own book keeping things will not work.
> For example when you kill lockd it need to free all the locks, and it does
> it by going through the local lock list and call the filesystem to release
> its locks.

And? The fact that lockd uses inode->i_flock does not mean that the
filesystem has to.

> I know that we have changed the code to call either the local lock or the
> filesystem but it is required that the filesystem call the local lock.

What is the point of forcing it to do that if it can do its own
bookkeeping? Why should the VFS need to care?

The only case where I can see the VFS might want to care is in the case
of mandatory locks. Most Linux filesystems don't support them anyway.

Cheers,
Trond

--
Trond Myklebust <[email protected]>



-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://productguide.itmanagersjournal.com/
_______________________________________________
NFS maillist - [email protected]
https://lists.sourceforge.net/lists/listinfo/nfs

2004-12-15 23:55:30

by Marc Eshel

[permalink] [raw]
Subject: Re: [patch] flock/fcntl bug



Trond Myklebust <[email protected]> wrote on 12/15/2004 02:52:26
PM:

> on den 15.12.2004 Klokka 14:34 (-0800) skreiv Marc Eshel:

> > If the filesystem doesn't use inode->i_flock than there will not be a
call
> > to the filesystem anyhow because locks_remove_posix() return
immediately if
> > i_flock is NULL.

> Right. Which may now be a bug...

So how would you fix it? Call the filesystem to unlock what? If you have no
information on what is locked how can you unlock it, and having an extra
call to the filesystem (that can be remote for NFS) when there is no lock
held is very wasteful.

> > In general I believe that if the filesystem doesn't get the local lock
on
> > top of what it needs to do for it own book keeping things will not
work.
> > For example when you kill lockd it need to free all the locks, and it
does
> > it by going through the local lock list and call the filesystem to
release
> > its locks.

> And? The fact that lockd uses inode->i_flock does not mean that the
> filesystem has to.

That is the only why that lockd knows what to clean up when it is
terminated

> > I know that we have changed the code to call either the local lock or
the
> > filesystem but it is required that the filesystem call the local lock.

> What is the point of forcing it to do that if it can do its own
> bookkeeping? Why should the VFS need to care?

It would be nice if it didn't have to care but the fact is that right now
there is dependency on the lock state to be in the VFS too for correct
operation.

Marc.



-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://productguide.itmanagersjournal.com/
_______________________________________________
NFS maillist - [email protected]
https://lists.sourceforge.net/lists/listinfo/nfs

2004-12-16 00:35:44

by Trond Myklebust

[permalink] [raw]
Subject: Re: [patch] flock/fcntl bug

on den 15.12.2004 Klokka 15:51 (-0800) skreiv Marc Eshel:

> > Right. Which may now be a bug...
>
> So how would you fix it? Call the filesystem to unlock what? If you have no
> information on what is locked how can you unlock it, and having an extra
> call to the filesystem (that can be remote for NFS) when there is no lock
> held is very wasteful.

So please tell me why I should be forced to keep all this information:

struct file_lock {
struct file_lock *fl_next; /* singly linked list for this
inode */ struct list_head fl_link; /* doubly linked list
of all locks */
struct list_head fl_block; /* circular list of blocked
processes */ fl_owner_t fl_owner;
unsigned int fl_pid;
wait_queue_head_t fl_wait;
struct file *fl_file;
unsigned char fl_flags;
unsigned char fl_type;
loff_t fl_start;
loff_t fl_end;

struct fasync_struct * fl_fasync; /* for lease break
notifications */
unsigned long fl_break_time; /* for nonblocking lease breaks
*/

struct file_lock_operations *fl_ops; /* Callbacks for
filesystems */
struct lock_manager_operations *fl_lmops; /* Callbacks for
lockmanagers */
union {
struct nfs_lock_info nfs_fl;
} fl_u;
};

for each and every byte range lock if all I'm interested in is deciding
whether or not one lock held by me exists? A minimum implementation for
that could be done within the filesystem as

struct foo {
fl_owner_t fl_owner;
struct foo *next;
};

If you don't believe me, look at your own patch. AFAICS the above is the
only information you are actually using.

> > And? The fact that lockd uses inode->i_flock does not mean that the
> > filesystem has to.
>
> That is the only why that lockd knows what to clean up when it is
> terminated

No! lockd keeps its own books entirely. It uses the VFS bookkeeping for
convenience, but it in no way relies on the filesystem to use the same
bookkeeping.

> > What is the point of forcing it to do that if it can do its own
> > bookkeeping? Why should the VFS need to care?
>
> It would be nice if it didn't have to care but the fact is that right now
> there is dependency on the lock state to be in the VFS too for correct
> operation.

Then fix the VFS to do the right thing. Move the decision about whether
or not to do an RPC call or whatever into the filesystem where it
belongs.

Cheers,
Trond

--
Trond Myklebust <[email protected]>



-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://productguide.itmanagersjournal.com/
_______________________________________________
NFS maillist - [email protected]
https://lists.sourceforge.net/lists/listinfo/nfs

2004-12-16 02:23:34

by Marc Eshel

[permalink] [raw]
Subject: Re: [patch] flock/fcntl bug



Trond Myklebust <[email protected]> wrote on 12/15/2004 04:34:55
PM:

> > It would be nice if it didn't have to care but the fact is that right
now
> > there is dependency on the lock state to be in the VFS too for correct
> > operation.

> Then fix the VFS to do the right thing. Move the decision about whether
> or not to do an RPC call or whatever into the filesystem where it
> belongs.

I will be glad to. Please add my patch 'locking for cluster filesystem' so
other users can experiment with their favorite file system and give some
feed back. My patch is getting too big and it is a pain to retrofit it to
constantly changing code. It will than be easier to build small patches for
the specific problem that will arise.

Thanks, Marc.



-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://productguide.itmanagersjournal.com/
_______________________________________________
NFS maillist - [email protected]
https://lists.sourceforge.net/lists/listinfo/nfs

2004-12-16 03:44:48

by Trond Myklebust

[permalink] [raw]
Subject: Re: [patch] flock/fcntl bug

on den 15.12.2004 Klokka 18:16 (-0800) skreiv Marc Eshel:

> I will be glad to. Please add my patch 'locking for cluster filesystem' so
> other users can experiment with their favorite file system and give some
> feed back. My patch is getting too big and it is a pain to retrofit it to
> constantly changing code. It will than be easier to build small patches for
> the specific problem that will arise.

I still have issues with it.

- You cannot mix NLM errors and VFS errors in the same variable. They
belong to completely different types.

- Why is vfs_test_and_lock_file() calling vfs_test_lock()? Why can't
vfs_lock_file() just return the conflicting file for you? Means you
do everything in one atomic call down to the filesystem instead of
(at least) two calls and possibly more...

- Why is posix_unblock_lock() suddenly calling filesystem routines via
vfs_lock_file()?

- Why is posix_block_lock() suddenly doing deadlock checking etc
without any of the callers actually looking at the return value?

- vfs_test_and_lock_file() appears to return EAGAIN if the user already
holds the lock (posix_locks_same() is true). Isn't that a bug?

- You cannot use memcpy() in order to copy locks.

- Why is "conflock" being allocated by kmalloc() inside
vfs_test_lock() instead of by the caller? You could avoid the whole
ugly FL_FREE hack. The way it all ends up getting called in
nlmsvc_delete_block() looks very suspicious: it looks to me as if
posix_unblock_lock() is freeing your lock before you've even started.

Cheers,
Trond

-
--
Trond Myklebust <[email protected]>



-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://productguide.itmanagersjournal.com/
_______________________________________________
NFS maillist - [email protected]
https://lists.sourceforge.net/lists/listinfo/nfs

2004-12-16 18:55:58

by Marc Eshel

[permalink] [raw]
Subject: Re: [patch] flock/fcntl bug

Trond Myklebust wrote on 12/15/2004 07:44:04 PM:

> on den 15.12.2004 Klokka 18:16 (-0800) skreiv Marc Eshel:

> > I will be glad to. Please add my patch 'locking for cluster filesystem'
so
> > other users can experiment with their favorite file system and give
some
> > feed back. My patch is getting too big and it is a pain to retrofit it
to
> > constantly changing code. It will than be easier to build small patches
for
> > the specific problem that will arise.

> I still have issues with it.

> - You cannot mix NLM errors and VFS errors in the same variable. They
> belong to completely different types.
>
I added a new NLM error nlm_lck_deferred that will never go back to the
client, but just tell the svc dispatcher to defer the request. If this is
also not appropriate then please give me a specific alternative.

> - Why is vfs_test_and_lock_file() calling vfs_test_lock()? Why can't
> vfs_lock_file() just return the conflicting file for you? Means you
> do everything in one atomic call down to the filesystem instead of
> (at least) two calls and possibly more...
>
I can change vfs_lock_file to return the conflicting lock but it will still
require two calls to the filesystem. Are you suggesting to change the VFS
lock interface down to the filesystem to combine F_SETLK and F_GETLK ?

> - Why is posix_unblock_lock() suddenly calling filesystem routines via
> vfs_lock_file()?
>
This call might not be necessary, I will remove it and do some more
testing.

> - Why is posix_block_lock() suddenly doing deadlock checking etc
> without any of the callers actually looking at the return value?
>
This was part of an older patch not related so I will remove the call.

> - vfs_test_and_lock_file() appears to return EAGAIN if the user already
> holds the lock (posix_locks_same() is true). Isn't that a bug?
>
If posix_locks_same() is true than vfs_test_lock will return 0 which will
be the return code from vfs_test_and_lock_file(). So no, I don't see a bug.

> - You cannot use memcpy() in order to copy locks.
I will change it to locks_copy_lock() if still required after the change
below.

> - Why is "conflock" being allocated by kmalloc() inside
> vfs_test_lock() instead of by the caller? You could avoid the whole
> ugly FL_FREE hack. The way it all ends up getting called in
> nlmsvc_delete_block() looks very suspicious: it looks to me as if
> posix_unblock_lock() is freeing your lock before you've even started.
>
I was trying to save the allocation call when it is not required, but will
change it to do the allocation by the caller.

Marc.



-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://productguide.itmanagersjournal.com/
_______________________________________________
NFS maillist - [email protected]
https://lists.sourceforge.net/lists/listinfo/nfs

2005-01-05 18:33:51

by Marc Eshel

[permalink] [raw]
Subject: [patch] updated locking for cluster filesystem

Hi Trond,

Here is an updated patch for Linux 2.6.10 which I believe addresses the
issues you had with the old one. In general the approach now is to have
complete separation between the local (POSIX) locking and the filesystem
locking. Only one of the two is called and there is no local state for
filesystem locks. The filesystem is responsible for keeping lock state and
cleaning up locks when necessary.

vfs_test_and_lock_file() is now really atomic for the POSIX case, to make
the filesystem locking atomic it will need a change in the interface so for
now there are two calls (test and lock).

Filesystems that want to support NLM locking will have to change to use the
new callback routine (fl_vfs_callback) for both blocking and non-blocking
locks. Since the filesystem needs to distinguish between the blocking and
the non-blocking calls, we are using FL_SLEEP to indicate blocking call. We
did not use SETLKW since it might cause filesystem that are not updated for
the new callback interface to block lockd. This the only point that we are
not completely comfortable with, let me know what you think.

Regards, Marc.


--- /nas/linux-2.6.10-uncompiled/fs/locks.c 2005-01-04
11:09:04.000000000 -0800
+++ /nas/linux-2.6.10-locks/fs/locks.c 2005-01-05 09:07:27.696101464
-0800
@@ -153,7 +153,7 @@ static struct file_lock *locks_alloc_loc
}

/* Free a lock which is not in use. */
-static inline void locks_free_lock(struct file_lock *fl)
+inline void locks_free_lock(struct file_lock *fl)
{
if (fl == NULL) {
BUG();
@@ -183,6 +183,8 @@ static inline void locks_free_lock(struc
kmem_cache_free(filelock_cache, fl);
}

+EXPORT_SYMBOL(locks_free_lock);
+
void locks_init_lock(struct file_lock *fl)
{
INIT_LIST_HEAD(&fl->fl_link);
@@ -656,7 +658,43 @@ 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;
+
+ if (filp->f_op && filp->f_op->lock) {
+ cfl = locks_alloc_lock();
+ if (cfl == NULL)
+ return -ENOLCK;
+ locks_copy_lock(cfl, fl);
+ result = filp->f_op->lock(filp, F_GETLK, cfl);
+ if (!result && cfl->fl_type == F_UNLCK) {
+ locks_free_lock(cfl);
+ cfl = NULL;
+ }
+ }
+ else {
+ lock_kernel();
+ for (cfl = filp->f_dentry->d_inode->i_flock; cfl; cfl =
cfl->fl_next) {
+ if (!IS_POSIX(cfl))
+ continue;
+ if (posix_locks_conflict(cfl, fl))
+ break;
+ }
+ unlock_kernel();
+ }
+ if (cfl) {
+ *conf = cfl;
+ return -EAGAIN;
+ }
+ *conf = NULL;
+ 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,
@@ -755,8 +793,10 @@ out:
}

EXPORT_SYMBOL(posix_lock_file);
+EXPORT_SYMBOL(vfs_lock_file);

-static int __posix_lock_file(struct inode *inode, struct file_lock
*request)
+static int __posix_lock_file(struct inode *inode, struct file_lock
*request,
+ struct file_lock **conflock)
{
struct file_lock *fl;
struct file_lock *new_fl, *new_fl2;
@@ -781,13 +821,18 @@ static int __posix_lock_file(struct inod
if (!posix_locks_conflict(request, fl))
continue;
error = -EAGAIN;
- if (!(request->fl_flags & FL_SLEEP))
+ if (!(request->fl_flags & FL_SLEEP)) {
+ if (conflock)
+ *conflock = fl;
goto out;
+ }
error = -EDEADLK;
if (posix_locks_deadlock(request, fl))
goto out;
error = -EAGAIN;
locks_insert_block(fl, request);
+ if (conflock)
+ *conflock = fl;
goto out;
}
}
@@ -944,8 +989,65 @@ static int __posix_lock_file(struct inod
*/
int posix_lock_file(struct file *filp, struct file_lock *fl)
{
- return __posix_lock_file(filp->f_dentry->d_inode, fl);
+ return __posix_lock_file(filp->f_dentry->d_inode, fl, NULL);
+}
+
+/**
+ * vfs_lock_file - Apply a POSIX-style lock to a file but call the
underlying
+ * filesystem if it provides an interface
+ * @filp: The file to apply the lock to
+ * @fl: The lock to be applied
+ *
+ */
+int vfs_lock_file(struct file *filp, struct file_lock *fl)
+{
+ int error = 0;
+
+ if (filp->f_op && filp->f_op->lock) {
+ error = filp->f_op->lock(filp, F_SETLK, fl);
+ }
+ else
+ error = __posix_lock_file(filp->f_dentry->d_inode, fl, NULL);
+
+ return error;
+}
+
+/*
+ * vfs_test_and_lock_file - Test for an existing lock and acquire it if
available.
+ * @filp: The file to apply the lock to
+ * @fl: The lock to be applied
+ * @conf: The conflicting lock, if no conflict fl_type set to F_UNLCK
+ * Return: 0 if granted, -EAGAIN otherwise
+ *
+ * Only non-blocking locks are handled
+ */
+int vfs_test_and_lock_file(struct file *filp, struct file_lock *fl, struct
file_lock **conf)
+{
+ int error = 0;
+ int count = 0; /* To avoid live deadlock. */
+ int maxtries = 1000;
+
+ if (filp->f_op && filp->f_op->lock) {
+try_again:
+ count++;
+ if (count > maxtries) {
+ printk(KERN_ERR "vfs_test_and_lock_file: EDEADLK filp %p
fl %p\n",
+ filp, fl);
+ return -EDEADLK;
+ }
+ error = filp->f_op->lock(filp, F_SETLK, fl);
+ if (error == -EAGAIN) {
+ error = vfs_test_lock(filp, fl, conf);
+ if (!error && *conf == NULL)
+ goto try_again;
+ }
+ }
+ else
+ error = __posix_lock_file(filp->f_dentry->d_inode, fl, conf);
+
+ return error;
}
+EXPORT_SYMBOL(vfs_test_and_lock_file);

/**
* posix_lock_file_wait - Apply a POSIX-style lock to a file
@@ -961,7 +1063,7 @@ int posix_lock_file_wait(struct file *fi
int error;
might_sleep ();
for (;;) {
- error = __posix_lock_file(filp->f_dentry->d_inode, fl);
+ error = __posix_lock_file(filp->f_dentry->d_inode, fl, NULL);
if ((error != -EAGAIN) || !(fl->fl_flags & FL_SLEEP))
break;
error = wait_event_interruptible(fl->fl_wait, !fl->fl_next);
@@ -1033,7 +1135,7 @@ int locks_mandatory_area(int read_write,
fl.fl_end = offset + count - 1;

for (;;) {
- error = __posix_lock_file(inode, &fl);
+ error = __posix_lock_file(inode, &fl, NULL);
if (error != -EAGAIN)
break;
if (!(fl.fl_flags & FL_SLEEP))
@@ -1661,7 +1763,7 @@ int fcntl_setlk(struct file *filp, unsig
}

for (;;) {
- error = __posix_lock_file(inode, file_lock);
+ error = __posix_lock_file(inode, file_lock, NULL);
if ((error != -EAGAIN) || (cmd == F_SETLK))
break;
error = wait_event_interruptible(file_lock->fl_wait,
@@ -1792,7 +1894,7 @@ int fcntl_setlk64(struct file *filp, uns
}

for (;;) {
- error = __posix_lock_file(inode, file_lock);
+ error = __posix_lock_file(inode, file_lock, NULL);
if ((error != -EAGAIN) || (cmd == F_SETLK64))
break;
error = wait_event_interruptible(file_lock->fl_wait,
@@ -1838,11 +1940,6 @@ void locks_remove_posix(struct file *fil
lock.fl_ops = NULL;
lock.fl_lmops = NULL;

- if (filp->f_op && filp->f_op->lock != NULL) {
- filp->f_op->lock(filp, F_SETLK, &lock);
- goto out;
- }
-
/* Can't use posix_lock_file here; we need to remove it no matter
* which pid we have.
*/
@@ -1856,7 +1953,7 @@ void locks_remove_posix(struct file *fil
before = &fl->fl_next;
}
unlock_kernel();
-out:
+
if (lock.fl_ops && lock.fl_ops->fl_release_private)
lock.fl_ops->fl_release_private(&lock);
}
--- /nas/linux-2.6.10-uncompiled/fs/lockd/svc.c 2005-01-04
11:09:04.000000000 -0800
+++ /nas/linux-2.6.10-locks/fs/lockd/svc.c 2005-01-04
14:14:02.000000000 -0800
@@ -317,6 +317,44 @@ out:
}
EXPORT_SYMBOL(lockd_down);

+int
+nlmsvc_dispatch(struct svc_rqst *rqstp, 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 ==
nlm_lck_deferred) {
+ 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).
*/
@@ -481,12 +519,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
@@ -494,6 +534,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.10-uncompiled/fs/lockd/svc4proc.c 2004-12-24
13:34:31.000000000 -0800
+++ /nas/linux-2.6.10-locks/fs/lockd/svc4proc.c 2005-01-04
14:14:02.000000000 -0800
@@ -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);
--- /nas/linux-2.6.10-uncompiled/fs/lockd/svcproc.c 2004-12-24
13:35:01.000000000 -0800
+++ /nas/linux-2.6.10-locks/fs/lockd/svcproc.c 2005-01-04
14:14:02.000000000 -0800
@@ -37,6 +37,7 @@ cast_to_nlm(u32 status, u32 vers)
case nlm_lck_denied_nolocks:
case nlm_lck_blocked:
case nlm_lck_denied_grace_period:
+ case nlm_lck_deferred:
break;
case nlm4_deadlock:
status = nlm_lck_denied;
@@ -129,7 +130,7 @@ 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 = cast_status(nlmsvc_testlock(rqstp, file, &argp->lock,
&resp->lock, &resp->cookie));

dprintk("lockd: TEST status %d vers %d\n",
ntohl(resp->status), rqstp->rq_vers);
--- /nas/linux-2.6.10-uncompiled/fs/lockd/svclock.c 2004-12-24
13:34:29.000000000 -0800
+++ /nas/linux-2.6.10-locks/fs/lockd/svclock.c 2005-01-04
15:23:01.000000000 -0800
@@ -264,6 +264,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);
}

@@ -291,6 +293,33 @@ nlmsvc_traverse_blocks(struct nlm_host *
}

/*
+ * Deferred lock request handling for non-blocking lock
+ */
+
+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, NLM_TIMEOUT);
+
+ 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 = nlm_lck_deferred;
+ }
+ 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.
*/
@@ -298,9 +327,10 @@ 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 file_lock *conflock = NULL;
struct nlm_block *block;
int error;
+ u32 status;

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,
@@ -320,32 +350,91 @@ again:
/* Lock file against concurrent access */
down(&file->f_sema);

- if (!(conflock = posix_test_lock(file->f_file, &lock->fl))) {
- error = posix_lock_file(file->f_file, &lock->fl);
+ if (block && (block->b_flags & B_DEFERRED)) {
+ dprintk("lockd: nlmsvc_lock deferred block %p flags %ld\n",
+ block, block->b_flags);
+ if (block->b_flags & B_GOT_LOCK) {
+ nlmsvc_delete_block(block, 0);
+ status = nlm_granted;
+ } else {
+ if (block->b_flags & B_TOO_LATE) {
+ nlmsvc_delete_block(block, 1);
+ status = nlm_lck_denied;
+ } else {
+ if (block->b_flags & B_WAIT)
+ status = nlm_lck_blocked;
+ else
+ status = nlm_lck_deferred;
+ }
+ }
+ up(&file->f_sema);
+ return status;
+ }
+
+ if (wait && file->f_file->f_op && file->f_file->f_op->lock) {
+ /* Since we cannot make blocking calls to the filesystem from
lockd,
+ we use FL_SLEEP to indicate a blocking call to distinguish
+ it from a non-blocking call */
+ lock->fl.fl_flags |= FL_SLEEP;
+ error = vfs_lock_file(file->f_file, &lock->fl);
+ }
+ else
+ error = vfs_test_and_lock_file(file->f_file, &lock->fl,
&conflock);
+
+ dprintk("lockd: posix_lock_file returned %d\n", -error);
+
+ if (error == -EINPROGRESS) {
+ /* Filesystem lock operation is in progress
+ Add it to the queue waiting for callback */
+ if (block)
+ BUG();
+ if (!(block = nlmsvc_create_block(rqstp, file, lock,
+ cookie))) {
+ up(&file->f_sema);
+ return nlm_lck_denied_nolocks;
+ }
+ if (wait) {
+ block->b_flags |= (B_DEFERRED | B_WAIT);
+ block->b_done = 1;
+ nlmsvc_insert_block(block, NLM_NEVER);
+ status = nlm_lck_blocked;
+ } else {
+ status = nlmsvc_defer_lock_rqst(rqstp, block);
+ }
+ up(&file->f_sema);
+ return status;
+ }

- if (block)
+ if (error != -EAGAIN) {
+ 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);
switch(-error) {
case 0:
return nlm_granted;
case EDEADLK:
return nlm_deadlock;
- case EAGAIN:
- return nlm_lck_denied;
default: /* includes ENOLCK */
return nlm_lck_denied_nolocks;
}
}
-
+
+ /* If the conflicting lock was returned from the filesystem, the
notification
+ will occur on the callback and we don't need to block on it. Also
we may
+ not block on it because the lock might not exist locally for
distributed
+ filesystems */
+ if (conflock && file->f_file->f_op && file->f_file->f_op->lock) {
+ locks_free_lock(conflock);
+ conflock = NULL;
+ }
if (!wait) {
up(&file->f_sema);
return nlm_lck_denied;
}

- if (posix_locks_deadlock(&lock->fl, conflock)) {
+ if (conflock && posix_locks_deadlock(&lock->fl, conflock)) {
up(&file->f_sema);
return nlm_deadlock;
}
@@ -368,8 +457,9 @@ again:
if (list_empty(&block->b_call.a_args.lock.fl.fl_block)) {
/* Now add block to block list of the conflicting lock
if we haven't done so. */
- dprintk("lockd: blocking on this lock.\n");
- posix_block_lock(conflock, &block->b_call.a_args.lock.fl);
+ dprintk("lockd: blocking on conflock %p\n", conflock);
+ if (conflock)
+ posix_block_lock(conflock,
&block->b_call.a_args.lock.fl);
}

up(&file->f_sema);
@@ -380,10 +470,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 file_lock *conf = NULL;
+ 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,
@@ -392,17 +485,58 @@ 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) {
- dprintk("lockd: 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 */
- conflock->fl = *fl;
- return nlm_lck_denied;
+ 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)) {
+ dprintk("lockd: nlmsvc_testlock deferred block %p flags %ld "
+ "fl %p\n", block, block->b_flags, block->b_fl);
+ if (block->b_flags & B_GOT_LOCK) {
+ if (block->b_fl != NULL) {
+ conflock->fl = *block->b_fl;
+ goto conf_lock;
+ }
+ else {
+ nlmsvc_delete_block(block, 0);
+ return nlm_granted;
+ }
+ } else {
+ if (block->b_flags & B_TOO_LATE) {
+ nlmsvc_delete_block(block, 0);
+ return nlm_lck_denied;
+ } else {
+ return EINPROGRESS;
+ }
+ }
+ }
+
+ error = vfs_test_lock(file->f_file, &lock->fl, &conf);
+ if (conf) {
+ conflock->fl = *conf;
+ if (file->f_file->f_op && file->f_file->f_op->lock)
+ locks_free_lock(conf); /* A filesystem lock */
+ goto conf_lock;
+ }
+ if (error == -EINPROGRESS && block == NULL) {
+ if (!(block = nlmsvc_create_block(rqstp, file, lock, cookie)))
+ return nlm_granted;
+ block->b_flags |= B_TEST;
+ return nlmsvc_defer_lock_rqst(rqstp, block);
}

return nlm_granted;
+
+conf_lock:
+ dprintk("lockd: conflicting lock(ty=%d, %Ld-%Ld)\n",
+ conflock->fl.fl_type, (long long)conflock->fl.fl_start,
+ (long long)conflock->fl.fl_end);
+ conflock->caller = "somehost"; /* FIXME */
+ conflock->oh.len = 0; /* don't return OH info */
+ if (block)
+ nlmsvc_delete_block(block, 0);
+ return nlm_lck_denied;
}

/*
@@ -428,7 +562,8 @@ 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);
+ lock->fl.fl_flags |= FL_LOCKD;
+ error = vfs_lock_file(file->f_file, &lock->fl);

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

+/*
+ * Helper routine that updates a deferred block in response to the
callback
+ * from VFS based on the returned conflock and result.
+ */
+static void
+nlmsvc_update_deferred_block(struct nlm_block *block, struct file_lock
*conf,
+ int result)
+{
+ if (block->b_flags & B_TEST) {
+ if (result == EBUSY && conf && conf->fl_type != F_UNLCK) {
+ block->b_fl = (struct file_lock *)
+ kmalloc(sizeof(*block), GFP_KERNEL);
+ if (block->b_fl) {
+ locks_copy_lock(block->b_fl, conf);
+ block->b_flags |= B_GOT_LOCK;
+ }
+ }
+ } else {
+ if (result == 0) {
+ block->b_flags |= B_GOT_LOCK;
+ block->b_granted = 1;
+ }
+ }
+ nlmsvc_insert_block(block, 0);
+ svc_wake_up(block->b_daemon);
+ return;
+}
+
+/*
+ * 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;
+ 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) {
+ if (block->b_flags & B_TOO_LATE) {
+ rc = 1;
+ break;
+ }
+ nlmsvc_update_deferred_block(block, conf, result);
+ }
+ }
+ }
+ 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;
@@ -491,6 +693,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,
};

/*
@@ -509,7 +712,7 @@ nlmsvc_grant_blocked(struct nlm_block *b
{
struct nlm_file *file = block->b_file;
struct nlm_lock *lock = &block->b_call.a_args.lock;
- struct file_lock *conflock;
+ struct file_lock *conflock = NULL;
int error;

dprintk("lockd: grant blocked lock %p\n", block);
@@ -529,20 +732,23 @@ nlmsvc_grant_blocked(struct nlm_block *b
}

/* Try the lock operation again */
- if ((conflock = posix_test_lock(file->f_file, &lock->fl)) != NULL) {
+ error = vfs_test_and_lock_file(file->f_file, &lock->fl, &conflock);
+ if (conflock) {
/* Bummer, we blocked again */
dprintk("lockd: lock still blocked\n");
nlmsvc_insert_block(block, NLM_NEVER);
- posix_block_lock(conflock, &lock->fl);
+ /* Free filesystem conflicting lock, can not block on it, the
+ filesystem lock might not exist locally. */
+ if (file->f_file->f_op && file->f_file->f_op->lock) {
+ locks_free_lock(conflock);
+ conflock = NULL;
+ }
+ else
+ posix_block_lock(conflock, &lock->fl);
up(&file->f_sema);
return;
}
-
- /* Alright, no conflicting lock. Now lock it for real. If the
- * 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) {
printk(KERN_WARNING "lockd: unexpected error %d in %s!\n",
-error, __FUNCTION__);
nlmsvc_insert_block(block, 10 * HZ);
@@ -654,6 +860,28 @@ nlmsvc_grant_reply(struct svc_rqst *rqst
nlm_release_file(file);
}

+/* Helper function to handle retry of a deferred block.
+ * If it is a blocking lock, call grant_blocked to send a GRANTED_MSG.
+ * For a non-blocking lock, revisit the RPC request.
+ */
+static void
+nlmsvc_retry_deferred_block(struct nlm_block *block)
+{
+ if (!(block->b_flags & B_GOT_LOCK) && !(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_deferred_block revisit block %p "
+ "flags %ld\n", block, block->b_flags);
+ block->b_deferred_req->revisit(block->b_deferred_req, 0);
+ }
+}
+
/*
* Retry all blocked locks that have been notified. This is where lockd
* picks up locks that can be granted, or grant notifications that must
@@ -674,8 +902,12 @@ 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)
+ nlmsvc_retry_deferred_block(block);
+ else
+ nlmsvc_delete_block(block, 0);
+ }
else
nlmsvc_grant_blocked(block);
}
--- /nas/linux-2.6.10-uncompiled/fs/lockd/svcsubs.c 2004-12-24
13:35:01.000000000 -0800
+++ /nas/linux-2.6.10-locks/fs/lockd/svcsubs.c 2005-01-04
14:14:02.000000000 -0800
@@ -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.10-uncompiled/fs/nfsd/nfs4state.c 2005-01-04
11:42:39.000000000 -0800
+++ /nas/linux-2.6.10-locks/fs/nfsd/nfs4state.c 2005-01-04
15:44:24.000000000 -0800
@@ -2672,7 +2672,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struc
struct nfs4_stateid *lock_stp;
struct file *filp;
struct file_lock file_lock;
- struct file_lock *conflock;
+ struct file_lock *conflock = NULL;
int status = 0;
unsigned int strhashval;

@@ -2797,8 +2797,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struc
* Try to lock the file in the VFS.
* Note: locks.c uses the BKL to protect the inode's lock list.
*/
-
- status = posix_lock_file(filp, &file_lock);
+ status = vfs_test_and_lock_file(filp, &file_lock, &conflock);
if (file_lock.fl_ops && file_lock.fl_ops->fl_release_private)
file_lock.fl_ops->fl_release_private(&file_lock);
dprintk("NFSD: nfsd4_lock: posix_lock_file status %d\n",status);
@@ -2819,16 +2818,15 @@ nfsd4_lock(struct svc_rqst *rqstp, struc

conflicting_lock:
dprintk("NFSD: nfsd4_lock: conflicting lock found!\n");
- status = nfserr_denied;
- /* XXX There is a race here. Future patch needed to provide
- * an atomic posix_lock_and_test_file
- */
- if (!(conflock = posix_test_lock(filp, &file_lock))) {
+ if (status != -EAGAIN) {
status = nfserr_serverfault;
goto out;
}
+ status = nfserr_denied;
nfs4_set_lock_denied(conflock, &lock->lk_denied);
-
+ if (filp->f_op && filp->f_op->lock) /* A filesystem lock */
+ locks_free_lock(conflock);
+
out_destroy_new_stateid:
if (lock->lk_is_new) {
dprintk("NFSD: nfsd4_lock: destroy new stateid!\n");
@@ -2857,7 +2855,7 @@ nfsd4_lockt(struct svc_rqst *rqstp, stru
struct inode *inode;
struct file file;
struct file_lock file_lock;
- struct file_lock *conflicting_lock;
+ struct file_lock *conflicting_lock = NULL;
unsigned int strhashval;
int status;

@@ -2927,11 +2925,12 @@ nfsd4_lockt(struct svc_rqst *rqstp, stru
memset(&file, 0, sizeof (struct file));
file.f_dentry = current_fh->fh_dentry;

- status = nfs_ok;
- conflicting_lock = posix_test_lock(&file, &file_lock);
+ status = vfs_test_lock(&file, &file_lock, &conflicting_lock);
if (conflicting_lock) {
status = nfserr_denied;
nfs4_set_lock_denied(conflicting_lock, &lockt->lt_denied);
+ if (file.f_op && file.f_op->lock) /* A filesystem lock */
+ locks_free_lock(conflicting_lock);
}
out:
nfs4_unlock_state();
@@ -2981,7 +2980,7 @@ nfsd4_locku(struct svc_rqst *rqstp, stru
/*
* Try to unlock the file in the VFS.
*/
- status = posix_lock_file(filp, &file_lock);
+ status = vfs_lock_file(filp, &file_lock);
if (file_lock.fl_ops && file_lock.fl_ops->fl_release_private)
file_lock.fl_ops->fl_release_private(&file_lock);
if (status) {
--- /nas/linux-2.6.10-uncompiled/include/linux/fs.h 2005-01-04
11:09:04.000000000 -0800
+++ /nas/linux-2.6.10-locks/include/linux/fs.h 2005-01-04
14:14:02.000000000 -0800
@@ -647,6 +647,7 @@ struct lock_manager_operations {
void (*fl_copy_lock)(struct file_lock *, struct file_lock *);
void (*fl_release_private)(struct file_lock *);
void (*fl_break)(struct file_lock *);
+ int (*fl_vfs_callback)(struct file_lock *, struct file_lock *, int
result);
};

/* that will die - we need it for nfs_lock_info */
@@ -706,6 +707,10 @@ 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 int vfs_lock_file(struct file *, struct file_lock *);
+extern int vfs_test_lock(struct file *, struct file_lock *, struct
file_lock **);
+extern int vfs_test_and_lock_file(struct file *, struct file_lock *,
struct file_lock **);
+extern void locks_free_lock(struct file_lock *fl);
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 *);
--- /nas/linux-2.6.10-uncompiled/include/linux/lockd/lockd.h
2004-12-24 13:34:01.000000000 -0800
+++ /nas/linux-2.6.10-locks/include/linux/lockd/lockd.h 2005-01-04
15:06:17.000000000 -0800
@@ -106,6 +106,8 @@ struct nlm_file {
* couldn't be granted because of a conflicting lock).
*/
#define NLM_NEVER (~(unsigned long) 0)
+#define NLM_TIMEOUT (~(unsigned long) 7 * HZ) /* timeout on
non-blocking call
+ to filesystem */
struct nlm_block {
struct nlm_block * b_next; /* linked list (all blocks) */
struct nlm_block * b_fnext; /* linked list (per file) */
@@ -119,6 +121,15 @@ 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 /* None blocking lock */
+#define B_GOT_LOCK 2 /* Got non-blocking lock */
+#define B_TOO_LATE 4 /* Too late for non-blocking lock */
+#define B_WAIT 16 /* Blocking lock */
+#define B_TEST 32 /* Test lock */
};

/*
@@ -174,8 +185,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 *,
--- /nas/linux-2.6.10-uncompiled/include/linux/lockd/nlm.h 2004-12-24
13:34:30.000000000 -0800
+++ /nas/linux-2.6.10-locks/include/linux/lockd/nlm.h 2005-01-04
14:14:02.000000000 -0800
@@ -29,6 +29,7 @@ enum {
NLM_FBIG = 8,
NLM_FAILED = 9,
#endif
+ NLM_LCK_DEFERRED = 10,
};

#define NLM_PROGRAM 100021
--- /nas/linux-2.6.10-uncompiled/include/linux/lockd/xdr.h 2004-12-24
13:33:48.000000000 -0800
+++ /nas/linux-2.6.10-locks/include/linux/lockd/xdr.h 2005-01-04
14:14:02.000000000 -0800
@@ -21,6 +21,7 @@
#define nlm_lck_denied_nolocks
__constant_htonl(NLM_LCK_DENIED_NOLOCKS)
#define nlm_lck_blocked __constant_htonl(NLM_LCK_BLOCKED)
#define nlm_lck_denied_grace_period
__constant_htonl(NLM_LCK_DENIED_GRACE_PERIOD)
+#define nlm_lck_deferred __constant_htonl(NLM_LCK_DEFERRED)

/* Lock info passed via NLM */
struct nlm_lock {




-------------------------------------------------------
The SF.Net email is sponsored by: Beat the post-holiday blues
Get a FREE limited edition SourceForge.net t-shirt from ThinkGeek.
It's fun and FREE -- well, almost....http://www.thinkgeek.com/sfshirt
_______________________________________________
NFS maillist - [email protected]
https://lists.sourceforge.net/lists/listinfo/nfs