Commit 0fd08c55 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'bugfixes' of git://git.linux-nfs.org/projects/trondmy/nfs-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()
parents 7921127e d1205f87
...@@ -520,7 +520,7 @@ static struct nlm_host *next_host_state(struct hlist_head *cache, ...@@ -520,7 +520,7 @@ static struct nlm_host *next_host_state(struct hlist_head *cache,
struct nsm_handle *nsm, struct nsm_handle *nsm,
const struct nlm_reboot *info) const struct nlm_reboot *info)
{ {
struct nlm_host *host = NULL; struct nlm_host *host;
struct hlist_head *chain; struct hlist_head *chain;
struct hlist_node *pos; struct hlist_node *pos;
...@@ -532,12 +532,13 @@ static struct nlm_host *next_host_state(struct hlist_head *cache, ...@@ -532,12 +532,13 @@ static struct nlm_host *next_host_state(struct hlist_head *cache,
host->h_state++; host->h_state++;
nlm_get_host(host); nlm_get_host(host);
goto out; mutex_unlock(&nlm_host_mutex);
return host;
} }
} }
out:
mutex_unlock(&nlm_host_mutex); mutex_unlock(&nlm_host_mutex);
return host; return NULL;
} }
/** /**
......
...@@ -134,33 +134,6 @@ nfs4_callback_up(struct svc_serv *serv) ...@@ -134,33 +134,6 @@ nfs4_callback_up(struct svc_serv *serv)
} }
#if defined(CONFIG_NFS_V4_1) #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 * The callback service for NFSv4.1 callbacks
*/ */
...@@ -266,10 +239,6 @@ static inline void nfs_callback_bc_serv(u32 minorversion, struct rpc_xprt *xprt, ...@@ -266,10 +239,6 @@ static inline void nfs_callback_bc_serv(u32 minorversion, struct rpc_xprt *xprt,
struct nfs_callback_data *cb_info) struct nfs_callback_data *cb_info)
{ {
} }
int nfs4_set_callback_sessionid(struct nfs_client *clp)
{
return 0;
}
#endif /* CONFIG_NFS_V4_1 */ #endif /* CONFIG_NFS_V4_1 */
/* /*
...@@ -359,78 +328,58 @@ void nfs_callback_down(int minorversion) ...@@ -359,78 +328,58 @@ void nfs_callback_down(int minorversion)
mutex_unlock(&nfs_callback_mutex); mutex_unlock(&nfs_callback_mutex);
} }
static int check_gss_callback_principal(struct nfs_client *clp, /* Boolean check of RPC_AUTH_GSS principal */
struct svc_rqst *rqstp) int
check_gss_callback_principal(struct nfs_client *clp, struct svc_rqst *rqstp)
{ {
struct rpc_clnt *r = clp->cl_rpcclient; struct rpc_clnt *r = clp->cl_rpcclient;
char *p = svc_gss_principal(rqstp); 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 */ /* No RPC_AUTH_GSS on NFSv4.1 back channel yet */
if (clp->cl_minorversion != 0) if (clp->cl_minorversion != 0)
return SVC_DROP; return 0;
/* /*
* It might just be a normal user principal, in which case * It might just be a normal user principal, in which case
* userspace won't bother to tell us the name at all. * userspace won't bother to tell us the name at all.
*/ */
if (p == NULL) if (p == NULL)
return SVC_DENIED; return 0;
/* Expect a GSS_C_NT_HOSTBASED_NAME like "nfs@serverhostname" */ /* Expect a GSS_C_NT_HOSTBASED_NAME like "nfs@serverhostname" */
if (memcmp(p, "nfs@", 4) != 0) if (memcmp(p, "nfs@", 4) != 0)
return SVC_DENIED; return 0;
p += 4; p += 4;
if (strcmp(p, r->cl_server) != 0) if (strcmp(p, r->cl_server) != 0)
return SVC_DENIED; return 0;
return SVC_OK; 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) 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) { switch (rqstp->rq_authop->flavour) {
case RPC_AUTH_NULL: case RPC_AUTH_NULL:
if (rqstp->rq_proc != CB_NULL) if (rqstp->rq_proc != CB_NULL)
ret = SVC_DENIED; return SVC_DROP;
break;
case RPC_AUTH_UNIX:
break; break;
case RPC_AUTH_GSS: case RPC_AUTH_GSS:
ret = check_gss_callback_principal(clp, rqstp); /* No RPC_AUTH_GSS support yet in NFSv4.1 */
break; if (svc_is_backchannel(rqstp))
default: return SVC_DROP;
ret = SVC_DENIED;
} }
nfs_put_client(clp); return SVC_OK;
return ret;
} }
/* /*
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
*/ */
#ifndef __LINUX_FS_NFS_CALLBACK_H #ifndef __LINUX_FS_NFS_CALLBACK_H
#define __LINUX_FS_NFS_CALLBACK_H #define __LINUX_FS_NFS_CALLBACK_H
#include <linux/sunrpc/svc.h>
#define NFS4_CALLBACK 0x40000000 #define NFS4_CALLBACK 0x40000000
#define NFS4_CALLBACK_XDRSIZE 2048 #define NFS4_CALLBACK_XDRSIZE 2048
...@@ -37,7 +38,6 @@ enum nfs4_callback_opnum { ...@@ -37,7 +38,6 @@ enum nfs4_callback_opnum {
struct cb_process_state { struct cb_process_state {
__be32 drc_status; __be32 drc_status;
struct nfs_client *clp; struct nfs_client *clp;
struct nfs4_sessionid *svc_sid; /* v4.1 callback service sessionid */
}; };
struct cb_compound_hdr_arg { struct cb_compound_hdr_arg {
...@@ -168,7 +168,7 @@ extern unsigned nfs4_callback_layoutrecall( ...@@ -168,7 +168,7 @@ extern unsigned nfs4_callback_layoutrecall(
extern void nfs4_check_drain_bc_complete(struct nfs4_session *ses); extern void nfs4_check_drain_bc_complete(struct nfs4_session *ses);
extern void nfs4_cb_take_slot(struct nfs_client *clp); extern void nfs4_cb_take_slot(struct nfs_client *clp);
#endif /* CONFIG_NFS_V4_1 */ #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, extern __be32 nfs4_callback_getattr(struct cb_getattrargs *args,
struct cb_getattrres *res, struct cb_getattrres *res,
struct cb_process_state *cps); struct cb_process_state *cps);
......
...@@ -373,17 +373,11 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args, ...@@ -373,17 +373,11 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args,
{ {
struct nfs_client *clp; struct nfs_client *clp;
int i; int i;
__be32 status; __be32 status = htonl(NFS4ERR_BADSESSION);
cps->clp = NULL; cps->clp = NULL;
status = htonl(NFS4ERR_BADSESSION); clp = nfs4_find_client_sessionid(args->csa_addr, &args->csa_sessionid);
/* 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);
if (clp == NULL) if (clp == NULL)
goto out; goto out;
...@@ -414,9 +408,9 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args, ...@@ -414,9 +408,9 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args,
res->csr_highestslotid = NFS41_BC_MAX_CALLBACKS - 1; res->csr_highestslotid = NFS41_BC_MAX_CALLBACKS - 1;
res->csr_target_highestslotid = NFS41_BC_MAX_CALLBACKS - 1; res->csr_target_highestslotid = NFS41_BC_MAX_CALLBACKS - 1;
nfs4_cb_take_slot(clp); nfs4_cb_take_slot(clp);
cps->clp = clp; /* put in nfs4_callback_compound */
out: out:
cps->clp = clp; /* put in nfs4_callback_compound */
for (i = 0; i < args->csa_nrclists; i++) for (i = 0; i < args->csa_nrclists; i++)
kfree(args->csa_rclists[i].rcl_refcalls); kfree(args->csa_rclists[i].rcl_refcalls);
kfree(args->csa_rclists); kfree(args->csa_rclists);
......
...@@ -794,10 +794,9 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r ...@@ -794,10 +794,9 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r
if (hdr_arg.minorversion == 0) { if (hdr_arg.minorversion == 0) {
cps.clp = nfs4_find_client_ident(hdr_arg.cb_ident); 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; return rpc_drop_reply;
} else }
cps.svc_sid = bc_xprt_sid(rqstp);
hdr_res.taglen = hdr_arg.taglen; hdr_res.taglen = hdr_arg.taglen;
hdr_res.tag = hdr_arg.tag; hdr_res.tag = hdr_arg.tag;
......
...@@ -1206,16 +1206,11 @@ nfs4_find_client_ident(int cb_ident) ...@@ -1206,16 +1206,11 @@ nfs4_find_client_ident(int cb_ident)
* For CB_COMPOUND calls, find a client by IP address, protocol version, * For CB_COMPOUND calls, find a client by IP address, protocol version,
* minorversion, and sessionID * 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 * Returns NULL if no such client
*/ */
struct nfs_client * struct nfs_client *
nfs4_find_client_sessionid(const struct sockaddr *addr, nfs4_find_client_sessionid(const struct sockaddr *addr,
struct nfs4_sessionid *sid, int is_cb_compound) struct nfs4_sessionid *sid)
{ {
struct nfs_client *clp; struct nfs_client *clp;
...@@ -1227,9 +1222,9 @@ nfs4_find_client_sessionid(const struct sockaddr *addr, ...@@ -1227,9 +1222,9 @@ nfs4_find_client_sessionid(const struct sockaddr *addr,
if (!nfs4_has_session(clp)) if (!nfs4_has_session(clp))
continue; continue;
/* Match sessionid unless cb_null call*/ /* Match sessionid*/
if (is_cb_compound && (memcmp(clp->cl_session->sess_id.data, if (memcmp(clp->cl_session->sess_id.data,
sid->data, NFS4_MAX_SESSIONID_LEN) != 0)) sid->data, NFS4_MAX_SESSIONID_LEN) != 0)
continue; continue;
atomic_inc(&clp->cl_count); atomic_inc(&clp->cl_count);
...@@ -1244,7 +1239,7 @@ nfs4_find_client_sessionid(const struct sockaddr *addr, ...@@ -1244,7 +1239,7 @@ nfs4_find_client_sessionid(const struct sockaddr *addr,
struct nfs_client * struct nfs_client *
nfs4_find_client_sessionid(const struct sockaddr *addr, nfs4_find_client_sessionid(const struct sockaddr *addr,
struct nfs4_sessionid *sid, int is_cb_compound) struct nfs4_sessionid *sid)
{ {
return NULL; return NULL;
} }
......
...@@ -23,8 +23,6 @@ ...@@ -23,8 +23,6 @@
static void nfs_do_free_delegation(struct nfs_delegation *delegation) static void nfs_do_free_delegation(struct nfs_delegation *delegation)
{ {
if (delegation->cred)
put_rpccred(delegation->cred);
kfree(delegation); kfree(delegation);
} }
...@@ -37,6 +35,10 @@ static void nfs_free_delegation_callback(struct rcu_head *head) ...@@ -37,6 +35,10 @@ static void nfs_free_delegation_callback(struct rcu_head *head)
static void nfs_free_delegation(struct nfs_delegation *delegation) 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); call_rcu(&delegation->rcu, nfs_free_delegation_callback);
} }
......
...@@ -407,15 +407,18 @@ static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq, ...@@ -407,15 +407,18 @@ static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq,
pos += vec->iov_len; 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)) if (put_dreq(dreq))
nfs_direct_complete(dreq); nfs_direct_complete(dreq);
if (requested_bytes != 0)
return 0; return 0;
if (result < 0)
return result;
return -EIO;
} }
static ssize_t nfs_direct_read(struct kiocb *iocb, const struct iovec *iov, static ssize_t nfs_direct_read(struct kiocb *iocb, const struct iovec *iov,
...@@ -841,15 +844,18 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq, ...@@ -841,15 +844,18 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq,
pos += vec->iov_len; 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)) if (put_dreq(dreq))
nfs_direct_write_complete(dreq, dreq->inode); nfs_direct_write_complete(dreq, dreq->inode);
if (requested_bytes != 0)
return 0; return 0;
if (result < 0)
return result;
return -EIO;
} }
static ssize_t nfs_direct_write(struct kiocb *iocb, const struct iovec *iov, static ssize_t nfs_direct_write(struct kiocb *iocb, const struct iovec *iov,
......
...@@ -881,9 +881,10 @@ int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping) ...@@ -881,9 +881,10 @@ int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping)
return ret; return ret;
} }
static void nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr) static unsigned long nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr)
{ {
struct nfs_inode *nfsi = NFS_I(inode); struct nfs_inode *nfsi = NFS_I(inode);
unsigned long ret = 0;
if ((fattr->valid & NFS_ATTR_FATTR_PRECHANGE) if ((fattr->valid & NFS_ATTR_FATTR_PRECHANGE)
&& (fattr->valid & NFS_ATTR_FATTR_CHANGE) && (fattr->valid & NFS_ATTR_FATTR_CHANGE)
...@@ -891,12 +892,15 @@ static void nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr) ...@@ -891,12 +892,15 @@ static void nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr)
nfsi->change_attr = fattr->change_attr; nfsi->change_attr = fattr->change_attr;
if (S_ISDIR(inode->i_mode)) if (S_ISDIR(inode->i_mode))
nfsi->cache_validity |= NFS_INO_INVALID_DATA; nfsi->cache_validity |= NFS_INO_INVALID_DATA;
ret |= NFS_INO_INVALID_ATTR;
} }
/* If we have atomic WCC data, we may update some attributes */ /* If we have atomic WCC data, we may update some attributes */
if ((fattr->valid & NFS_ATTR_FATTR_PRECTIME) if ((fattr->valid & NFS_ATTR_FATTR_PRECTIME)
&& (fattr->valid & NFS_ATTR_FATTR_CTIME) && (fattr->valid & NFS_ATTR_FATTR_CTIME)
&& timespec_equal(&inode->i_ctime, &fattr->pre_ctime)) && timespec_equal(&inode->i_ctime, &fattr->pre_ctime)) {
memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime)); memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime));
ret |= NFS_INO_INVALID_ATTR;
}
if ((fattr->valid & NFS_ATTR_FATTR_PREMTIME) if ((fattr->valid & NFS_ATTR_FATTR_PREMTIME)
&& (fattr->valid & NFS_ATTR_FATTR_MTIME) && (fattr->valid & NFS_ATTR_FATTR_MTIME)
...@@ -904,12 +908,16 @@ static void nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr) ...@@ -904,12 +908,16 @@ static void nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr)
memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime)); memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime));
if (S_ISDIR(inode->i_mode)) if (S_ISDIR(inode->i_mode))
nfsi->cache_validity |= NFS_INO_INVALID_DATA; nfsi->cache_validity |= NFS_INO_INVALID_DATA;
ret |= NFS_INO_INVALID_ATTR;
} }
if ((fattr->valid & NFS_ATTR_FATTR_PRESIZE) if ((fattr->valid & NFS_ATTR_FATTR_PRESIZE)
&& (fattr->valid & NFS_ATTR_FATTR_SIZE) && (fattr->valid & NFS_ATTR_FATTR_SIZE)
&& i_size_read(inode) == nfs_size_to_loff_t(fattr->pre_size) && i_size_read(inode) == nfs_size_to_loff_t(fattr->pre_size)
&& nfsi->npages == 0) && nfsi->npages == 0) {
i_size_write(inode, nfs_size_to_loff_t(fattr->size)); i_size_write(inode, nfs_size_to_loff_t(fattr->size));
ret |= NFS_INO_INVALID_ATTR;
}
return ret;
} }
/** /**
...@@ -1223,7 +1231,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) ...@@ -1223,7 +1231,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
| NFS_INO_REVAL_PAGECACHE); | NFS_INO_REVAL_PAGECACHE);
/* Do atomic weak cache consistency updates */ /* Do atomic weak cache consistency updates */
nfs_wcc_update_inode(inode, fattr); invalid |= nfs_wcc_update_inode(inode, fattr);
/* More cache consistency checks */ /* More cache consistency checks */
if (fattr->valid & NFS_ATTR_FATTR_CHANGE) { if (fattr->valid & NFS_ATTR_FATTR_CHANGE) {
......
...@@ -133,8 +133,7 @@ extern void nfs_put_client(struct nfs_client *); ...@@ -133,8 +133,7 @@ extern void nfs_put_client(struct nfs_client *);
extern struct nfs_client *nfs4_find_client_no_ident(const struct sockaddr *); extern struct nfs_client *nfs4_find_client_no_ident(const struct sockaddr *);
extern struct nfs_client *nfs4_find_client_ident(int); extern struct nfs_client *nfs4_find_client_ident(int);
extern struct nfs_client * extern struct nfs_client *
nfs4_find_client_sessionid(const struct sockaddr *, struct nfs4_sessionid *, nfs4_find_client_sessionid(const struct sockaddr *, struct nfs4_sessionid *);
int);
extern struct nfs_server *nfs_create_server( extern struct nfs_server *nfs_create_server(
const struct nfs_parsed_mount_data *, const struct nfs_parsed_mount_data *,
struct nfs_fh *); struct nfs_fh *);
......
...@@ -311,8 +311,8 @@ static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl, ...@@ -311,8 +311,8 @@ static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl,
if (!nfs_server_capable(inode, NFS_CAP_ACLS)) if (!nfs_server_capable(inode, NFS_CAP_ACLS))
goto out; goto out;
/* We are doing this here, because XDR marshalling can only /* We are doing this here because XDR marshalling does not
return -ENOMEM. */ * return any results, it BUGs. */
status = -ENOSPC; status = -ENOSPC;
if (acl != NULL && acl->a_count > NFS_ACL_MAX_ENTRIES) if (acl != NULL && acl->a_count > NFS_ACL_MAX_ENTRIES)
goto out; goto out;
......
...@@ -1328,10 +1328,13 @@ static void nfs3_xdr_enc_setacl3args(struct rpc_rqst *req, ...@@ -1328,10 +1328,13 @@ static void nfs3_xdr_enc_setacl3args(struct rpc_rqst *req,
encode_nfs_fh3(xdr, NFS_FH(args->inode)); encode_nfs_fh3(xdr, NFS_FH(args->inode));
encode_uint32(xdr, args->mask); encode_uint32(xdr, args->mask);
base = req->rq_slen;
if (args->npages != 0) if (args->npages != 0)
xdr_write_pages(xdr, args->pages, 0, args->len); xdr_write_pages(xdr, args->pages, 0, args->len);
else
xdr_reserve_space(xdr, NFS_ACL_INLINE_BUFSIZE);
base = req->rq_slen;
error = nfsacl_encode(xdr->buf, base, args->inode, error = nfsacl_encode(xdr->buf, base, args->inode,
(args->mask & NFS_ACL) ? (args->mask & NFS_ACL) ?
args->acl_access : NULL, 1, 0); args->acl_access : NULL, 1, 0);
......
...@@ -214,7 +214,7 @@ decode_and_add_ds(__be32 **pp, struct inode *inode) ...@@ -214,7 +214,7 @@ decode_and_add_ds(__be32 **pp, struct inode *inode)
/* ipv6 length plus port is legal */ /* ipv6 length plus port is legal */
if (rlen > INET6_ADDRSTRLEN + 8) { if (rlen > INET6_ADDRSTRLEN + 8) {
dprintk("%s Invalid address, length %d\n", __func__, dprintk("%s: Invalid address, length %d\n", __func__,
rlen); rlen);
goto out_err; goto out_err;
} }
...@@ -225,6 +225,11 @@ decode_and_add_ds(__be32 **pp, struct inode *inode) ...@@ -225,6 +225,11 @@ decode_and_add_ds(__be32 **pp, struct inode *inode)
/* replace the port dots with dashes for the in4_pton() delimiter*/ /* replace the port dots with dashes for the in4_pton() delimiter*/
for (i = 0; i < 2; i++) { for (i = 0; i < 2; i++) {
char *res = strrchr(buf, '.'); char *res = strrchr(buf, '.');
if (!res) {
dprintk("%s: Failed finding expected dots in port\n",
__func__);
goto out_free;
}
*res = '-'; *res = '-';
} }
...@@ -240,7 +245,7 @@ decode_and_add_ds(__be32 **pp, struct inode *inode) ...@@ -240,7 +245,7 @@ decode_and_add_ds(__be32 **pp, struct inode *inode)
port = htons((tmp[0] << 8) | (tmp[1])); port = htons((tmp[0] << 8) | (tmp[1]));
ds = nfs4_pnfs_ds_add(inode, ip_addr, port); ds = nfs4_pnfs_ds_add(inode, ip_addr, port);
dprintk("%s Decoded address and port %s\n", __func__, buf); dprintk("%s: Decoded address and port %s\n", __func__, buf);
out_free: out_free:
kfree(buf); kfree(buf);
out_err: out_err:
......
...@@ -50,6 +50,7 @@ ...@@ -50,6 +50,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/sunrpc/bc_xprt.h> #include <linux/sunrpc/bc_xprt.h>
#include <linux/xattr.h> #include <linux/xattr.h>
#include <linux/utsname.h>
#include "nfs4_fs.h" #include "nfs4_fs.h"
#include "delegation.h" #include "delegation.h"
...@@ -4572,26 +4573,15 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred) ...@@ -4572,26 +4573,15 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred)
*p = htonl((u32)clp->cl_boot_time.tv_nsec); *p = htonl((u32)clp->cl_boot_time.tv_nsec);
args.verifier = &verifier; args.verifier = &verifier;
while (1) {
args.id_len = scnprintf(args.id, sizeof(args.id), args.id_len = scnprintf(args.id, sizeof(args.id),
"%s/%s %u", "%s/%s.%s/%u",
clp->cl_ipaddr, clp->cl_ipaddr,
rpc_peeraddr2str(clp->cl_rpcclient, init_utsname()->nodename,
RPC_DISPLAY_ADDR), init_utsname()->domainname,
clp->cl_id_uniquifier); clp->cl_rpcclient->cl_auth->au_flavor);
status = rpc_call_sync(clp->cl_rpcclient, &msg, 0); status = rpc_call_sync(clp->cl_rpcclient, &msg, 0);
if (!status)
if (status != -NFS4ERR_CLID_INUSE)
break;
if (signalled())
break;
if (++clp->cl_id_uniquifier == 0)
break;
}
status = nfs4_check_cl_exchange_flags(clp->cl_exchange_flags); status = nfs4_check_cl_exchange_flags(clp->cl_exchange_flags);
dprintk("<-- %s status= %d\n", __func__, status); dprintk("<-- %s status= %d\n", __func__, status);
return status; return status;
......
...@@ -232,12 +232,6 @@ int nfs41_init_clientid(struct nfs_client *clp, struct rpc_cred *cred) ...@@ -232,12 +232,6 @@ int nfs41_init_clientid(struct nfs_client *clp, struct rpc_cred *cred)
status = nfs4_proc_create_session(clp); status = nfs4_proc_create_session(clp);
if (status != 0) if (status != 0)
goto out; goto out;
status = nfs4_set_callback_sessionid(clp);
if (status != 0) {
printk(KERN_WARNING "Sessionid not set. No callback service\n");
nfs_callback_down(1);
status = 0;
}
nfs41_setup_state_renewal(clp); nfs41_setup_state_renewal(clp);
nfs_mark_client_ready(clp, NFS_CS_READY); nfs_mark_client_ready(clp, NFS_CS_READY);
out: out:
......
...@@ -6086,11 +6086,11 @@ int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, ...@@ -6086,11 +6086,11 @@ int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
__be32 *p = xdr_inline_decode(xdr, 4); __be32 *p = xdr_inline_decode(xdr, 4);
if (unlikely(!p)) if (unlikely(!p))
goto out_overflow; goto out_overflow;
if (!ntohl(*p++)) { if (*p == xdr_zero) {
p = xdr_inline_decode(xdr, 4); p = xdr_inline_decode(xdr, 4);
if (unlikely(!p)) if (unlikely(!p))
goto out_overflow; goto out_overflow;
if (!ntohl(*p++)) if (*p == xdr_zero)
return -EAGAIN; return -EAGAIN;
entry->eof = 1; entry->eof = 1;
return -EBADCOOKIE; return -EBADCOOKIE;
...@@ -6101,7 +6101,7 @@ int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, ...@@ -6101,7 +6101,7 @@ int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
goto out_overflow; goto out_overflow;
entry->prev_cookie = entry->cookie; entry->prev_cookie = entry->cookie;
p = xdr_decode_hyper(p, &entry->cookie); p = xdr_decode_hyper(p, &entry->cookie);
entry->len = ntohl(*p++); entry->len = be32_to_cpup(p);
p = xdr_inline_decode(xdr, entry->len); p = xdr_inline_decode(xdr, entry->len);
if (unlikely(!p)) if (unlikely(!p))
...@@ -6132,9 +6132,6 @@ int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, ...@@ -6132,9 +6132,6 @@ int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
if (entry->fattr->valid & NFS_ATTR_FATTR_TYPE) if (entry->fattr->valid & NFS_ATTR_FATTR_TYPE)
entry->d_type = nfs_umode_to_dtype(entry->fattr->mode); entry->d_type = nfs_umode_to_dtype(entry->fattr->mode);
if (verify_attr_len(xdr, p, len) < 0)
goto out_overflow;
return 0; return 0;
out_overflow: out_overflow:
......
...@@ -951,7 +951,7 @@ pnfs_put_deviceid_cache(struct nfs_client *clp) ...@@ -951,7 +951,7 @@ pnfs_put_deviceid_cache(struct nfs_client *clp)
{ {
struct pnfs_deviceid_cache *local = clp->cl_devid_cache; struct pnfs_deviceid_cache *local = clp->cl_devid_cache;
dprintk("--> %s cl_devid_cache %p\n", __func__, clp->cl_devid_cache); dprintk("--> %s ({%d})\n", __func__, atomic_read(&local->dc_ref));
if (atomic_dec_and_lock(&local->dc_ref, &clp->cl_lock)) { if (atomic_dec_and_lock(&local->dc_ref, &clp->cl_lock)) {
int i; int i;
/* Verify cache is empty */ /* Verify cache is empty */
......
...@@ -932,7 +932,7 @@ static int nfs_flush_multi(struct inode *inode, struct list_head *head, unsigned ...@@ -932,7 +932,7 @@ static int nfs_flush_multi(struct inode *inode, struct list_head *head, unsigned
while (!list_empty(&list)) { while (!list_empty(&list)) {
data = list_entry(list.next, struct nfs_write_data, pages); data = list_entry(list.next, struct nfs_write_data, pages);
list_del(&data->pages); list_del(&data->pages);
nfs_writedata_release(data); nfs_writedata_free(data);
} }
nfs_redirty_request(req); nfs_redirty_request(req);
return -ENOMEM; return -ENOMEM;
......
...@@ -42,6 +42,11 @@ struct nfsacl_encode_desc { ...@@ -42,6 +42,11 @@ struct nfsacl_encode_desc {
gid_t gid; gid_t gid;
}; };
struct nfsacl_simple_acl {
struct posix_acl acl;
struct posix_acl_entry ace[4];
};
static int static int
xdr_nfsace_encode(struct xdr_array2_desc *desc, void *elem) xdr_nfsace_encode(struct xdr_array2_desc *desc, void *elem)
{ {
...@@ -72,8 +77,19 @@ xdr_nfsace_encode(struct xdr_array2_desc *desc, void *elem) ...@@ -72,8 +77,19 @@ xdr_nfsace_encode(struct xdr_array2_desc *desc, void *elem)
return 0; return 0;
} }
unsigned int /**
nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode, * nfsacl_encode - Encode an NFSv3 ACL
*
* @buf: destination xdr_buf to contain XDR encoded ACL
* @base: byte offset in xdr_buf where XDR'd ACL begins
* @inode: inode of file whose ACL this is
* @acl: posix_acl to encode
* @encode_entries: whether to encode ACEs as well
* @typeflag: ACL type: NFS_ACL_DEFAULT or zero
*
* Returns size of encoded ACL in bytes or a negative errno value.
*/
int nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode,
struct posix_acl *acl, int encode_entries, int typeflag) struct posix_acl *acl, int encode_entries, int typeflag)
{ {
int entries = (acl && acl->a_count) ? max_t(int, acl->a_count, 4) : 0; int entries = (acl && acl->a_count) ? max_t(int, acl->a_count, 4) : 0;
...@@ -88,17 +104,22 @@ nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode, ...@@ -88,17 +104,22 @@ nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode,
.uid = inode->i_uid, .uid = inode->i_uid,
.gid = inode->i_gid, .gid = inode->i_gid,
}; };
struct nfsacl_simple_acl aclbuf;
int err; int err;
struct posix_acl *acl2 = NULL;
if (entries > NFS_ACL_MAX_ENTRIES || if (entries > NFS_ACL_MAX_ENTRIES ||
xdr_encode_word(buf, base, entries)) xdr_encode_word(buf, base, entries))
return -EINVAL; return -EINVAL;
if (encode_entries && acl && acl->a_count == 3) { if (encode_entries && acl && acl->a_count == 3) {
/* Fake up an ACL_MASK entry. */ struct posix_acl *acl2 = &aclbuf.acl;
acl2 = posix_acl_alloc(4, GFP_KERNEL);
if (!acl2) /* Avoid the use of posix_acl_alloc(). nfsacl_encode() is
return -ENOMEM; * invoked in contexts where a memory allocation failure is
* fatal. Fortunately this fake ACL is small enough to
* construct on the stack. */
memset(acl2, 0, sizeof(acl2));
posix_acl_init(acl2, 4);
/* Insert entries in canonical order: other orders seem /* Insert entries in canonical order: other orders seem
to confuse Solaris VxFS. */ to confuse Solaris VxFS. */
acl2->a_entries[0] = acl->a_entries[0]; /* ACL_USER_OBJ */ acl2->a_entries[0] = acl->a_entries[0]; /* ACL_USER_OBJ */
...@@ -109,8 +130,6 @@ nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode, ...@@ -109,8 +130,6 @@ nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode,
nfsacl_desc.acl = acl2; nfsacl_desc.acl = acl2;
} }
err = xdr_encode_array2(buf, base + 4, &nfsacl_desc.desc); err = xdr_encode_array2(buf, base + 4, &nfsacl_desc.desc);
if (acl2)
posix_acl_release(acl2);
if (!err) if (!err)
err = 8 + nfsacl_desc.desc.elem_size * err = 8 + nfsacl_desc.desc.elem_size *
nfsacl_desc.desc.array_len; nfsacl_desc.desc.array_len;
...@@ -224,8 +243,17 @@ posix_acl_from_nfsacl(struct posix_acl *acl) ...@@ -224,8 +243,17 @@ posix_acl_from_nfsacl(struct posix_acl *acl)
return 0; return 0;
} }
unsigned int /**
nfsacl_decode(struct xdr_buf *buf, unsigned int base, unsigned int *aclcnt, * nfsacl_decode - Decode an NFSv3 ACL
*
* @buf: xdr_buf containing XDR'd ACL data to decode
* @base: byte offset in xdr_buf where XDR'd ACL begins
* @aclcnt: count of ACEs in decoded posix_acl
* @pacl: buffer in which to place decoded posix_acl
*
* Returns the length of the decoded ACL in bytes, or a negative errno value.
*/
int nfsacl_decode(struct xdr_buf *buf, unsigned int base, unsigned int *aclcnt,
struct posix_acl **pacl) struct posix_acl **pacl)
{ {
struct nfsacl_decode_desc nfsacl_desc = { struct nfsacl_decode_desc nfsacl_desc = {
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <linux/errno.h> #include <linux/errno.h>
EXPORT_SYMBOL(posix_acl_init);
EXPORT_SYMBOL(posix_acl_alloc); EXPORT_SYMBOL(posix_acl_alloc);
EXPORT_SYMBOL(posix_acl_clone); EXPORT_SYMBOL(posix_acl_clone);
EXPORT_SYMBOL(posix_acl_valid); EXPORT_SYMBOL(posix_acl_valid);
...@@ -31,6 +32,16 @@ EXPORT_SYMBOL(posix_acl_create_masq); ...@@ -31,6 +32,16 @@ EXPORT_SYMBOL(posix_acl_create_masq);
EXPORT_SYMBOL(posix_acl_chmod_masq); EXPORT_SYMBOL(posix_acl_chmod_masq);
EXPORT_SYMBOL(posix_acl_permission); EXPORT_SYMBOL(posix_acl_permission);
/*
* Init a fresh posix_acl
*/
void
posix_acl_init(struct posix_acl *acl, int count)
{
atomic_set(&acl->a_refcount, 1);
acl->a_count = count;
}
/* /*
* Allocate a new ACL with the specified number of entries. * Allocate a new ACL with the specified number of entries.
*/ */
...@@ -40,10 +51,8 @@ posix_acl_alloc(int count, gfp_t flags) ...@@ -40,10 +51,8 @@ posix_acl_alloc(int count, gfp_t flags)
const size_t size = sizeof(struct posix_acl) + const size_t size = sizeof(struct posix_acl) +
count * sizeof(struct posix_acl_entry); count * sizeof(struct posix_acl_entry);
struct posix_acl *acl = kmalloc(size, flags); struct posix_acl *acl = kmalloc(size, flags);
if (acl) { if (acl)
atomic_set(&acl->a_refcount, 1); posix_acl_init(acl, count);
acl->a_count = count;
}
return acl; return acl;
} }
......
...@@ -51,10 +51,10 @@ nfsacl_size(struct posix_acl *acl_access, struct posix_acl *acl_default) ...@@ -51,10 +51,10 @@ nfsacl_size(struct posix_acl *acl_access, struct posix_acl *acl_default)
return w; return w;
} }
extern unsigned int extern int
nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode, nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode,
struct posix_acl *acl, int encode_entries, int typeflag); struct posix_acl *acl, int encode_entries, int typeflag);
extern unsigned int extern int
nfsacl_decode(struct xdr_buf *buf, unsigned int base, unsigned int *aclcnt, nfsacl_decode(struct xdr_buf *buf, unsigned int base, unsigned int *aclcnt,
struct posix_acl **pacl); struct posix_acl **pacl);
......
...@@ -71,6 +71,7 @@ posix_acl_release(struct posix_acl *acl) ...@@ -71,6 +71,7 @@ posix_acl_release(struct posix_acl *acl)
/* posix_acl.c */ /* posix_acl.c */
extern void posix_acl_init(struct posix_acl *, int);
extern struct posix_acl *posix_acl_alloc(int, gfp_t); extern struct posix_acl *posix_acl_alloc(int, gfp_t);
extern struct posix_acl *posix_acl_clone(const struct posix_acl *, gfp_t); extern struct posix_acl *posix_acl_clone(const struct posix_acl *, gfp_t);
extern int posix_acl_valid(const struct posix_acl *); extern int posix_acl_valid(const struct posix_acl *);
......
...@@ -47,14 +47,6 @@ static inline int svc_is_backchannel(const struct svc_rqst *rqstp) ...@@ -47,14 +47,6 @@ static inline int svc_is_backchannel(const struct svc_rqst *rqstp)
return 1; return 1;
return 0; return 0;
} }
static inline struct nfs4_sessionid *bc_xprt_sid(struct svc_rqst *rqstp)
{
if (svc_is_backchannel(rqstp))
return (struct nfs4_sessionid *)
rqstp->rq_server->sv_bc_xprt->xpt_bc_sid;
return NULL;
}
#else /* CONFIG_NFS_V4_1 */ #else /* CONFIG_NFS_V4_1 */
static inline int xprt_setup_backchannel(struct rpc_xprt *xprt, static inline int xprt_setup_backchannel(struct rpc_xprt *xprt,
unsigned int min_reqs) unsigned int min_reqs)
...@@ -67,11 +59,6 @@ static inline int svc_is_backchannel(const struct svc_rqst *rqstp) ...@@ -67,11 +59,6 @@ static inline int svc_is_backchannel(const struct svc_rqst *rqstp)
return 0; return 0;
} }
static inline struct nfs4_sessionid *bc_xprt_sid(struct svc_rqst *rqstp)
{
return NULL;
}
static inline void xprt_free_bc_request(struct rpc_rqst *req) static inline void xprt_free_bc_request(struct rpc_rqst *req)
{ {
} }
......
...@@ -77,7 +77,6 @@ struct svc_xprt { ...@@ -77,7 +77,6 @@ struct svc_xprt {
size_t xpt_remotelen; /* length of address */ size_t xpt_remotelen; /* length of address */
struct rpc_wait_queue xpt_bc_pending; /* backchannel wait queue */ struct rpc_wait_queue xpt_bc_pending; /* backchannel wait queue */
struct list_head xpt_users; /* callbacks on free */ struct list_head xpt_users; /* callbacks on free */
void *xpt_bc_sid; /* back channel session ID */
struct net *xpt_net; struct net *xpt_net;
struct rpc_xprt *xpt_bc_xprt; /* NFSv4.1 backchannel */ struct rpc_xprt *xpt_bc_xprt; /* NFSv4.1 backchannel */
......
...@@ -1609,9 +1609,7 @@ static struct svc_xprt *svc_bc_create_socket(struct svc_serv *serv, ...@@ -1609,9 +1609,7 @@ static struct svc_xprt *svc_bc_create_socket(struct svc_serv *serv,
*/ */
static void svc_bc_sock_free(struct svc_xprt *xprt) static void svc_bc_sock_free(struct svc_xprt *xprt)
{ {
if (xprt) { if (xprt)
kfree(xprt->xpt_bc_sid);
kfree(container_of(xprt, struct svc_sock, sk_xprt)); kfree(container_of(xprt, struct svc_sock, sk_xprt));
}
} }
#endif /* CONFIG_NFS_V4_1 */ #endif /* CONFIG_NFS_V4_1 */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment