Skip to content

Commit

Permalink
Merge branch 'bugfixes' of git://git.linux-nfs.org/projects/trondmy/n…
Browse files Browse the repository at this point in the history
…fs-2.6

* 'bugfixes' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6:
  NFS: NFSv4 readdir loses entries
  NFS: Micro-optimize nfs4_decode_dirent()
  NFS: Fix an NFS client lockdep issue
  NFS construct consistent co_ownerid for v4.1
  NFS: nfs_wcc_update_inode() should set nfsi->attr_gencount
  NFS improve pnfs_put_deviceid_cache debug print
  NFS fix cb_sequence error processing
  NFS do not find client in NFSv4 pg_authenticate
  NLM: Fix "kernel BUG at fs/lockd/host.c:417!" or ".../host.c:283!"
  NFS: Prevent memory allocation failure in nfsacl_encode()
  NFS: nfsacl_{encode,decode} should return signed integer
  NFS: Fix "kernel BUG at fs/nfs/nfs3xdr.c:1338!"
  NFS: Fix "kernel BUG at fs/aio.c:554!"
  NFS4: Avoid potential NULL pointer dereference in decode_and_add_ds().
  NFS: fix handling of malloc failure during nfs_flush_multi()
  • Loading branch information
Linus Torvalds committed Jan 31, 2011
2 parents 7921127 + d1205f8 commit 0fd08c5
Show file tree
Hide file tree
Showing 25 changed files with 174 additions and 210 deletions.
9 changes: 5 additions & 4 deletions fs/lockd/host.c
Original file line number Diff line number Diff line change
Expand Up @@ -520,7 +520,7 @@ static struct nlm_host *next_host_state(struct hlist_head *cache,
struct nsm_handle *nsm,
const struct nlm_reboot *info)
{
struct nlm_host *host = NULL;
struct nlm_host *host;
struct hlist_head *chain;
struct hlist_node *pos;

Expand All @@ -532,12 +532,13 @@ static struct nlm_host *next_host_state(struct hlist_head *cache,
host->h_state++;

nlm_get_host(host);
goto out;
mutex_unlock(&nlm_host_mutex);
return host;
}
}
out:

mutex_unlock(&nlm_host_mutex);
return host;
return NULL;
}

/**
Expand Down
109 changes: 29 additions & 80 deletions fs/nfs/callback.c
Original file line number Diff line number Diff line change
Expand Up @@ -134,33 +134,6 @@ nfs4_callback_up(struct svc_serv *serv)
}

#if defined(CONFIG_NFS_V4_1)
/*
* * CB_SEQUENCE operations will fail until the callback sessionid is set.
* */
int nfs4_set_callback_sessionid(struct nfs_client *clp)
{
struct svc_serv *serv = clp->cl_rpcclient->cl_xprt->bc_serv;
struct nfs4_sessionid *bc_sid;

if (!serv->sv_bc_xprt)
return -EINVAL;

/* on success freed in xprt_free */
bc_sid = kmalloc(sizeof(struct nfs4_sessionid), GFP_KERNEL);
if (!bc_sid)
return -ENOMEM;
memcpy(bc_sid->data, &clp->cl_session->sess_id.data,
NFS4_MAX_SESSIONID_LEN);
spin_lock_bh(&serv->sv_cb_lock);
serv->sv_bc_xprt->xpt_bc_sid = bc_sid;
spin_unlock_bh(&serv->sv_cb_lock);
dprintk("%s set xpt_bc_sid=%u:%u:%u:%u for sv_bc_xprt %p\n", __func__,
((u32 *)bc_sid->data)[0], ((u32 *)bc_sid->data)[1],
((u32 *)bc_sid->data)[2], ((u32 *)bc_sid->data)[3],
serv->sv_bc_xprt);
return 0;
}

/*
* The callback service for NFSv4.1 callbacks
*/
Expand Down Expand Up @@ -266,10 +239,6 @@ static inline void nfs_callback_bc_serv(u32 minorversion, struct rpc_xprt *xprt,
struct nfs_callback_data *cb_info)
{
}
int nfs4_set_callback_sessionid(struct nfs_client *clp)
{
return 0;
}
#endif /* CONFIG_NFS_V4_1 */

/*
Expand Down Expand Up @@ -359,78 +328,58 @@ void nfs_callback_down(int minorversion)
mutex_unlock(&nfs_callback_mutex);
}

static int check_gss_callback_principal(struct nfs_client *clp,
struct svc_rqst *rqstp)
/* Boolean check of RPC_AUTH_GSS principal */
int
check_gss_callback_principal(struct nfs_client *clp, struct svc_rqst *rqstp)
{
struct rpc_clnt *r = clp->cl_rpcclient;
char *p = svc_gss_principal(rqstp);

if (rqstp->rq_authop->flavour != RPC_AUTH_GSS)
return 1;

/* No RPC_AUTH_GSS on NFSv4.1 back channel yet */
if (clp->cl_minorversion != 0)
return SVC_DROP;
return 0;
/*
* It might just be a normal user principal, in which case
* userspace won't bother to tell us the name at all.
*/
if (p == NULL)
return SVC_DENIED;
return 0;

/* Expect a GSS_C_NT_HOSTBASED_NAME like "nfs@serverhostname" */

if (memcmp(p, "nfs@", 4) != 0)
return SVC_DENIED;
return 0;
p += 4;
if (strcmp(p, r->cl_server) != 0)
return SVC_DENIED;
return SVC_OK;
return 0;
return 1;
}

/* pg_authenticate method helper */
static struct nfs_client *nfs_cb_find_client(struct svc_rqst *rqstp)
{
struct nfs4_sessionid *sessionid = bc_xprt_sid(rqstp);
int is_cb_compound = rqstp->rq_proc == CB_COMPOUND ? 1 : 0;

dprintk("--> %s rq_proc %d\n", __func__, rqstp->rq_proc);
if (svc_is_backchannel(rqstp))
/* Sessionid (usually) set after CB_NULL ping */
return nfs4_find_client_sessionid(svc_addr(rqstp), sessionid,
is_cb_compound);
else
/* No callback identifier in pg_authenticate */
return nfs4_find_client_no_ident(svc_addr(rqstp));
}

/* pg_authenticate method for nfsv4 callback threads. */
/*
* pg_authenticate method for nfsv4 callback threads.
*
* The authflavor has been negotiated, so an incorrect flavor is a server
* bug. Drop packets with incorrect authflavor.
*
* All other checking done after NFS decoding where the nfs_client can be
* found in nfs4_callback_compound
*/
static int nfs_callback_authenticate(struct svc_rqst *rqstp)
{
struct nfs_client *clp;
RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]);
int ret = SVC_OK;

/* Don't talk to strangers */
clp = nfs_cb_find_client(rqstp);
if (clp == NULL)
return SVC_DROP;

dprintk("%s: %s NFSv4 callback!\n", __func__,
svc_print_addr(rqstp, buf, sizeof(buf)));

switch (rqstp->rq_authop->flavour) {
case RPC_AUTH_NULL:
if (rqstp->rq_proc != CB_NULL)
ret = SVC_DENIED;
break;
case RPC_AUTH_UNIX:
break;
case RPC_AUTH_GSS:
ret = check_gss_callback_principal(clp, rqstp);
break;
default:
ret = SVC_DENIED;
case RPC_AUTH_NULL:
if (rqstp->rq_proc != CB_NULL)
return SVC_DROP;
break;
case RPC_AUTH_GSS:
/* No RPC_AUTH_GSS support yet in NFSv4.1 */
if (svc_is_backchannel(rqstp))
return SVC_DROP;
}
nfs_put_client(clp);
return ret;
return SVC_OK;
}

/*
Expand Down
4 changes: 2 additions & 2 deletions fs/nfs/callback.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
*/
#ifndef __LINUX_FS_NFS_CALLBACK_H
#define __LINUX_FS_NFS_CALLBACK_H
#include <linux/sunrpc/svc.h>

