mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-07-23 23:32:14 +00:00
Merge branch 'for-2.6.38' of git://linux-nfs.org/~bfields/linux
* 'for-2.6.38' of git://linux-nfs.org/~bfields/linux: (62 commits) nfsd4: fix callback restarting nfsd: break lease on unlink, link, and rename nfsd4: break lease on nfsd setattr nfsd: don't support msnfs export option nfsd4: initialize cb_per_client nfsd4: allow restarting callbacks nfsd4: simplify nfsd4_cb_prepare nfsd4: give out delegations more quickly in 4.1 case nfsd4: add helper function to run callbacks nfsd4: make sure sequence flags are set after destroy_session nfsd4: re-probe callback on connection loss nfsd4: set sequence flag when backchannel is down nfsd4: keep finer-grained callback status rpc: allow xprt_class->setup to return a preexisting xprt rpc: keep backchannel xprt as long as server connection rpc: move sk_bc_xprt to svc_xprt nfsd4: allow backchannel recovery nfsd4: support BIND_CONN_TO_SESSION nfsd4: modify session list under cl_lock Documentation: fl_mylease no longer exists ... Fix up conflicts in fs/nfsd/vfs.c with the vfs-scale work. The vfs-scale work touched some msnfs cases, and this merge removes support for that entirely, so the conflict was trivial to resolve.
This commit is contained in:
commit
18bce371ae
38 changed files with 608 additions and 383 deletions
59
fs/nfsd/acl.h
Normal file
59
fs/nfsd/acl.h
Normal file
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Common NFSv4 ACL handling definitions.
|
||||
*
|
||||
* Copyright (c) 2002 The Regents of the University of Michigan.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Marius Aamodt Eriksen <marius@umich.edu>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef LINUX_NFS4_ACL_H
|
||||
#define LINUX_NFS4_ACL_H
|
||||
|
||||
#include <linux/posix_acl.h>
|
||||
|
||||
/* Maximum ACL we'll accept from client; chosen (somewhat arbitrarily) to
|
||||
* fit in a page: */
|
||||
#define NFS4_ACL_MAX 170
|
||||
|
||||
struct nfs4_acl *nfs4_acl_new(int);
|
||||
int nfs4_acl_get_whotype(char *, u32);
|
||||
int nfs4_acl_write_who(int who, char *p);
|
||||
int nfs4_acl_permission(struct nfs4_acl *acl, uid_t owner, gid_t group,
|
||||
uid_t who, u32 mask);
|
||||
|
||||
#define NFS4_ACL_TYPE_DEFAULT 0x01
|
||||
#define NFS4_ACL_DIR 0x02
|
||||
#define NFS4_ACL_OWNER 0x04
|
||||
|
||||
struct nfs4_acl *nfs4_acl_posix_to_nfsv4(struct posix_acl *,
|
||||
struct posix_acl *, unsigned int flags);
|
||||
int nfs4_acl_nfsv4_to_posix(struct nfs4_acl *, struct posix_acl **,
|
||||
struct posix_acl **, unsigned int flags);
|
||||
|
||||
#endif /* LINUX_NFS4_ACL_H */
|
|
@ -1,4 +1,3 @@
|
|||
#define MSNFS /* HACK HACK */
|
||||
/*
|
||||
* NFS exporting and validation.
|
||||
*
|
||||
|
@ -1444,9 +1443,6 @@ static struct flags {
|
|||
{ NFSEXP_NOSUBTREECHECK, {"no_subtree_check", ""}},
|
||||
{ NFSEXP_NOAUTHNLM, {"insecure_locks", ""}},
|
||||
{ NFSEXP_V4ROOT, {"v4root", ""}},
|
||||
#ifdef MSNFS
|
||||
{ NFSEXP_MSNFS, {"msnfs", ""}},
|
||||
#endif
|
||||
{ 0, {"", ""}}
|
||||
};
|
||||
|
||||
|
|
62
fs/nfsd/idmap.h
Normal file
62
fs/nfsd/idmap.h
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Mapping of UID to name and vice versa.
|
||||
*
|
||||
* Copyright (c) 2002, 2003 The Regents of the University of
|
||||
* Michigan. All rights reserved.
|
||||
> *
|
||||
* Marius Aamodt Eriksen <marius@umich.edu>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef LINUX_NFSD_IDMAP_H
|
||||
#define LINUX_NFSD_IDMAP_H
|
||||
|
||||
#include <linux/in.h>
|
||||
#include <linux/sunrpc/svc.h>
|
||||
|
||||
/* XXX from linux/nfs_idmap.h */
|
||||
#define IDMAP_NAMESZ 128
|
||||
|
||||
#ifdef CONFIG_NFSD_V4
|
||||
int nfsd_idmap_init(void);
|
||||
void nfsd_idmap_shutdown(void);
|
||||
#else
|
||||
static inline int nfsd_idmap_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline void nfsd_idmap_shutdown(void)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
__be32 nfsd_map_name_to_uid(struct svc_rqst *, const char *, size_t, __u32 *);
|
||||
__be32 nfsd_map_name_to_gid(struct svc_rqst *, const char *, size_t, __u32 *);
|
||||
int nfsd_map_uid_to_name(struct svc_rqst *, __u32, char *);
|
||||
int nfsd_map_gid_to_name(struct svc_rqst *, __u32, char *);
|
||||
|
||||
#endif /* LINUX_NFSD_IDMAP_H */
|
|
@ -151,10 +151,10 @@ nfsd3_proc_read(struct svc_rqst *rqstp, struct nfsd3_readargs *argp,
|
|||
__be32 nfserr;
|
||||
u32 max_blocksize = svc_max_payload(rqstp);
|
||||
|
||||
dprintk("nfsd: READ(3) %s %lu bytes at %lu\n",
|
||||
dprintk("nfsd: READ(3) %s %lu bytes at %Lu\n",
|
||||
SVCFH_fmt(&argp->fh),
|
||||
(unsigned long) argp->count,
|
||||
(unsigned long) argp->offset);
|
||||
(unsigned long long) argp->offset);
|
||||
|
||||
/* Obtain buffer pointer for payload.
|
||||
* 1 (status) + 22 (post_op_attr) + 1 (count) + 1 (eof)
|
||||
|
@ -191,10 +191,10 @@ nfsd3_proc_write(struct svc_rqst *rqstp, struct nfsd3_writeargs *argp,
|
|||
__be32 nfserr;
|
||||
unsigned long cnt = argp->len;
|
||||
|
||||
dprintk("nfsd: WRITE(3) %s %d bytes at %ld%s\n",
|
||||
dprintk("nfsd: WRITE(3) %s %d bytes at %Lu%s\n",
|
||||
SVCFH_fmt(&argp->fh),
|
||||
argp->len,
|
||||
(unsigned long) argp->offset,
|
||||
(unsigned long long) argp->offset,
|
||||
argp->stable? " stable" : "");
|
||||
|
||||
fh_copy(&resp->fh, &argp->fh);
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/nfs_fs.h>
|
||||
#include <linux/nfs4_acl.h>
|
||||
#include "acl.h"
|
||||
|
||||
|
||||
/* mode bit translations: */
|
||||
|
|
|
@ -628,10 +628,8 @@ static int max_cb_time(void)
|
|||
return max(nfsd4_lease/10, (time_t)1) * HZ;
|
||||
}
|
||||
|
||||
/* Reference counting, callback cleanup, etc., all look racy as heck.
|
||||
* And why is cl_cb_set an atomic? */
|
||||
|
||||
int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *conn)
|
||||
static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *conn, struct nfsd4_session *ses)
|
||||
{
|
||||
struct rpc_timeout timeparms = {
|
||||
.to_initval = max_cb_time(),
|
||||
|
@ -641,6 +639,7 @@ int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *conn)
|
|||
.net = &init_net,
|
||||
.address = (struct sockaddr *) &conn->cb_addr,
|
||||
.addrsize = conn->cb_addrlen,
|
||||
.saddress = (struct sockaddr *) &conn->cb_saddr,
|
||||
.timeout = &timeparms,
|
||||
.program = &cb_program,
|
||||
.version = 0,
|
||||
|
@ -657,6 +656,10 @@ int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *conn)
|
|||
args.protocol = XPRT_TRANSPORT_TCP;
|
||||
clp->cl_cb_ident = conn->cb_ident;
|
||||
} else {
|
||||
if (!conn->cb_xprt)
|
||||
return -EINVAL;
|
||||
clp->cl_cb_conn.cb_xprt = conn->cb_xprt;
|
||||
clp->cl_cb_session = ses;
|
||||
args.bc_xprt = conn->cb_xprt;
|
||||
args.prognumber = clp->cl_cb_session->se_cb_prog;
|
||||
args.protocol = XPRT_TRANSPORT_BC_TCP;
|
||||
|
@ -679,14 +682,20 @@ static void warn_no_callback_path(struct nfs4_client *clp, int reason)
|
|||
(int)clp->cl_name.len, clp->cl_name.data, reason);
|
||||
}
|
||||
|
||||
static void nfsd4_mark_cb_down(struct nfs4_client *clp, int reason)
|
||||
{
|
||||
clp->cl_cb_state = NFSD4_CB_DOWN;
|
||||
warn_no_callback_path(clp, reason);
|
||||
}
|
||||
|
||||
static void nfsd4_cb_probe_done(struct rpc_task *task, void *calldata)
|
||||
{
|
||||
struct nfs4_client *clp = container_of(calldata, struct nfs4_client, cl_cb_null);
|
||||
|
||||
if (task->tk_status)
|
||||
warn_no_callback_path(clp, task->tk_status);
|
||||
nfsd4_mark_cb_down(clp, task->tk_status);
|
||||
else
|
||||
atomic_set(&clp->cl_cb_set, 1);
|
||||
clp->cl_cb_state = NFSD4_CB_UP;
|
||||
}
|
||||
|
||||
static const struct rpc_call_ops nfsd4_cb_probe_ops = {
|
||||
|
@ -709,6 +718,11 @@ int set_callback_cred(void)
|
|||
|
||||
static struct workqueue_struct *callback_wq;
|
||||
|
||||
static void run_nfsd4_cb(struct nfsd4_callback *cb)
|
||||
{
|
||||
queue_work(callback_wq, &cb->cb_work);
|
||||
}
|
||||
|
||||
static void do_probe_callback(struct nfs4_client *clp)
|
||||
{
|
||||
struct nfsd4_callback *cb = &clp->cl_cb_null;
|
||||
|
@ -723,7 +737,7 @@ static void do_probe_callback(struct nfs4_client *clp)
|
|||
|
||||
cb->cb_ops = &nfsd4_cb_probe_ops;
|
||||
|
||||
queue_work(callback_wq, &cb->cb_work);
|
||||
run_nfsd4_cb(cb);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -732,14 +746,21 @@ static void do_probe_callback(struct nfs4_client *clp)
|
|||
*/
|
||||
void nfsd4_probe_callback(struct nfs4_client *clp)
|
||||
{
|
||||
/* XXX: atomicity? Also, should we be using cl_cb_flags? */
|
||||
clp->cl_cb_state = NFSD4_CB_UNKNOWN;
|
||||
set_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_cb_flags);
|
||||
do_probe_callback(clp);
|
||||
}
|
||||
|
||||
void nfsd4_probe_callback_sync(struct nfs4_client *clp)
|
||||
{
|
||||
nfsd4_probe_callback(clp);
|
||||
flush_workqueue(callback_wq);
|
||||
}
|
||||
|
||||
void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *conn)
|
||||
{
|
||||
BUG_ON(atomic_read(&clp->cl_cb_set));
|
||||
|
||||
clp->cl_cb_state = NFSD4_CB_UNKNOWN;
|
||||
spin_lock(&clp->cl_lock);
|
||||
memcpy(&clp->cl_cb_conn, conn, sizeof(struct nfs4_cb_conn));
|
||||
spin_unlock(&clp->cl_lock);
|
||||
|
@ -750,24 +771,14 @@ void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *conn)
|
|||
* If the slot is available, then mark it busy. Otherwise, set the
|
||||
* thread for sleeping on the callback RPC wait queue.
|
||||
*/
|
||||
static int nfsd41_cb_setup_sequence(struct nfs4_client *clp,
|
||||
struct rpc_task *task)
|
||||
static bool nfsd41_cb_get_slot(struct nfs4_client *clp, struct rpc_task *task)
|
||||
{
|
||||
u32 *ptr = (u32 *)clp->cl_cb_session->se_sessionid.data;
|
||||
int status = 0;
|
||||
|
||||
dprintk("%s: %u:%u:%u:%u\n", __func__,
|
||||
ptr[0], ptr[1], ptr[2], ptr[3]);
|
||||
|
||||
if (test_and_set_bit(0, &clp->cl_cb_slot_busy) != 0) {
|
||||
rpc_sleep_on(&clp->cl_cb_waitq, task, NULL);
|
||||
dprintk("%s slot is busy\n", __func__);
|
||||
status = -EAGAIN;
|
||||
goto out;
|
||||
return false;
|
||||
}
|
||||
out:
|
||||
dprintk("%s status=%d\n", __func__, status);
|
||||
return status;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -780,20 +791,19 @@ static void nfsd4_cb_prepare(struct rpc_task *task, void *calldata)
|
|||
struct nfs4_delegation *dp = container_of(cb, struct nfs4_delegation, dl_recall);
|
||||
struct nfs4_client *clp = dp->dl_client;
|
||||
u32 minorversion = clp->cl_minorversion;
|
||||
int status = 0;
|
||||
|
||||
cb->cb_minorversion = minorversion;
|
||||
if (minorversion) {
|
||||
status = nfsd41_cb_setup_sequence(clp, task);
|
||||
if (status) {
|
||||
if (status != -EAGAIN) {
|
||||
/* terminate rpc task */
|
||||
task->tk_status = status;
|
||||
task->tk_action = NULL;
|
||||
}
|
||||
if (!nfsd41_cb_get_slot(clp, task))
|
||||
return;
|
||||
}
|
||||
}
|
||||
spin_lock(&clp->cl_lock);
|
||||
if (list_empty(&cb->cb_per_client)) {
|
||||
/* This is the first call, not a restart */
|
||||
cb->cb_done = false;
|
||||
list_add(&cb->cb_per_client, &clp->cl_callbacks);
|
||||
}
|
||||
spin_unlock(&clp->cl_lock);
|
||||
rpc_call_start(task);
|
||||
}
|
||||
|
||||
|
@ -829,15 +839,18 @@ static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata)
|
|||
|
||||
nfsd4_cb_done(task, calldata);
|
||||
|
||||
if (current_rpc_client == NULL) {
|
||||
/* We're shutting down; give up. */
|
||||
/* XXX: err, or is it ok just to fall through
|
||||
* and rpc_restart_call? */
|
||||
if (current_rpc_client != task->tk_client) {
|
||||
/* We're shutting down or changing cl_cb_client; leave
|
||||
* it to nfsd4_process_cb_update to restart the call if
|
||||
* necessary. */
|
||||
return;
|
||||
}
|
||||
|
||||
if (cb->cb_done)
|
||||
return;
|
||||
switch (task->tk_status) {
|
||||
case 0:
|
||||
cb->cb_done = true;
|
||||
return;
|
||||
case -EBADHANDLE:
|
||||
case -NFS4ERR_BAD_STATEID:
|
||||
|
@ -846,32 +859,30 @@ static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata)
|
|||
break;
|
||||
default:
|
||||
/* Network partition? */
|
||||
atomic_set(&clp->cl_cb_set, 0);
|
||||
warn_no_callback_path(clp, task->tk_status);
|
||||
if (current_rpc_client != task->tk_client) {
|
||||
/* queue a callback on the new connection: */
|
||||
atomic_inc(&dp->dl_count);
|
||||
nfsd4_cb_recall(dp);
|
||||
return;
|
||||
}
|
||||
nfsd4_mark_cb_down(clp, task->tk_status);
|
||||
}
|
||||
if (dp->dl_retries--) {
|
||||
rpc_delay(task, 2*HZ);
|
||||
task->tk_status = 0;
|
||||
rpc_restart_call_prepare(task);
|
||||
return;
|
||||
} else {
|
||||
atomic_set(&clp->cl_cb_set, 0);
|
||||
warn_no_callback_path(clp, task->tk_status);
|
||||
}
|
||||
nfsd4_mark_cb_down(clp, task->tk_status);
|
||||
cb->cb_done = true;
|
||||
}
|
||||
|
||||
static void nfsd4_cb_recall_release(void *calldata)
|
||||
{
|
||||
struct nfsd4_callback *cb = calldata;
|
||||
struct nfs4_client *clp = cb->cb_clp;
|
||||
struct nfs4_delegation *dp = container_of(cb, struct nfs4_delegation, dl_recall);
|
||||
|
||||
nfs4_put_delegation(dp);
|
||||
if (cb->cb_done) {
|
||||
spin_lock(&clp->cl_lock);
|
||||
list_del(&cb->cb_per_client);
|
||||
spin_unlock(&clp->cl_lock);
|
||||
nfs4_put_delegation(dp);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct rpc_call_ops nfsd4_cb_recall_ops = {
|
||||
|
@ -906,16 +917,33 @@ void nfsd4_shutdown_callback(struct nfs4_client *clp)
|
|||
flush_workqueue(callback_wq);
|
||||
}
|
||||
|
||||
void nfsd4_release_cb(struct nfsd4_callback *cb)
|
||||
static void nfsd4_release_cb(struct nfsd4_callback *cb)
|
||||
{
|
||||
if (cb->cb_ops->rpc_release)
|
||||
cb->cb_ops->rpc_release(cb);
|
||||
}
|
||||
|
||||
void nfsd4_process_cb_update(struct nfsd4_callback *cb)
|
||||
/* requires cl_lock: */
|
||||
static struct nfsd4_conn * __nfsd4_find_backchannel(struct nfs4_client *clp)
|
||||
{
|
||||
struct nfsd4_session *s;
|
||||
struct nfsd4_conn *c;
|
||||
|
||||
list_for_each_entry(s, &clp->cl_sessions, se_perclnt) {
|
||||
list_for_each_entry(c, &s->se_conns, cn_persession) {
|
||||
if (c->cn_flags & NFS4_CDFC4_BACK)
|
||||
return c;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void nfsd4_process_cb_update(struct nfsd4_callback *cb)
|
||||
{
|
||||
struct nfs4_cb_conn conn;
|
||||
struct nfs4_client *clp = cb->cb_clp;
|
||||
struct nfsd4_session *ses = NULL;
|
||||
struct nfsd4_conn *c;
|
||||
int err;
|
||||
|
||||
/*
|
||||
|
@ -926,6 +954,10 @@ void nfsd4_process_cb_update(struct nfsd4_callback *cb)
|
|||
rpc_shutdown_client(clp->cl_cb_client);
|
||||
clp->cl_cb_client = NULL;
|
||||
}
|
||||
if (clp->cl_cb_conn.cb_xprt) {
|
||||
svc_xprt_put(clp->cl_cb_conn.cb_xprt);
|
||||
clp->cl_cb_conn.cb_xprt = NULL;
|
||||
}
|
||||
if (test_bit(NFSD4_CLIENT_KILL, &clp->cl_cb_flags))
|
||||
return;
|
||||
spin_lock(&clp->cl_lock);
|
||||
|
@ -936,11 +968,22 @@ void nfsd4_process_cb_update(struct nfsd4_callback *cb)
|
|||
BUG_ON(!clp->cl_cb_flags);
|
||||
clear_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_cb_flags);
|
||||
memcpy(&conn, &cb->cb_clp->cl_cb_conn, sizeof(struct nfs4_cb_conn));
|
||||
c = __nfsd4_find_backchannel(clp);
|
||||
if (c) {
|
||||
svc_xprt_get(c->cn_xprt);
|
||||
conn.cb_xprt = c->cn_xprt;
|
||||
ses = c->cn_session;
|
||||
}
|
||||
spin_unlock(&clp->cl_lock);
|
||||
|
||||
err = setup_callback_client(clp, &conn);
|
||||
if (err)
|
||||
err = setup_callback_client(clp, &conn, ses);
|
||||
if (err) {
|
||||
warn_no_callback_path(clp, err);
|
||||
return;
|
||||
}
|
||||
/* Yay, the callback channel's back! Restart any callbacks: */
|
||||
list_for_each_entry(cb, &clp->cl_callbacks, cb_per_client)
|
||||
run_nfsd4_cb(cb);
|
||||
}
|
||||
|
||||
void nfsd4_do_callback_rpc(struct work_struct *w)
|
||||
|
@ -965,10 +1008,11 @@ void nfsd4_do_callback_rpc(struct work_struct *w)
|
|||
void nfsd4_cb_recall(struct nfs4_delegation *dp)
|
||||
{
|
||||
struct nfsd4_callback *cb = &dp->dl_recall;
|
||||
struct nfs4_client *clp = dp->dl_client;
|
||||
|
||||
dp->dl_retries = 1;
|
||||
cb->cb_op = dp;
|
||||
cb->cb_clp = dp->dl_client;
|
||||
cb->cb_clp = clp;
|
||||
cb->cb_msg.rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL];
|
||||
cb->cb_msg.rpc_argp = cb;
|
||||
cb->cb_msg.rpc_resp = cb;
|
||||
|
@ -977,5 +1021,8 @@ void nfsd4_cb_recall(struct nfs4_delegation *dp)
|
|||
cb->cb_ops = &nfsd4_cb_recall_ops;
|
||||
dp->dl_retries = 1;
|
||||
|
||||
queue_work(callback_wq, &dp->dl_recall.cb_work);
|
||||
INIT_LIST_HEAD(&cb->cb_per_client);
|
||||
cb->cb_done = true;
|
||||
|
||||
run_nfsd4_cb(&dp->dl_recall);
|
||||
}
|
||||
|
|
|
@ -33,10 +33,11 @@
|
|||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/nfsd_idmap.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
#include "idmap.h"
|
||||
#include "nfsd.h"
|
||||
|
||||
/*
|
||||
* Cache entry
|
||||
|
@ -514,7 +515,7 @@ rqst_authname(struct svc_rqst *rqstp)
|
|||
return clp->name;
|
||||
}
|
||||
|
||||
static int
|
||||
static __be32
|
||||
idmap_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen,
|
||||
uid_t *id)
|
||||
{
|
||||
|
@ -524,15 +525,15 @@ idmap_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen
|
|||
int ret;
|
||||
|
||||
if (namelen + 1 > sizeof(key.name))
|
||||
return -EINVAL;
|
||||
return nfserr_badowner;
|
||||
memcpy(key.name, name, namelen);
|
||||
key.name[namelen] = '\0';
|
||||
strlcpy(key.authname, rqst_authname(rqstp), sizeof(key.authname));
|
||||
ret = idmap_lookup(rqstp, nametoid_lookup, &key, &nametoid_cache, &item);
|
||||
if (ret == -ENOENT)
|
||||
ret = -ESRCH; /* nfserr_badname */
|
||||
return nfserr_badowner;
|
||||
if (ret)
|
||||
return ret;
|
||||
return nfserrno(ret);
|
||||
*id = item->id;
|
||||
cache_put(&item->h, &nametoid_cache);
|
||||
return 0;
|
||||
|
@ -560,14 +561,14 @@ idmap_id_to_name(struct svc_rqst *rqstp, int type, uid_t id, char *name)
|
|||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
__be32
|
||||
nfsd_map_name_to_uid(struct svc_rqst *rqstp, const char *name, size_t namelen,
|
||||
__u32 *id)
|
||||
{
|
||||
return idmap_name_to_id(rqstp, IDMAP_TYPE_USER, name, namelen, id);
|
||||
}
|
||||
|
||||
int
|
||||
__be32
|
||||
nfsd_map_name_to_gid(struct svc_rqst *rqstp, const char *name, size_t namelen,
|
||||
__u32 *id)
|
||||
{
|
||||
|
|
|
@ -604,9 +604,7 @@ nfsd4_link(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
|||
return status;
|
||||
}
|
||||
|
||||
static __be32
|
||||
nfsd4_lookupp(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
void *arg)
|
||||
static __be32 nfsd4_do_lookupp(struct svc_rqst *rqstp, struct svc_fh *fh)
|
||||
{
|
||||
struct svc_fh tmp_fh;
|
||||
__be32 ret;
|
||||
|
@ -615,13 +613,19 @@ nfsd4_lookupp(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
|||
ret = exp_pseudoroot(rqstp, &tmp_fh);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (tmp_fh.fh_dentry == cstate->current_fh.fh_dentry) {
|
||||
if (tmp_fh.fh_dentry == fh->fh_dentry) {
|
||||
fh_put(&tmp_fh);
|
||||
return nfserr_noent;
|
||||
}
|
||||
fh_put(&tmp_fh);
|
||||
return nfsd_lookup(rqstp, &cstate->current_fh,
|
||||
"..", 2, &cstate->current_fh);
|
||||
return nfsd_lookup(rqstp, fh, "..", 2, fh);
|
||||
}
|
||||
|
||||
static __be32
|
||||
nfsd4_lookupp(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
void *arg)
|
||||
{
|
||||
return nfsd4_do_lookupp(rqstp, &cstate->current_fh);
|
||||
}
|
||||
|
||||
static __be32
|
||||
|
@ -769,9 +773,35 @@ nfsd4_secinfo(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
|||
} else
|
||||
secinfo->si_exp = exp;
|
||||
dput(dentry);
|
||||
if (cstate->minorversion)
|
||||
/* See rfc 5661 section 2.6.3.1.1.8 */
|
||||
fh_put(&cstate->current_fh);
|
||||
return err;
|
||||
}
|
||||
|
||||
static __be32
|
||||
nfsd4_secinfo_no_name(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
struct nfsd4_secinfo_no_name *sin)
|
||||
{
|
||||
__be32 err;
|
||||
|
||||
switch (sin->sin_style) {
|
||||
case NFS4_SECINFO_STYLE4_CURRENT_FH:
|
||||
break;
|
||||
case NFS4_SECINFO_STYLE4_PARENT:
|
||||
err = nfsd4_do_lookupp(rqstp, &cstate->current_fh);
|
||||
if (err)
|
||||
return err;
|
||||
break;
|
||||
default:
|
||||
return nfserr_inval;
|
||||
}
|
||||
exp_get(cstate->current_fh.fh_export);
|
||||
sin->sin_exp = cstate->current_fh.fh_export;
|
||||
fh_put(&cstate->current_fh);
|
||||
return nfs_ok;
|
||||
}
|
||||
|
||||
static __be32
|
||||
nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
struct nfsd4_setattr *setattr)
|
||||
|
@ -974,8 +1004,8 @@ static const char *nfsd4_op_name(unsigned opnum);
|
|||
* Also note, enforced elsewhere:
|
||||
* - SEQUENCE other than as first op results in
|
||||
* NFS4ERR_SEQUENCE_POS. (Enforced in nfsd4_sequence().)
|
||||
* - BIND_CONN_TO_SESSION must be the only op in its compound
|
||||
* (Will be enforced in nfsd4_bind_conn_to_session().)
|
||||
* - BIND_CONN_TO_SESSION must be the only op in its compound.
|
||||
* (Enforced in nfsd4_bind_conn_to_session().)
|
||||
* - DESTROY_SESSION must be the final operation in a compound, if
|
||||
* sessionid's in SEQUENCE and DESTROY_SESSION are the same.
|
||||
* (Enforced in nfsd4_destroy_session().)
|
||||
|
@ -1126,10 +1156,6 @@ encode_op:
|
|||
|
||||
nfsd4_increment_op_stats(op->opnum);
|
||||
}
|
||||
if (!rqstp->rq_usedeferral && status == nfserr_dropit) {
|
||||
dprintk("%s Dropit - send NFS4ERR_DELAY\n", __func__);
|
||||
status = nfserr_jukebox;
|
||||
}
|
||||
|
||||
resp->cstate.status = status;
|
||||
fh_put(&resp->cstate.current_fh);
|
||||
|
@ -1300,6 +1326,11 @@ static struct nfsd4_operation nfsd4_ops[] = {
|
|||
.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP,
|
||||
.op_name = "OP_EXCHANGE_ID",
|
||||
},
|
||||
[OP_BIND_CONN_TO_SESSION] = {
|
||||
.op_func = (nfsd4op_func)nfsd4_bind_conn_to_session,
|
||||
.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP,
|
||||
.op_name = "OP_BIND_CONN_TO_SESSION",
|
||||
},
|
||||
[OP_CREATE_SESSION] = {
|
||||
.op_func = (nfsd4op_func)nfsd4_create_session,
|
||||
.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP,
|
||||
|
@ -1320,6 +1351,10 @@ static struct nfsd4_operation nfsd4_ops[] = {
|
|||
.op_flags = ALLOWED_WITHOUT_FH,
|
||||
.op_name = "OP_RECLAIM_COMPLETE",
|
||||
},
|
||||
[OP_SECINFO_NO_NAME] = {
|
||||
.op_func = (nfsd4op_func)nfsd4_secinfo_no_name,
|
||||
.op_name = "OP_SECINFO_NO_NAME",
|
||||
},
|
||||
};
|
||||
|
||||
static const char *nfsd4_op_name(unsigned opnum)
|
||||
|
|
|
@ -302,7 +302,6 @@ purge_old(struct dentry *parent, struct dentry *child)
|
|||
{
|
||||
int status;
|
||||
|
||||
/* note: we currently use this path only for minorversion 0 */
|
||||
if (nfs4_has_reclaimed_state(child->d_name.name, false))
|
||||
return 0;
|
||||
|
||||
|
|
|
@ -230,7 +230,8 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f
|
|||
dp->dl_client = clp;
|
||||
get_nfs4_file(fp);
|
||||
dp->dl_file = fp;
|
||||
nfs4_file_get_access(fp, O_RDONLY);
|
||||
dp->dl_vfs_file = find_readable_file(fp);
|
||||
get_file(dp->dl_vfs_file);
|
||||
dp->dl_flock = NULL;
|
||||
dp->dl_type = type;
|
||||
dp->dl_stateid.si_boot = boot_time;
|
||||
|
@ -252,6 +253,7 @@ nfs4_put_delegation(struct nfs4_delegation *dp)
|
|||
if (atomic_dec_and_test(&dp->dl_count)) {
|
||||
dprintk("NFSD: freeing dp %p\n",dp);
|
||||
put_nfs4_file(dp->dl_file);
|
||||
fput(dp->dl_vfs_file);
|
||||
kmem_cache_free(deleg_slab, dp);
|
||||
num_delegations--;
|
||||
}
|
||||
|
@ -265,12 +267,10 @@ nfs4_put_delegation(struct nfs4_delegation *dp)
|
|||
static void
|
||||
nfs4_close_delegation(struct nfs4_delegation *dp)
|
||||
{
|
||||
struct file *filp = find_readable_file(dp->dl_file);
|
||||
|
||||
dprintk("NFSD: close_delegation dp %p\n",dp);
|
||||
/* XXX: do we even need this check?: */
|
||||
if (dp->dl_flock)
|
||||
vfs_setlease(filp, F_UNLCK, &dp->dl_flock);
|
||||
nfs4_file_put_access(dp->dl_file, O_RDONLY);
|
||||
vfs_setlease(dp->dl_vfs_file, F_UNLCK, &dp->dl_flock);
|
||||
}
|
||||
|
||||
/* Called under the state lock. */
|
||||
|
@ -642,6 +642,7 @@ static void nfsd4_conn_lost(struct svc_xpt_user *u)
|
|||
free_conn(c);
|
||||
}
|
||||
spin_unlock(&clp->cl_lock);
|
||||
nfsd4_probe_callback(clp);
|
||||
}
|
||||
|
||||
static struct nfsd4_conn *alloc_conn(struct svc_rqst *rqstp, u32 flags)
|
||||
|
@ -679,15 +680,12 @@ static int nfsd4_register_conn(struct nfsd4_conn *conn)
|
|||
return register_xpt_user(conn->cn_xprt, &conn->cn_xpt_user);
|
||||
}
|
||||
|
||||
static __be32 nfsd4_new_conn(struct svc_rqst *rqstp, struct nfsd4_session *ses)
|
||||
static __be32 nfsd4_new_conn(struct svc_rqst *rqstp, struct nfsd4_session *ses, u32 dir)
|
||||
{
|
||||
struct nfsd4_conn *conn;
|
||||
u32 flags = NFS4_CDFC4_FORE;
|
||||
int ret;
|
||||
|
||||
if (ses->se_flags & SESSION4_BACK_CHAN)
|
||||
flags |= NFS4_CDFC4_BACK;
|
||||
conn = alloc_conn(rqstp, flags);
|
||||
conn = alloc_conn(rqstp, dir);
|
||||
if (!conn)
|
||||
return nfserr_jukebox;
|
||||
nfsd4_hash_conn(conn, ses);
|
||||
|
@ -698,6 +696,17 @@ static __be32 nfsd4_new_conn(struct svc_rqst *rqstp, struct nfsd4_session *ses)
|
|||
return nfs_ok;
|
||||
}
|
||||
|
||||
static __be32 nfsd4_new_conn_from_crses(struct svc_rqst *rqstp, struct nfsd4_session *ses)
|
||||
{
|
||||
u32 dir = NFS4_CDFC4_FORE;
|
||||
|
||||
if (ses->se_flags & SESSION4_BACK_CHAN)
|
||||
dir |= NFS4_CDFC4_BACK;
|
||||
|
||||
return nfsd4_new_conn(rqstp, ses, dir);
|
||||
}
|
||||
|
||||
/* must be called under client_lock */
|
||||
static void nfsd4_del_conns(struct nfsd4_session *s)
|
||||
{
|
||||
struct nfs4_client *clp = s->se_client;
|
||||
|
@ -749,6 +758,8 @@ static struct nfsd4_session *alloc_init_session(struct svc_rqst *rqstp, struct n
|
|||
*/
|
||||
slotsize = nfsd4_sanitize_slot_size(fchan->maxresp_cached);
|
||||
numslots = nfsd4_get_drc_mem(slotsize, fchan->maxreqs);
|
||||
if (numslots < 1)
|
||||
return NULL;
|
||||
|
||||
new = alloc_session(slotsize, numslots);
|
||||
if (!new) {
|
||||
|
@ -769,25 +780,30 @@ static struct nfsd4_session *alloc_init_session(struct svc_rqst *rqstp, struct n
|
|||
idx = hash_sessionid(&new->se_sessionid);
|
||||
spin_lock(&client_lock);
|
||||
list_add(&new->se_hash, &sessionid_hashtbl[idx]);
|
||||
spin_lock(&clp->cl_lock);
|
||||
list_add(&new->se_perclnt, &clp->cl_sessions);
|
||||
spin_unlock(&clp->cl_lock);
|
||||
spin_unlock(&client_lock);
|
||||
|
||||
status = nfsd4_new_conn(rqstp, new);
|
||||
status = nfsd4_new_conn_from_crses(rqstp, new);
|
||||
/* whoops: benny points out, status is ignored! (err, or bogus) */
|
||||
if (status) {
|
||||
free_session(&new->se_ref);
|
||||
return NULL;
|
||||
}
|
||||
if (!clp->cl_cb_session && (cses->flags & SESSION4_BACK_CHAN)) {
|
||||
if (cses->flags & SESSION4_BACK_CHAN) {
|
||||
struct sockaddr *sa = svc_addr(rqstp);
|
||||
|
||||
clp->cl_cb_session = new;
|
||||
clp->cl_cb_conn.cb_xprt = rqstp->rq_xprt;
|
||||
svc_xprt_get(rqstp->rq_xprt);
|
||||
/*
|
||||
* This is a little silly; with sessions there's no real
|
||||
* use for the callback address. Use the peer address
|
||||
* as a reasonable default for now, but consider fixing
|
||||
* the rpc client not to require an address in the
|
||||
* future:
|
||||
*/
|
||||
rpc_copy_addr((struct sockaddr *)&clp->cl_cb_conn.cb_addr, sa);
|
||||
clp->cl_cb_conn.cb_addrlen = svc_addr_len(sa);
|
||||
nfsd4_probe_callback(clp);
|
||||
}
|
||||
nfsd4_probe_callback(clp);
|
||||
return new;
|
||||
}
|
||||
|
||||
|
@ -817,7 +833,9 @@ static void
|
|||
unhash_session(struct nfsd4_session *ses)
|
||||
{
|
||||
list_del(&ses->se_hash);
|
||||
spin_lock(&ses->se_client->cl_lock);
|
||||
list_del(&ses->se_perclnt);
|
||||
spin_unlock(&ses->se_client->cl_lock);
|
||||
}
|
||||
|
||||
/* must be called under the client_lock */
|
||||
|
@ -923,8 +941,10 @@ unhash_client_locked(struct nfs4_client *clp)
|
|||
|
||||
mark_client_expired(clp);
|
||||
list_del(&clp->cl_lru);
|
||||
spin_lock(&clp->cl_lock);
|
||||
list_for_each_entry(ses, &clp->cl_sessions, se_perclnt)
|
||||
list_del_init(&ses->se_hash);
|
||||
spin_unlock(&clp->cl_lock);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1051,12 +1071,13 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir,
|
|||
|
||||
memcpy(clp->cl_recdir, recdir, HEXDIR_LEN);
|
||||
atomic_set(&clp->cl_refcount, 0);
|
||||
atomic_set(&clp->cl_cb_set, 0);
|
||||
clp->cl_cb_state = NFSD4_CB_UNKNOWN;
|
||||
INIT_LIST_HEAD(&clp->cl_idhash);
|
||||
INIT_LIST_HEAD(&clp->cl_strhash);
|
||||
INIT_LIST_HEAD(&clp->cl_openowners);
|
||||
INIT_LIST_HEAD(&clp->cl_delegations);
|
||||
INIT_LIST_HEAD(&clp->cl_lru);
|
||||
INIT_LIST_HEAD(&clp->cl_callbacks);
|
||||
spin_lock_init(&clp->cl_lock);
|
||||
INIT_WORK(&clp->cl_cb_null.cb_work, nfsd4_do_callback_rpc);
|
||||
clp->cl_time = get_seconds();
|
||||
|
@ -1132,54 +1153,55 @@ find_unconfirmed_client(clientid_t *clid)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return 1 iff clp's clientid establishment method matches the use_exchange_id
|
||||
* parameter. Matching is based on the fact the at least one of the
|
||||
* EXCHGID4_FLAG_USE_{NON_PNFS,PNFS_MDS,PNFS_DS} flags must be set for v4.1
|
||||
*
|
||||
* FIXME: we need to unify the clientid namespaces for nfsv4.x
|
||||
* and correctly deal with client upgrade/downgrade in EXCHANGE_ID
|
||||
* and SET_CLIENTID{,_CONFIRM}
|
||||
*/
|
||||
static inline int
|
||||
match_clientid_establishment(struct nfs4_client *clp, bool use_exchange_id)
|
||||
static bool clp_used_exchangeid(struct nfs4_client *clp)
|
||||
{
|
||||
bool has_exchange_flags = (clp->cl_exchange_flags != 0);
|
||||
return use_exchange_id == has_exchange_flags;
|
||||
}
|
||||
return clp->cl_exchange_flags != 0;
|
||||
}
|
||||
|
||||
static struct nfs4_client *
|
||||
find_confirmed_client_by_str(const char *dname, unsigned int hashval,
|
||||
bool use_exchange_id)
|
||||
find_confirmed_client_by_str(const char *dname, unsigned int hashval)
|
||||
{
|
||||
struct nfs4_client *clp;
|
||||
|
||||
list_for_each_entry(clp, &conf_str_hashtbl[hashval], cl_strhash) {
|
||||
if (same_name(clp->cl_recdir, dname) &&
|
||||
match_clientid_establishment(clp, use_exchange_id))
|
||||
if (same_name(clp->cl_recdir, dname))
|
||||
return clp;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct nfs4_client *
|
||||
find_unconfirmed_client_by_str(const char *dname, unsigned int hashval,
|
||||
bool use_exchange_id)
|
||||
find_unconfirmed_client_by_str(const char *dname, unsigned int hashval)
|
||||
{
|
||||
struct nfs4_client *clp;
|
||||
|
||||
list_for_each_entry(clp, &unconf_str_hashtbl[hashval], cl_strhash) {
|
||||
if (same_name(clp->cl_recdir, dname) &&
|
||||
match_clientid_establishment(clp, use_exchange_id))
|
||||
if (same_name(clp->cl_recdir, dname))
|
||||
return clp;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void rpc_svcaddr2sockaddr(struct sockaddr *sa, unsigned short family, union svc_addr_u *svcaddr)
|
||||
{
|
||||
switch (family) {
|
||||
case AF_INET:
|
||||
((struct sockaddr_in *)sa)->sin_family = AF_INET;
|
||||
((struct sockaddr_in *)sa)->sin_addr = svcaddr->addr;
|
||||
return;
|
||||
case AF_INET6:
|
||||
((struct sockaddr_in6 *)sa)->sin6_family = AF_INET6;
|
||||
((struct sockaddr_in6 *)sa)->sin6_addr = svcaddr->addr6;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, u32 scopeid)
|
||||
gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfs4_cb_conn *conn = &clp->cl_cb_conn;
|
||||
struct sockaddr *sa = svc_addr(rqstp);
|
||||
u32 scopeid = rpc_get_scope_id(sa);
|
||||
unsigned short expected_family;
|
||||
|
||||
/* Currently, we only support tcp and tcp6 for the callback channel */
|
||||
|
@ -1205,6 +1227,7 @@ gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, u32 scopeid)
|
|||
|
||||
conn->cb_prog = se->se_callback_prog;
|
||||
conn->cb_ident = se->se_callback_ident;
|
||||
rpc_svcaddr2sockaddr((struct sockaddr *)&conn->cb_saddr, expected_family, &rqstp->rq_daddr);
|
||||
return;
|
||||
out_err:
|
||||
conn->cb_addr.ss_family = AF_UNSPEC;
|
||||
|
@ -1344,7 +1367,7 @@ nfsd4_exchange_id(struct svc_rqst *rqstp,
|
|||
case SP4_NONE:
|
||||
break;
|
||||
case SP4_SSV:
|
||||
return nfserr_encr_alg_unsupp;
|
||||
return nfserr_serverfault;
|
||||
default:
|
||||
BUG(); /* checked by xdr code */
|
||||
case SP4_MACH_CRED:
|
||||
|
@ -1361,8 +1384,12 @@ nfsd4_exchange_id(struct svc_rqst *rqstp,
|
|||
nfs4_lock_state();
|
||||
status = nfs_ok;
|
||||
|
||||
conf = find_confirmed_client_by_str(dname, strhashval, true);
|
||||
conf = find_confirmed_client_by_str(dname, strhashval);
|
||||
if (conf) {
|
||||
if (!clp_used_exchangeid(conf)) {
|
||||
status = nfserr_clid_inuse; /* XXX: ? */
|
||||
goto out;
|
||||
}
|
||||
if (!same_verf(&verf, &conf->cl_verifier)) {
|
||||
/* 18.35.4 case 8 */
|
||||
if (exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A) {
|
||||
|
@ -1403,7 +1430,7 @@ nfsd4_exchange_id(struct svc_rqst *rqstp,
|
|||
goto out;
|
||||
}
|
||||
|
||||
unconf = find_unconfirmed_client_by_str(dname, strhashval, true);
|
||||
unconf = find_unconfirmed_client_by_str(dname, strhashval);
|
||||
if (unconf) {
|
||||
/*
|
||||
* Possible retry or client restart. Per 18.35.4 case 4,
|
||||
|
@ -1560,6 +1587,8 @@ nfsd4_create_session(struct svc_rqst *rqstp,
|
|||
status = nfs_ok;
|
||||
memcpy(cr_ses->sessionid.data, new->se_sessionid.data,
|
||||
NFS4_MAX_SESSIONID_LEN);
|
||||
memcpy(&cr_ses->fore_channel, &new->se_fchannel,
|
||||
sizeof(struct nfsd4_channel_attrs));
|
||||
cs_slot->sl_seqid++;
|
||||
cr_ses->seqid = cs_slot->sl_seqid;
|
||||
|
||||
|
@ -1581,6 +1610,45 @@ static bool nfsd4_last_compound_op(struct svc_rqst *rqstp)
|
|||
return argp->opcnt == resp->opcnt;
|
||||
}
|
||||
|
||||
static __be32 nfsd4_map_bcts_dir(u32 *dir)
|
||||
{
|
||||
switch (*dir) {
|
||||
case NFS4_CDFC4_FORE:
|
||||
case NFS4_CDFC4_BACK:
|
||||
return nfs_ok;
|
||||
case NFS4_CDFC4_FORE_OR_BOTH:
|
||||
case NFS4_CDFC4_BACK_OR_BOTH:
|
||||
*dir = NFS4_CDFC4_BOTH;
|
||||
return nfs_ok;
|
||||
};
|
||||
return nfserr_inval;
|
||||
}
|
||||
|
||||
__be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp,
|
||||
struct nfsd4_compound_state *cstate,
|
||||
struct nfsd4_bind_conn_to_session *bcts)
|
||||
{
|
||||
__be32 status;
|
||||
|
||||
if (!nfsd4_last_compound_op(rqstp))
|
||||
return nfserr_not_only_op;
|
||||
spin_lock(&client_lock);
|
||||
cstate->session = find_in_sessionid_hashtbl(&bcts->sessionid);
|
||||
/* Sorta weird: we only need the refcnt'ing because new_conn acquires
|
||||
* client_lock iself: */
|
||||
if (cstate->session) {
|
||||
nfsd4_get_session(cstate->session);
|
||||
atomic_inc(&cstate->session->se_client->cl_refcount);
|
||||
}
|
||||
spin_unlock(&client_lock);
|
||||
if (!cstate->session)
|
||||
return nfserr_badsession;
|
||||
|
||||
status = nfsd4_map_bcts_dir(&bcts->dir);
|
||||
nfsd4_new_conn(rqstp, cstate->session, bcts->dir);
|
||||
return nfs_ok;
|
||||
}
|
||||
|
||||
static bool nfsd4_compound_in_session(struct nfsd4_session *session, struct nfs4_sessionid *sid)
|
||||
{
|
||||
if (!session)
|
||||
|
@ -1619,8 +1687,7 @@ nfsd4_destroy_session(struct svc_rqst *r,
|
|||
spin_unlock(&client_lock);
|
||||
|
||||
nfs4_lock_state();
|
||||
/* wait for callbacks */
|
||||
nfsd4_shutdown_callback(ses->se_client);
|
||||
nfsd4_probe_callback_sync(ses->se_client);
|
||||
nfs4_unlock_state();
|
||||
|
||||
nfsd4_del_conns(ses);
|
||||
|
@ -1733,8 +1800,12 @@ nfsd4_sequence(struct svc_rqst *rqstp,
|
|||
out:
|
||||
/* Hold a session reference until done processing the compound. */
|
||||
if (cstate->session) {
|
||||
struct nfs4_client *clp = session->se_client;
|
||||
|
||||
nfsd4_get_session(cstate->session);
|
||||
atomic_inc(&session->se_client->cl_refcount);
|
||||
atomic_inc(&clp->cl_refcount);
|
||||
if (clp->cl_cb_state == NFSD4_CB_DOWN)
|
||||
seq->status_flags |= SEQ4_STATUS_CB_PATH_DOWN;
|
||||
}
|
||||
kfree(conn);
|
||||
spin_unlock(&client_lock);
|
||||
|
@ -1775,7 +1846,6 @@ __be32
|
|||
nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
struct nfsd4_setclientid *setclid)
|
||||
{
|
||||
struct sockaddr *sa = svc_addr(rqstp);
|
||||
struct xdr_netobj clname = {
|
||||
.len = setclid->se_namelen,
|
||||
.data = setclid->se_name,
|
||||
|
@ -1801,10 +1871,12 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
|||
strhashval = clientstr_hashval(dname);
|
||||
|
||||
nfs4_lock_state();
|
||||
conf = find_confirmed_client_by_str(dname, strhashval, false);
|
||||
conf = find_confirmed_client_by_str(dname, strhashval);
|
||||
if (conf) {
|
||||
/* RFC 3530 14.2.33 CASE 0: */
|
||||
status = nfserr_clid_inuse;
|
||||
if (clp_used_exchangeid(conf))
|
||||
goto out;
|
||||
if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) {
|
||||
char addr_str[INET6_ADDRSTRLEN];
|
||||
rpc_ntop((struct sockaddr *) &conf->cl_addr, addr_str,
|
||||
|
@ -1819,7 +1891,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
|||
* has a description of SETCLIENTID request processing consisting
|
||||
* of 5 bullet points, labeled as CASE0 - CASE4 below.
|
||||
*/
|
||||
unconf = find_unconfirmed_client_by_str(dname, strhashval, false);
|
||||
unconf = find_unconfirmed_client_by_str(dname, strhashval);
|
||||
status = nfserr_resource;
|
||||
if (!conf) {
|
||||
/*
|
||||
|
@ -1876,7 +1948,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
|||
* for consistent minorversion use throughout:
|
||||
*/
|
||||
new->cl_minorversion = 0;
|
||||
gen_callback(new, setclid, rpc_get_scope_id(sa));
|
||||
gen_callback(new, setclid, rqstp);
|
||||
add_to_unconfirmed(new, strhashval);
|
||||
setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot;
|
||||
setclid->se_clientid.cl_id = new->cl_clientid.cl_id;
|
||||
|
@ -1935,7 +2007,6 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
|
|||
if (!same_creds(&conf->cl_cred, &unconf->cl_cred))
|
||||
status = nfserr_clid_inuse;
|
||||
else {
|
||||
atomic_set(&conf->cl_cb_set, 0);
|
||||
nfsd4_change_callback(conf, &unconf->cl_cb_conn);
|
||||
nfsd4_probe_callback(conf);
|
||||
expire_client(unconf);
|
||||
|
@ -1964,7 +2035,7 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
|
|||
unsigned int hash =
|
||||
clientstr_hashval(unconf->cl_recdir);
|
||||
conf = find_confirmed_client_by_str(unconf->cl_recdir,
|
||||
hash, false);
|
||||
hash);
|
||||
if (conf) {
|
||||
nfsd4_remove_clid_dir(conf);
|
||||
expire_client(conf);
|
||||
|
@ -2300,41 +2371,6 @@ void nfsd_break_deleg_cb(struct file_lock *fl)
|
|||
nfsd4_cb_recall(dp);
|
||||
}
|
||||
|
||||
/*
|
||||
* The file_lock is being reapd.
|
||||
*
|
||||
* Called by locks_free_lock() with lock_flocks() held.
|
||||
*/
|
||||
static
|
||||
void nfsd_release_deleg_cb(struct file_lock *fl)
|
||||
{
|
||||
struct nfs4_delegation *dp = (struct nfs4_delegation *)fl->fl_owner;
|
||||
|
||||
dprintk("NFSD nfsd_release_deleg_cb: fl %p dp %p dl_count %d\n", fl,dp, atomic_read(&dp->dl_count));
|
||||
|
||||
if (!(fl->fl_flags & FL_LEASE) || !dp)
|
||||
return;
|
||||
dp->dl_flock = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Called from setlease() with lock_flocks() held
|
||||
*/
|
||||
static
|
||||
int nfsd_same_client_deleg_cb(struct file_lock *onlist, struct file_lock *try)
|
||||
{
|
||||
struct nfs4_delegation *onlistd =
|
||||
(struct nfs4_delegation *)onlist->fl_owner;
|
||||
struct nfs4_delegation *tryd =
|
||||
(struct nfs4_delegation *)try->fl_owner;
|
||||
|
||||
if (onlist->fl_lmops != try->fl_lmops)
|
||||
return 0;
|
||||
|
||||
return onlistd->dl_client == tryd->dl_client;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
int nfsd_change_deleg_cb(struct file_lock **onlist, int arg)
|
||||
{
|
||||
|
@ -2346,8 +2382,6 @@ int nfsd_change_deleg_cb(struct file_lock **onlist, int arg)
|
|||
|
||||
static const struct lock_manager_operations nfsd_lease_mng_ops = {
|
||||
.fl_break = nfsd_break_deleg_cb,
|
||||
.fl_release_private = nfsd_release_deleg_cb,
|
||||
.fl_mylease = nfsd_same_client_deleg_cb,
|
||||
.fl_change = nfsd_change_deleg_cb,
|
||||
};
|
||||
|
||||
|
@ -2514,8 +2548,6 @@ static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file
|
|||
if (!fp->fi_fds[oflag]) {
|
||||
status = nfsd_open(rqstp, cur_fh, S_IFREG, access,
|
||||
&fp->fi_fds[oflag]);
|
||||
if (status == nfserr_dropit)
|
||||
status = nfserr_jukebox;
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
|
@ -2596,6 +2628,19 @@ nfs4_set_claim_prev(struct nfsd4_open *open)
|
|||
open->op_stateowner->so_client->cl_firststate = 1;
|
||||
}
|
||||
|
||||
/* Should we give out recallable state?: */
|
||||
static bool nfsd4_cb_channel_good(struct nfs4_client *clp)
|
||||
{
|
||||
if (clp->cl_cb_state == NFSD4_CB_UP)
|
||||
return true;
|
||||
/*
|
||||
* In the sessions case, since we don't have to establish a
|
||||
* separate connection for callbacks, we assume it's OK
|
||||
* until we hear otherwise:
|
||||
*/
|
||||
return clp->cl_minorversion && clp->cl_cb_state == NFSD4_CB_UNKNOWN;
|
||||
}
|
||||
|
||||
/*
|
||||
* Attempt to hand out a delegation.
|
||||
*/
|
||||
|
@ -2604,10 +2649,11 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta
|
|||
{
|
||||
struct nfs4_delegation *dp;
|
||||
struct nfs4_stateowner *sop = stp->st_stateowner;
|
||||
int cb_up = atomic_read(&sop->so_client->cl_cb_set);
|
||||
int cb_up;
|
||||
struct file_lock *fl;
|
||||
int status, flag = 0;
|
||||
|
||||
cb_up = nfsd4_cb_channel_good(sop->so_client);
|
||||
flag = NFS4_OPEN_DELEGATE_NONE;
|
||||
open->op_recall = 0;
|
||||
switch (open->op_claim_type) {
|
||||
|
@ -2655,7 +2701,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta
|
|||
dp->dl_flock = fl;
|
||||
|
||||
/* vfs_setlease checks to see if delegation should be handed out.
|
||||
* the lock_manager callbacks fl_mylease and fl_change are used
|
||||
* the lock_manager callback fl_change is used
|
||||
*/
|
||||
if ((status = vfs_setlease(fl->fl_file, fl->fl_type, &fl))) {
|
||||
dprintk("NFSD: setlease failed [%d], no delegation\n", status);
|
||||
|
@ -2794,7 +2840,7 @@ nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
|||
renew_client(clp);
|
||||
status = nfserr_cb_path_down;
|
||||
if (!list_empty(&clp->cl_delegations)
|
||||
&& !atomic_read(&clp->cl_cb_set))
|
||||
&& clp->cl_cb_state != NFSD4_CB_UP)
|
||||
goto out;
|
||||
status = nfs_ok;
|
||||
out:
|
||||
|
@ -3081,9 +3127,10 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate,
|
|||
if (status)
|
||||
goto out;
|
||||
renew_client(dp->dl_client);
|
||||
if (filpp)
|
||||
if (filpp) {
|
||||
*filpp = find_readable_file(dp->dl_file);
|
||||
BUG_ON(!*filpp);
|
||||
BUG_ON(!*filpp);
|
||||
}
|
||||
} else { /* open or lock stateid */
|
||||
stp = find_stateid(stateid, flags);
|
||||
if (!stp)
|
||||
|
@ -4107,7 +4154,7 @@ nfs4_has_reclaimed_state(const char *name, bool use_exchange_id)
|
|||
unsigned int strhashval = clientstr_hashval(name);
|
||||
struct nfs4_client *clp;
|
||||
|
||||
clp = find_confirmed_client_by_str(name, strhashval, use_exchange_id);
|
||||
clp = find_confirmed_client_by_str(name, strhashval);
|
||||
return clp ? 1 : 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -44,13 +44,14 @@
|
|||
#include <linux/namei.h>
|
||||
#include <linux/statfs.h>
|
||||
#include <linux/utsname.h>
|
||||
#include <linux/nfsd_idmap.h>
|
||||
#include <linux/nfs4_acl.h>
|
||||
#include <linux/sunrpc/svcauth_gss.h>
|
||||
|
||||
#include "idmap.h"
|
||||
#include "acl.h"
|
||||
#include "xdr4.h"
|
||||
#include "vfs.h"
|
||||
|
||||
|
||||
#define NFSDDBG_FACILITY NFSDDBG_XDR
|
||||
|
||||
/*
|
||||
|
@ -288,17 +289,17 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval,
|
|||
len += XDR_QUADLEN(dummy32) << 2;
|
||||
READMEM(buf, dummy32);
|
||||
ace->whotype = nfs4_acl_get_whotype(buf, dummy32);
|
||||
host_err = 0;
|
||||
status = nfs_ok;
|
||||
if (ace->whotype != NFS4_ACL_WHO_NAMED)
|
||||
ace->who = 0;
|
||||
else if (ace->flag & NFS4_ACE_IDENTIFIER_GROUP)
|
||||
host_err = nfsd_map_name_to_gid(argp->rqstp,
|
||||
status = nfsd_map_name_to_gid(argp->rqstp,
|
||||
buf, dummy32, &ace->who);
|
||||
else
|
||||
host_err = nfsd_map_name_to_uid(argp->rqstp,
|
||||
status = nfsd_map_name_to_uid(argp->rqstp,
|
||||
buf, dummy32, &ace->who);
|
||||
if (host_err)
|
||||
goto out_nfserr;
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
} else
|
||||
*acl = NULL;
|
||||
|
@ -420,6 +421,21 @@ nfsd4_decode_access(struct nfsd4_compoundargs *argp, struct nfsd4_access *access
|
|||
DECODE_TAIL;
|
||||
}
|
||||
|
||||
static __be32 nfsd4_decode_bind_conn_to_session(struct nfsd4_compoundargs *argp, struct nfsd4_bind_conn_to_session *bcts)
|
||||
{
|
||||
DECODE_HEAD;
|
||||
u32 dummy;
|
||||
|
||||
READ_BUF(NFS4_MAX_SESSIONID_LEN + 8);
|
||||
COPYMEM(bcts->sessionid.data, NFS4_MAX_SESSIONID_LEN);
|
||||
READ32(bcts->dir);
|
||||
/* XXX: Perhaps Tom Tucker could help us figure out how we
|
||||
* should be using ctsa_use_conn_in_rdma_mode: */
|
||||
READ32(dummy);
|
||||
|
||||
DECODE_TAIL;
|
||||
}
|
||||
|
||||
static __be32
|
||||
nfsd4_decode_close(struct nfsd4_compoundargs *argp, struct nfsd4_close *close)
|
||||
{
|
||||
|
@ -846,6 +862,17 @@ nfsd4_decode_secinfo(struct nfsd4_compoundargs *argp,
|
|||
DECODE_TAIL;
|
||||
}
|
||||
|
||||
static __be32
|
||||
nfsd4_decode_secinfo_no_name(struct nfsd4_compoundargs *argp,
|
||||
struct nfsd4_secinfo_no_name *sin)
|
||||
{
|
||||
DECODE_HEAD;
|
||||
|
||||
READ_BUF(4);
|
||||
READ32(sin->sin_style);
|
||||
DECODE_TAIL;
|
||||
}
|
||||
|
||||
static __be32
|
||||
nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *setattr)
|
||||
{
|
||||
|
@ -1005,7 +1032,7 @@ static __be32
|
|||
nfsd4_decode_exchange_id(struct nfsd4_compoundargs *argp,
|
||||
struct nfsd4_exchange_id *exid)
|
||||
{
|
||||
int dummy;
|
||||
int dummy, tmp;
|
||||
DECODE_HEAD;
|
||||
|
||||
READ_BUF(NFS4_VERIFIER_SIZE);
|
||||
|
@ -1053,15 +1080,23 @@ nfsd4_decode_exchange_id(struct nfsd4_compoundargs *argp,
|
|||
|
||||
/* ssp_hash_algs<> */
|
||||
READ_BUF(4);
|
||||
READ32(dummy);
|
||||
READ_BUF(dummy);
|
||||
p += XDR_QUADLEN(dummy);
|
||||
READ32(tmp);
|
||||
while (tmp--) {
|
||||
READ_BUF(4);
|
||||
READ32(dummy);
|
||||
READ_BUF(dummy);
|
||||
p += XDR_QUADLEN(dummy);
|
||||
}
|
||||
|
||||
/* ssp_encr_algs<> */
|
||||
READ_BUF(4);
|
||||
READ32(dummy);
|
||||
READ_BUF(dummy);
|
||||
p += XDR_QUADLEN(dummy);
|
||||
READ32(tmp);
|
||||
while (tmp--) {
|
||||
READ_BUF(4);
|
||||
READ32(dummy);
|
||||
READ_BUF(dummy);
|
||||
p += XDR_QUADLEN(dummy);
|
||||
}
|
||||
|
||||
/* ssp_window and ssp_num_gss_handles */
|
||||
READ_BUF(8);
|
||||
|
@ -1339,7 +1374,7 @@ static nfsd4_dec nfsd41_dec_ops[] = {
|
|||
|
||||
/* new operations for NFSv4.1 */
|
||||
[OP_BACKCHANNEL_CTL] = (nfsd4_dec)nfsd4_decode_notsupp,
|
||||
[OP_BIND_CONN_TO_SESSION]= (nfsd4_dec)nfsd4_decode_notsupp,
|
||||
[OP_BIND_CONN_TO_SESSION]= (nfsd4_dec)nfsd4_decode_bind_conn_to_session,
|
||||
[OP_EXCHANGE_ID] = (nfsd4_dec)nfsd4_decode_exchange_id,
|
||||
[OP_CREATE_SESSION] = (nfsd4_dec)nfsd4_decode_create_session,
|
||||
[OP_DESTROY_SESSION] = (nfsd4_dec)nfsd4_decode_destroy_session,
|
||||
|
@ -1350,7 +1385,7 @@ static nfsd4_dec nfsd41_dec_ops[] = {
|
|||
[OP_LAYOUTCOMMIT] = (nfsd4_dec)nfsd4_decode_notsupp,
|
||||
[OP_LAYOUTGET] = (nfsd4_dec)nfsd4_decode_notsupp,
|
||||
[OP_LAYOUTRETURN] = (nfsd4_dec)nfsd4_decode_notsupp,
|
||||
[OP_SECINFO_NO_NAME] = (nfsd4_dec)nfsd4_decode_notsupp,
|
||||
[OP_SECINFO_NO_NAME] = (nfsd4_dec)nfsd4_decode_secinfo_no_name,
|
||||
[OP_SEQUENCE] = (nfsd4_dec)nfsd4_decode_sequence,
|
||||
[OP_SET_SSV] = (nfsd4_dec)nfsd4_decode_notsupp,
|
||||
[OP_TEST_STATEID] = (nfsd4_dec)nfsd4_decode_notsupp,
|
||||
|
@ -2309,8 +2344,6 @@ nfsd4_encode_dirent(void *ccdv, const char *name, int namlen,
|
|||
case nfserr_resource:
|
||||
nfserr = nfserr_toosmall;
|
||||
goto fail;
|
||||
case nfserr_dropit:
|
||||
goto fail;
|
||||
case nfserr_noent:
|
||||
goto skip_entry;
|
||||
default:
|
||||
|
@ -2365,6 +2398,21 @@ nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_
|
|||
return nfserr;
|
||||
}
|
||||
|
||||
static __be32 nfsd4_encode_bind_conn_to_session(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_bind_conn_to_session *bcts)
|
||||
{
|
||||
__be32 *p;
|
||||
|
||||
if (!nfserr) {
|
||||
RESERVE_SPACE(NFS4_MAX_SESSIONID_LEN + 8);
|
||||
WRITEMEM(bcts->sessionid.data, NFS4_MAX_SESSIONID_LEN);
|
||||
WRITE32(bcts->dir);
|
||||
/* XXX: ? */
|
||||
WRITE32(0);
|
||||
ADJUST_ARGS();
|
||||
}
|
||||
return nfserr;
|
||||
}
|
||||
|
||||
static __be32
|
||||
nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_close *close)
|
||||
{
|
||||
|
@ -2826,11 +2874,10 @@ nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_
|
|||
}
|
||||
|
||||
static __be32
|
||||
nfsd4_encode_secinfo(struct nfsd4_compoundres *resp, __be32 nfserr,
|
||||
struct nfsd4_secinfo *secinfo)
|
||||
nfsd4_do_encode_secinfo(struct nfsd4_compoundres *resp,
|
||||
__be32 nfserr,struct svc_export *exp)
|
||||
{
|
||||
int i = 0;
|
||||
struct svc_export *exp = secinfo->si_exp;
|
||||
u32 nflavs;
|
||||
struct exp_flavor_info *flavs;
|
||||
struct exp_flavor_info def_flavs[2];
|
||||
|
@ -2892,6 +2939,20 @@ out:
|
|||
return nfserr;
|
||||
}
|
||||
|
||||
static __be32
|
||||
nfsd4_encode_secinfo(struct nfsd4_compoundres *resp, __be32 nfserr,
|
||||
struct nfsd4_secinfo *secinfo)
|
||||
{
|
||||
return nfsd4_do_encode_secinfo(resp, nfserr, secinfo->si_exp);
|
||||
}
|
||||
|
||||
static __be32
|
||||
nfsd4_encode_secinfo_no_name(struct nfsd4_compoundres *resp, __be32 nfserr,
|
||||
struct nfsd4_secinfo_no_name *secinfo)
|
||||
{
|
||||
return nfsd4_do_encode_secinfo(resp, nfserr, secinfo->sin_exp);
|
||||
}
|
||||
|
||||
/*
|
||||
* The SETATTR encode routine is special -- it always encodes a bitmap,
|
||||
* regardless of the error status.
|
||||
|
@ -3076,13 +3137,9 @@ nfsd4_encode_sequence(struct nfsd4_compoundres *resp, int nfserr,
|
|||
WRITE32(seq->seqid);
|
||||
WRITE32(seq->slotid);
|
||||
WRITE32(seq->maxslots);
|
||||
/*
|
||||
* FIXME: for now:
|
||||
* target_maxslots = maxslots
|
||||
* status_flags = 0
|
||||
*/
|
||||
/* For now: target_maxslots = maxslots */
|
||||
WRITE32(seq->maxslots);
|
||||
WRITE32(0);
|
||||
WRITE32(seq->status_flags);
|
||||
|
||||
ADJUST_ARGS();
|
||||
resp->cstate.datap = p; /* DRC cache data pointer */
|
||||
|
@ -3143,7 +3200,7 @@ static nfsd4_enc nfsd4_enc_ops[] = {
|
|||
|
||||
/* NFSv4.1 operations */
|
||||
[OP_BACKCHANNEL_CTL] = (nfsd4_enc)nfsd4_encode_noop,
|
||||
[OP_BIND_CONN_TO_SESSION] = (nfsd4_enc)nfsd4_encode_noop,
|
||||
[OP_BIND_CONN_TO_SESSION] = (nfsd4_enc)nfsd4_encode_bind_conn_to_session,
|
||||
[OP_EXCHANGE_ID] = (nfsd4_enc)nfsd4_encode_exchange_id,
|
||||
[OP_CREATE_SESSION] = (nfsd4_enc)nfsd4_encode_create_session,
|
||||
[OP_DESTROY_SESSION] = (nfsd4_enc)nfsd4_encode_destroy_session,
|
||||
|
@ -3154,7 +3211,7 @@ static nfsd4_enc nfsd4_enc_ops[] = {
|
|||
[OP_LAYOUTCOMMIT] = (nfsd4_enc)nfsd4_encode_noop,
|
||||
[OP_LAYOUTGET] = (nfsd4_enc)nfsd4_encode_noop,
|
||||
[OP_LAYOUTRETURN] = (nfsd4_enc)nfsd4_encode_noop,
|
||||
[OP_SECINFO_NO_NAME] = (nfsd4_enc)nfsd4_encode_noop,
|
||||
[OP_SECINFO_NO_NAME] = (nfsd4_enc)nfsd4_encode_secinfo_no_name,
|
||||
[OP_SEQUENCE] = (nfsd4_enc)nfsd4_encode_sequence,
|
||||
[OP_SET_SSV] = (nfsd4_enc)nfsd4_encode_noop,
|
||||
[OP_TEST_STATEID] = (nfsd4_enc)nfsd4_encode_noop,
|
||||
|
|
|
@ -8,12 +8,12 @@
|
|||
#include <linux/namei.h>
|
||||
#include <linux/ctype.h>
|
||||
|
||||
#include <linux/nfsd_idmap.h>
|
||||
#include <linux/sunrpc/svcsock.h>
|
||||
#include <linux/nfsd/syscall.h>
|
||||
#include <linux/lockd/lockd.h>
|
||||
#include <linux/sunrpc/clnt.h>
|
||||
|
||||
#include "idmap.h"
|
||||
#include "nfsd.h"
|
||||
#include "cache.h"
|
||||
|
||||
|
@ -127,6 +127,7 @@ static ssize_t nfsctl_transaction_write(struct file *file, const char __user *bu
|
|||
|
||||
static ssize_t nfsctl_transaction_read(struct file *file, char __user *buf, size_t size, loff_t *pos)
|
||||
{
|
||||
#ifdef CONFIG_NFSD_DEPRECATED
|
||||
static int warned;
|
||||
if (file->f_dentry->d_name.name[0] == '.' && !warned) {
|
||||
printk(KERN_INFO
|
||||
|
@ -135,6 +136,7 @@ static ssize_t nfsctl_transaction_read(struct file *file, char __user *buf, size
|
|||
current->comm, file->f_dentry->d_name.name);
|
||||
warned = 1;
|
||||
}
|
||||
#endif
|
||||
if (! file->private_data) {
|
||||
/* An attempt to read a transaction file without writing
|
||||
* causes a 0-byte write so that the file can return
|
||||
|
|
|
@ -158,6 +158,7 @@ void nfsd_lockd_shutdown(void);
|
|||
#define nfserr_attrnotsupp cpu_to_be32(NFSERR_ATTRNOTSUPP)
|
||||
#define nfserr_bad_xdr cpu_to_be32(NFSERR_BAD_XDR)
|
||||
#define nfserr_openmode cpu_to_be32(NFSERR_OPENMODE)
|
||||
#define nfserr_badowner cpu_to_be32(NFSERR_BADOWNER)
|
||||
#define nfserr_locks_held cpu_to_be32(NFSERR_LOCKS_HELD)
|
||||
#define nfserr_op_illegal cpu_to_be32(NFSERR_OP_ILLEGAL)
|
||||
#define nfserr_grace cpu_to_be32(NFSERR_GRACE)
|
||||
|
|
|
@ -735,9 +735,9 @@ nfserrno (int errno)
|
|||
{ nfserr_stale, -ESTALE },
|
||||
{ nfserr_jukebox, -ETIMEDOUT },
|
||||
{ nfserr_jukebox, -ERESTARTSYS },
|
||||
{ nfserr_dropit, -EAGAIN },
|
||||
{ nfserr_dropit, -ENOMEM },
|
||||
{ nfserr_badname, -ESRCH },
|
||||
{ nfserr_jukebox, -EAGAIN },
|
||||
{ nfserr_jukebox, -EWOULDBLOCK },
|
||||
{ nfserr_jukebox, -ENOMEM },
|
||||
{ nfserr_io, -ETXTBSY },
|
||||
{ nfserr_notsupp, -EOPNOTSUPP },
|
||||
{ nfserr_toosmall, -ETOOSMALL },
|
||||
|
|
|
@ -608,7 +608,7 @@ nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp)
|
|||
/* Now call the procedure handler, and encode NFS status. */
|
||||
nfserr = proc->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp);
|
||||
nfserr = map_new_errors(rqstp->rq_vers, nfserr);
|
||||
if (nfserr == nfserr_dropit) {
|
||||
if (nfserr == nfserr_dropit || rqstp->rq_dropme) {
|
||||
dprintk("nfsd: Dropping request; may be revisited later\n");
|
||||
nfsd_cache_update(rqstp, RC_NOCACHE, NULL);
|
||||
return 0;
|
||||
|
|
|
@ -68,10 +68,12 @@ typedef struct {
|
|||
struct nfsd4_callback {
|
||||
void *cb_op;
|
||||
struct nfs4_client *cb_clp;
|
||||
struct list_head cb_per_client;
|
||||
u32 cb_minorversion;
|
||||
struct rpc_message cb_msg;
|
||||
const struct rpc_call_ops *cb_ops;
|
||||
struct work_struct cb_work;
|
||||
bool cb_done;
|
||||
};
|
||||
|
||||
struct nfs4_delegation {
|
||||
|
@ -81,6 +83,7 @@ struct nfs4_delegation {
|
|||
atomic_t dl_count; /* ref count */
|
||||
struct nfs4_client *dl_client;
|
||||
struct nfs4_file *dl_file;
|
||||
struct file *dl_vfs_file;
|
||||
struct file_lock *dl_flock;
|
||||
u32 dl_type;
|
||||
time_t dl_time;
|
||||
|
@ -95,6 +98,7 @@ struct nfs4_delegation {
|
|||
struct nfs4_cb_conn {
|
||||
/* SETCLIENTID info */
|
||||
struct sockaddr_storage cb_addr;
|
||||
struct sockaddr_storage cb_saddr;
|
||||
size_t cb_addrlen;
|
||||
u32 cb_prog; /* used only in 4.0 case;
|
||||
per-session otherwise */
|
||||
|
@ -146,6 +150,11 @@ struct nfsd4_create_session {
|
|||
u32 gid;
|
||||
};
|
||||
|
||||
struct nfsd4_bind_conn_to_session {
|
||||
struct nfs4_sessionid sessionid;
|
||||
u32 dir;
|
||||
};
|
||||
|
||||
/* The single slot clientid cache structure */
|
||||
struct nfsd4_clid_slot {
|
||||
u32 sl_seqid;
|
||||
|
@ -235,9 +244,13 @@ struct nfs4_client {
|
|||
unsigned long cl_cb_flags;
|
||||
struct rpc_clnt *cl_cb_client;
|
||||
u32 cl_cb_ident;
|
||||
atomic_t cl_cb_set;
|
||||
#define NFSD4_CB_UP 0
|
||||
#define NFSD4_CB_UNKNOWN 1
|
||||
#define NFSD4_CB_DOWN 2
|
||||
int cl_cb_state;
|
||||
struct nfsd4_callback cl_cb_null;
|
||||
struct nfsd4_session *cl_cb_session;
|
||||
struct list_head cl_callbacks; /* list of in-progress callbacks */
|
||||
|
||||
/* for all client information that callback code might need: */
|
||||
spinlock_t cl_lock;
|
||||
|
@ -454,6 +467,7 @@ extern __be32 nfs4_check_open_reclaim(clientid_t *clid);
|
|||
extern void nfs4_free_stateowner(struct kref *kref);
|
||||
extern int set_callback_cred(void);
|
||||
extern void nfsd4_probe_callback(struct nfs4_client *clp);
|
||||
extern void nfsd4_probe_callback_sync(struct nfs4_client *clp);
|
||||
extern void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *);
|
||||
extern void nfsd4_do_callback_rpc(struct work_struct *);
|
||||
extern void nfsd4_cb_recall(struct nfs4_delegation *dp);
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
#define MSNFS /* HACK HACK */
|
||||
/*
|
||||
* File operations used by nfsd. Some of these have been ripped from
|
||||
* other parts of the kernel because they weren't exported, others
|
||||
|
@ -35,8 +34,8 @@
|
|||
#endif /* CONFIG_NFSD_V3 */
|
||||
|
||||
#ifdef CONFIG_NFSD_V4
|
||||
#include <linux/nfs4_acl.h>
|
||||
#include <linux/nfsd_idmap.h>
|
||||
#include "acl.h"
|
||||
#include "idmap.h"
|
||||
#endif /* CONFIG_NFSD_V4 */
|
||||
|
||||
#include "nfsd.h"
|
||||
|
@ -273,6 +272,13 @@ out:
|
|||
return err;
|
||||
}
|
||||
|
||||
static int nfsd_break_lease(struct inode *inode)
|
||||
{
|
||||
if (!S_ISREG(inode->i_mode))
|
||||
return 0;
|
||||
return break_lease(inode, O_WRONLY | O_NONBLOCK);
|
||||
}
|
||||
|
||||
/*
|
||||
* Commit metadata changes to stable storage.
|
||||
*/
|
||||
|
@ -375,16 +381,6 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
|
|||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we are changing the size of the file, then
|
||||
* we need to break all leases.
|
||||
*/
|
||||
host_err = break_lease(inode, O_WRONLY | O_NONBLOCK);
|
||||
if (host_err == -EWOULDBLOCK)
|
||||
host_err = -ETIMEDOUT;
|
||||
if (host_err) /* ENOMEM or EWOULDBLOCK */
|
||||
goto out_nfserr;
|
||||
|
||||
host_err = get_write_access(inode);
|
||||
if (host_err)
|
||||
goto out_nfserr;
|
||||
|
@ -425,7 +421,11 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
|
|||
|
||||
err = nfserr_notsync;
|
||||
if (!check_guard || guardtime == inode->i_ctime.tv_sec) {
|
||||
host_err = nfsd_break_lease(inode);
|
||||
if (host_err)
|
||||
goto out_nfserr;
|
||||
fh_lock(fhp);
|
||||
|
||||
host_err = notify_change(dentry, iap);
|
||||
err = nfserrno(host_err);
|
||||
fh_unlock(fhp);
|
||||
|
@ -752,8 +752,6 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
|
|||
*/
|
||||
if (!(access & NFSD_MAY_NOT_BREAK_LEASE))
|
||||
host_err = break_lease(inode, O_NONBLOCK | ((access & NFSD_MAY_WRITE) ? O_WRONLY : 0));
|
||||
if (host_err == -EWOULDBLOCK)
|
||||
host_err = -ETIMEDOUT;
|
||||
if (host_err) /* NOMEM or WOULDBLOCK */
|
||||
goto out_nfserr;
|
||||
|
||||
|
@ -874,15 +872,6 @@ static int nfsd_direct_splice_actor(struct pipe_inode_info *pipe,
|
|||
return __splice_from_pipe(pipe, sd, nfsd_splice_actor);
|
||||
}
|
||||
|
||||
static inline int svc_msnfs(struct svc_fh *ffhp)
|
||||
{
|
||||
#ifdef MSNFS
|
||||
return (ffhp->fh_export->ex_flags & NFSEXP_MSNFS);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static __be32
|
||||
nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
|
||||
loff_t offset, struct kvec *vec, int vlen, unsigned long *count)
|
||||
|
@ -895,9 +884,6 @@ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
|
|||
err = nfserr_perm;
|
||||
inode = file->f_path.dentry->d_inode;
|
||||
|
||||
if (svc_msnfs(fhp) && !lock_may_read(inode, offset, *count))
|
||||
goto out;
|
||||
|
||||
if (file->f_op->splice_read && rqstp->rq_splice_ok) {
|
||||
struct splice_desc sd = {
|
||||
.len = 0,
|
||||
|
@ -922,7 +908,6 @@ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
|
|||
fsnotify_access(file);
|
||||
} else
|
||||
err = nfserrno(host_err);
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -987,14 +972,6 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
|
|||
int stable = *stablep;
|
||||
int use_wgather;
|
||||
|
||||
#ifdef MSNFS
|
||||
err = nfserr_perm;
|
||||
|
||||
if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) &&
|
||||
(!lock_may_write(file->f_path.dentry->d_inode, offset, *cnt)))
|
||||
goto out;
|
||||
#endif
|
||||
|
||||
dentry = file->f_path.dentry;
|
||||
inode = dentry->d_inode;
|
||||
exp = fhp->fh_export;
|
||||
|
@ -1045,7 +1022,6 @@ out_nfserr:
|
|||
err = 0;
|
||||
else
|
||||
err = nfserrno(host_err);
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -1665,6 +1641,12 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
|
|||
err = nfserrno(host_err);
|
||||
goto out_dput;
|
||||
}
|
||||
err = nfserr_noent;
|
||||
if (!dold->d_inode)
|
||||
goto out_drop_write;
|
||||
host_err = nfsd_break_lease(dold->d_inode);
|
||||
if (host_err)
|
||||
goto out_drop_write;
|
||||
host_err = vfs_link(dold, dirp, dnew);
|
||||
if (!host_err) {
|
||||
err = nfserrno(commit_metadata(ffhp));
|
||||
|
@ -1676,6 +1658,7 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
|
|||
else
|
||||
err = nfserrno(host_err);
|
||||
}
|
||||
out_drop_write:
|
||||
mnt_drop_write(tfhp->fh_export->ex_path.mnt);
|
||||
out_dput:
|
||||
dput(dnew);
|
||||
|
@ -1750,12 +1733,6 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
|
|||
if (ndentry == trap)
|
||||
goto out_dput_new;
|
||||
|
||||
if (svc_msnfs(ffhp) &&
|
||||
((odentry->d_count > 1) || (ndentry->d_count > 1))) {
|
||||
host_err = -EPERM;
|
||||
goto out_dput_new;
|
||||
}
|
||||
|
||||
host_err = -EXDEV;
|
||||
if (ffhp->fh_export->ex_path.mnt != tfhp->fh_export->ex_path.mnt)
|
||||
goto out_dput_new;
|
||||
|
@ -1763,15 +1740,17 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
|
|||
if (host_err)
|
||||
goto out_dput_new;
|
||||
|
||||
host_err = nfsd_break_lease(odentry->d_inode);
|
||||
if (host_err)
|
||||
goto out_drop_write;
|
||||
host_err = vfs_rename(fdir, odentry, tdir, ndentry);
|
||||
if (!host_err) {
|
||||
host_err = commit_metadata(tfhp);
|
||||
if (!host_err)
|
||||
host_err = commit_metadata(ffhp);
|
||||
}
|
||||
|
||||
out_drop_write:
|
||||
mnt_drop_write(ffhp->fh_export->ex_path.mnt);
|
||||
|
||||
out_dput_new:
|
||||
dput(ndentry);
|
||||
out_dput_old:
|
||||
|
@ -1834,18 +1813,14 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
|
|||
if (host_err)
|
||||
goto out_nfserr;
|
||||
|
||||
if (type != S_IFDIR) { /* It's UNLINK */
|
||||
#ifdef MSNFS
|
||||
if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) &&
|
||||
(rdentry->d_count > 1)) {
|
||||
host_err = -EPERM;
|
||||
} else
|
||||
#endif
|
||||
host_err = nfsd_break_lease(rdentry->d_inode);
|
||||
if (host_err)
|
||||
goto out_put;
|
||||
if (type != S_IFDIR)
|
||||
host_err = vfs_unlink(dirp, rdentry);
|
||||
} else { /* It's RMDIR */
|
||||
else
|
||||
host_err = vfs_rmdir(dirp, rdentry);
|
||||
}
|
||||
|
||||
out_put:
|
||||
dput(rdentry);
|
||||
|
||||
if (!host_err)
|
||||
|
|
|
@ -311,6 +311,11 @@ struct nfsd4_secinfo {
|
|||
struct svc_export *si_exp; /* response */
|
||||
};
|
||||
|
||||
struct nfsd4_secinfo_no_name {
|
||||
u32 sin_style; /* request */
|
||||
struct svc_export *sin_exp; /* response */
|
||||
};
|
||||
|
||||
struct nfsd4_setattr {
|
||||
stateid_t sa_stateid; /* request */
|
||||
u32 sa_bmval[3]; /* request */
|
||||
|
@ -373,8 +378,8 @@ struct nfsd4_sequence {
|
|||
u32 cachethis; /* request */
|
||||
#if 0
|
||||
u32 target_maxslots; /* response */
|
||||
u32 status_flags; /* response */
|
||||
#endif /* not yet */
|
||||
u32 status_flags; /* response */
|
||||
};
|
||||
|
||||
struct nfsd4_destroy_session {
|
||||
|
@ -422,6 +427,7 @@ struct nfsd4_op {
|
|||
|
||||
/* NFSv4.1 */
|
||||
struct nfsd4_exchange_id exchange_id;
|
||||
struct nfsd4_bind_conn_to_session bind_conn_to_session;
|
||||
struct nfsd4_create_session create_session;
|
||||
struct nfsd4_destroy_session destroy_session;
|
||||
struct nfsd4_sequence sequence;
|
||||
|
@ -518,6 +524,7 @@ extern __be32 nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp,
|
|||
struct nfsd4_sequence *seq);
|
||||
extern __be32 nfsd4_exchange_id(struct svc_rqst *rqstp,
|
||||
struct nfsd4_compound_state *, struct nfsd4_exchange_id *);
|
||||
extern __be32 nfsd4_bind_conn_to_session(struct svc_rqst *, struct nfsd4_compound_state *, struct nfsd4_bind_conn_to_session *);
|
||||
extern __be32 nfsd4_create_session(struct svc_rqst *,
|
||||
struct nfsd4_compound_state *,
|
||||
struct nfsd4_create_session *);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue