NFSv4: fix delegated locking
authorTrond Myklebust <Trond.Myklebust@netapp.com>
Sun, 11 Apr 2010 20:48:44 +0000 (16:48 -0400)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Mon, 12 Apr 2010 11:55:15 +0000 (07:55 -0400)
Arnaud Giersch reports that NFSv4 locking is broken when we hold a
delegation since commit 8e469ebd6dc32cbaf620e134d79f740bf0ebab79 (NFSv4:
Don't allow posix locking against servers that don't support it).

According to Arnaud, the lock succeeds the first time he opens the file
(since we cannot do a delegated open) but then fails after we start using
delegated opens.

The following patch fixes it by ensuring that locking behaviour is
governed by a per-filesystem capability flag that is initially set, but
gets cleared if the server ever returns an OPEN without the
NFS4_OPEN_RESULT_LOCKTYPE_POSIX flag being set.

Reported-by: Arnaud Giersch <arnaud.giersch@iut-bm.univ-fcomte.fr>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Cc: stable@kernel.org
fs/nfs/client.c
fs/nfs/nfs4proc.c
include/linux/nfs_fs_sb.h

index 2a3d352c0bffdba569e76cc50318a3d619ef3877..a8766c4ef2e09f143b52a69d464b320ad1b5d76d 100644 (file)
@@ -1294,7 +1294,8 @@ static int nfs4_init_server(struct nfs_server *server,
 
        /* Initialise the client representation from the mount data */
        server->flags = data->flags;
-       server->caps |= NFS_CAP_ATOMIC_OPEN|NFS_CAP_CHANGE_ATTR;
+       server->caps |= NFS_CAP_ATOMIC_OPEN|NFS_CAP_CHANGE_ATTR|
+               NFS_CAP_POSIX_LOCK;
        server->options = data->options;
 
        /* Get a client record */
index fe0cd9eb1d4db1680f74ca530118b34ff8b24afd..638067007c65e8010c68f84710d6cc0a1e782158 100644 (file)
@@ -1523,6 +1523,8 @@ static int _nfs4_proc_open(struct nfs4_opendata *data)
                nfs_post_op_update_inode(dir, o_res->dir_attr);
        } else
                nfs_refresh_inode(dir, o_res->dir_attr);
+       if ((o_res->rflags & NFS4_OPEN_RESULT_LOCKTYPE_POSIX) == 0)
+               server->caps &= ~NFS_CAP_POSIX_LOCK;
        if(o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) {
                status = _nfs4_proc_open_confirm(data);
                if (status != 0)
@@ -1664,7 +1666,7 @@ static int _nfs4_do_open(struct inode *dir, struct path *path, fmode_t fmode, in
        status = PTR_ERR(state);
        if (IS_ERR(state))
                goto err_opendata_put;
-       if ((opendata->o_res.rflags & NFS4_OPEN_RESULT_LOCKTYPE_POSIX) != 0)
+       if (server->caps & NFS_CAP_POSIX_LOCK)
                set_bit(NFS_STATE_POSIX_LOCKS, &state->flags);
        nfs4_opendata_put(opendata);
        nfs4_put_state_owner(sp);
index 717a5e54eb1dcf68cdda886b71601e003fec105a..e82957acea561bfb9e4a73f33bbd7faf888cf671 100644 (file)
@@ -176,6 +176,7 @@ struct nfs_server {
 #define NFS_CAP_ATIME          (1U << 11)
 #define NFS_CAP_CTIME          (1U << 12)
 #define NFS_CAP_MTIME          (1U << 13)
+#define NFS_CAP_POSIX_LOCK     (1U << 14)
 
 
 /* maximum number of slots to use */