#define NFS4_CALLBACK 0x40000000
#define NFS4_CALLBACK_XDRSIZE 2048
Expand Down Expand Up @@ -37,7 +38,6 @@ enum nfs4_callback_opnum {
struct cb_process_state {
__be32 drc_status;
struct nfs_client *clp;
struct nfs4_sessionid *svc_sid; /* v4.1 callback service sessionid */
};

struct cb_compound_hdr_arg {
Expand Down Expand Up @@ -168,7 +168,7 @@ extern unsigned nfs4_callback_layoutrecall(
extern void nfs4_check_drain_bc_complete(struct nfs4_session *ses);
extern void nfs4_cb_take_slot(struct nfs_client *clp);
#endif /* CONFIG_NFS_V4_1 */

extern int check_gss_callback_principal(struct nfs_client *, struct svc_rqst *);
extern __be32 nfs4_callback_getattr(struct cb_getattrargs *args,
struct cb_getattrres *res,
struct cb_process_state *cps);
Expand Down
12 changes: 3 additions & 9 deletions fs/nfs/callback_proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -373,17 +373,11 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args,
{
struct nfs_client *clp;
int i;
__be32 status;
__be32 status = htonl(NFS4ERR_BADSESSION);

cps->clp = NULL;

status = htonl(NFS4ERR_BADSESSION);
/* Incoming session must match the callback session */
if (memcmp(&args->csa_sessionid, cps->svc_sid, NFS4_MAX_SESSIONID_LEN))
goto out;

clp = nfs4_find_client_sessionid(args->csa_addr,
&args->csa_sessionid, 1);
clp = nfs4_find_client_sessionid(args->csa_addr, &args->csa_sessionid);
if (clp == NULL)
goto out;

Expand Down Expand Up @@ -414,9 +408,9 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args,
res->csr_highestslotid = NFS41_BC_MAX_CALLBACKS - 1;
res->csr_target_highestslotid = NFS41_BC_MAX_CALLBACKS - 1;
nfs4_cb_take_slot(clp);
cps->clp = clp; /* put in nfs4_callback_compound */

out:
cps->clp = clp; /* put in nfs4_callback_compound */
for (i = 0; i < args->csa_nrclists; i++)
kfree(args->csa_rclists[i].rcl_refcalls);
kfree(args->csa_rclists);
Expand Down
5 changes: 2 additions & 3 deletions fs/nfs/callback_xdr.c
Original file line number Diff line number Diff line change
Expand Up @@ -794,10 +794,9 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r

if (hdr_arg.minorversion == 0) {
cps.clp = nfs4_find_client_ident(hdr_arg.cb_ident);
if (!cps.clp)
if (!cps.clp || !check_gss_callback_principal(cps.clp, rqstp))
return rpc_drop_reply;
} else
cps.svc_sid = bc_xprt_sid(rqstp);
}

hdr_res.taglen = hdr_arg.taglen;
hdr_res.tag = hdr_arg.tag;
Expand Down
15 changes: 5 additions & 10 deletions fs/nfs/client.c
Original file line number Diff line number Diff line change
Expand Up @@ -1206,16 +1206,11 @@ nfs4_find_client_ident(int cb_ident)
* For CB_COMPOUND calls, find a client by IP address, protocol version,
* minorversion, and sessionID
*
* CREATE_SESSION triggers a CB_NULL ping from servers. The callback service
* sessionid can only be set after the CREATE_SESSION return, so a CB_NULL
* can arrive before the callback sessionid is set. For CB_NULL calls,
* find a client by IP address protocol version, and minorversion.
*
* Returns NULL if no such client
*/
struct nfs_client *
nfs4_find_client_sessionid(const struct sockaddr *addr,
struct nfs4_sessionid *sid, int is_cb_compound)
struct nfs4_sessionid *sid)
{
struct nfs_client *clp;

Expand All @@ -1227,9 +1222,9 @@ nfs4_find_client_sessionid(const struct sockaddr *addr,
if (!nfs4_has_session(clp))
continue;

/* Match sessionid unless cb_null call*/
if (is_cb_compound && (memcmp(clp->cl_session->sess_id.data,
sid->data, NFS4_MAX_SESSIONID_LEN) != 0))
/* Match sessionid*/
if (memcmp(clp->cl_session->sess_id.data,
sid->data, NFS4_MAX_SESSIONID_LEN) != 0)
continue;

atomic_inc(&clp->cl_count);
Expand All @@ -1244,7 +1239,7 @@ nfs4_find_client_sessionid(const struct sockaddr *addr,

struct nfs_client *
nfs4_find_client_sessionid(const struct sockaddr *addr,
struct nfs4_sessionid *sid, int is_cb_compound)
struct nfs4_sessionid *sid)
{
return NULL;
}
Expand Down
6 changes: 4 additions & 2 deletions fs/nfs/delegation.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@

static void nfs_do_free_delegation(struct nfs_delegation *delegation)
{
if (delegation->cred)
put_rpccred(delegation->cred);
kfree(delegation);
}

Expand All @@ -37,6 +35,10 @@ static void nfs_free_delegation_callback(struct rcu_head *head)

static void nfs_free_delegation(struct nfs_delegation *delegation)
{
if (delegation->cred) {
put_rpccred(delegation->cred);
delegation->cred = NULL;
}
call_rcu(&delegation->rcu, nfs_free_delegation_callback);
}

Expand Down
34 changes: 20 additions & 14 deletions fs/nfs/direct.c
Original file line number Diff line number Diff line change
Expand Up @@ -407,15 +407,18 @@ static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq,
pos += vec->iov_len;
}

/*
* If no bytes were started, return the error, and let the
* generic layer handle the completion.
*/
if (requested_bytes == 0) {
nfs_direct_req_release(dreq);
return result < 0 ? result : -EIO;
}

if (put_dreq(dreq))
nfs_direct_complete(dreq);

if (requested_bytes != 0)
return 0;

if (result < 0)
return result;
return -EIO;
return 0;
}

static ssize_t nfs_direct_read(struct kiocb *iocb, const struct iovec *iov,
Expand Down Expand Up @@ -841,15 +844,18 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq,
pos += vec->iov_len;
}

/*
* If no bytes were started, return the error, and let the
* generic layer handle the completion.
*/
if (requested_bytes == 0) {
nfs_direct_req_release(dreq);
return result < 0 ? result : -EIO;
}

if (put_dreq(dreq))
nfs_direct_write_complete(dreq, dreq->inode);

if (requested_bytes != 0)
return 0;

if (result < 0)
return result;
return -EIO;
return 0;
}

static ssize_t nfs_direct_write(struct kiocb *iocb, const struct iovec *iov,
Expand Down
Loading

0 comments on commit 0fd08c5

Please sign in to comment.