Merge branch 'nfsd-next' of git://linux-nfs.org/~bfields/linux

Pull nfsd updates from Bruce Fields:
 "This was a very quiet cycle! Just a few bugfixes and some cleanup"

* 'nfsd-next' of git://linux-nfs.org/~bfields/linux:
  rpc: let xdr layer allocate gssproxy receieve pages
  rpc: fix huge kmalloc's in gss-proxy
  rpc: comment on linux_cred encoding, treat all as unsigned
  rpc: clean up decoding of gssproxy linux creds
  svcrpc: remove unused rq_resused
  nfsd4: nfsd4_create_clid_dir prints uninitialized data
  nfsd4: fix leak of inode reference on delegation failure
  Revert "nfsd: nfs4_file_get_access: need to be more careful with O_RDWR"
  sunrpc: prepare NFS for 2038
  nfsd4: fix setlease error return
  nfsd: nfs4_file_get_access: need to be more careful with O_RDWR
This commit is contained in:
Linus Torvalds 2013-09-10 20:04:59 -07:00
commit cf596766fc
7 changed files with 91 additions and 39 deletions

View File

@ -173,8 +173,6 @@ nfsd4_create_clid_dir(struct nfs4_client *clp)
int status; int status;
struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
dprintk("NFSD: nfsd4_create_clid_dir for \"%s\"\n", dname);
if (test_and_set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags)) if (test_and_set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
return; return;
if (!nn->rec_file) if (!nn->rec_file)

View File

@ -368,11 +368,8 @@ static struct nfs4_delegation *
alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct svc_fh *current_fh) alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct svc_fh *current_fh)
{ {
struct nfs4_delegation *dp; struct nfs4_delegation *dp;
struct nfs4_file *fp = stp->st_file;
dprintk("NFSD alloc_init_deleg\n"); dprintk("NFSD alloc_init_deleg\n");
if (fp->fi_had_conflict)
return NULL;
if (num_delegations > max_delegations) if (num_delegations > max_delegations)
return NULL; return NULL;
dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab)); dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab));
@ -389,8 +386,7 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct sv
INIT_LIST_HEAD(&dp->dl_perfile); INIT_LIST_HEAD(&dp->dl_perfile);
INIT_LIST_HEAD(&dp->dl_perclnt); INIT_LIST_HEAD(&dp->dl_perclnt);
INIT_LIST_HEAD(&dp->dl_recall_lru); INIT_LIST_HEAD(&dp->dl_recall_lru);
get_nfs4_file(fp); dp->dl_file = NULL;
dp->dl_file = fp;
dp->dl_type = NFS4_OPEN_DELEGATE_READ; dp->dl_type = NFS4_OPEN_DELEGATE_READ;
fh_copy_shallow(&dp->dl_fh, &current_fh->fh_handle); fh_copy_shallow(&dp->dl_fh, &current_fh->fh_handle);
dp->dl_time = 0; dp->dl_time = 0;
@ -3035,7 +3031,7 @@ static int nfs4_setlease(struct nfs4_delegation *dp)
if (status) { if (status) {
list_del_init(&dp->dl_perclnt); list_del_init(&dp->dl_perclnt);
locks_free_lock(fl); locks_free_lock(fl);
return -ENOMEM; return status;
} }
fp->fi_lease = fl; fp->fi_lease = fl;
fp->fi_deleg_file = get_file(fl->fl_file); fp->fi_deleg_file = get_file(fl->fl_file);
@ -3044,22 +3040,35 @@ static int nfs4_setlease(struct nfs4_delegation *dp)
return 0; return 0;
} }
static int nfs4_set_delegation(struct nfs4_delegation *dp) static int nfs4_set_delegation(struct nfs4_delegation *dp, struct nfs4_file *fp)
{ {
struct nfs4_file *fp = dp->dl_file; int status;
if (!fp->fi_lease) if (fp->fi_had_conflict)
return nfs4_setlease(dp); return -EAGAIN;
get_nfs4_file(fp);
dp->dl_file = fp;
if (!fp->fi_lease) {
status = nfs4_setlease(dp);
if (status)
goto out_free;
return 0;
}
spin_lock(&recall_lock); spin_lock(&recall_lock);
if (fp->fi_had_conflict) { if (fp->fi_had_conflict) {
spin_unlock(&recall_lock); spin_unlock(&recall_lock);
return -EAGAIN; status = -EAGAIN;
goto out_free;
} }
atomic_inc(&fp->fi_delegees); atomic_inc(&fp->fi_delegees);
list_add(&dp->dl_perfile, &fp->fi_delegations); list_add(&dp->dl_perfile, &fp->fi_delegations);
spin_unlock(&recall_lock); spin_unlock(&recall_lock);
list_add(&dp->dl_perclnt, &dp->dl_stid.sc_client->cl_delegations); list_add(&dp->dl_perclnt, &dp->dl_stid.sc_client->cl_delegations);
return 0; return 0;
out_free:
put_nfs4_file(fp);
dp->dl_file = fp;
return status;
} }
static void nfsd4_open_deleg_none_ext(struct nfsd4_open *open, int status) static void nfsd4_open_deleg_none_ext(struct nfsd4_open *open, int status)
@ -3134,7 +3143,7 @@ nfs4_open_delegation(struct net *net, struct svc_fh *fh,
dp = alloc_init_deleg(oo->oo_owner.so_client, stp, fh); dp = alloc_init_deleg(oo->oo_owner.so_client, stp, fh);
if (dp == NULL) if (dp == NULL)
goto out_no_deleg; goto out_no_deleg;
status = nfs4_set_delegation(dp); status = nfs4_set_delegation(dp, stp->st_file);
if (status) if (status)
goto out_free; goto out_free;

View File

@ -264,12 +264,30 @@ static inline int get_uint(char **bpp, unsigned int *anint)
return 0; return 0;
} }
static inline int get_time(char **bpp, time_t *time)
{
char buf[50];
long long ll;
int len = qword_get(bpp, buf, sizeof(buf));
if (len < 0)
return -EINVAL;
if (len == 0)
return -ENOENT;
if (kstrtoll(buf, 0, &ll))
return -EINVAL;
*time = (time_t)ll;
return 0;
}
static inline time_t get_expiry(char **bpp) static inline time_t get_expiry(char **bpp)
{ {
int rv; time_t rv;
struct timespec boot; struct timespec boot;
if (get_int(bpp, &rv)) if (get_time(bpp, &rv))
return 0; return 0;
if (rv < 0) if (rv < 0)
return 0; return 0;

View File

@ -243,7 +243,6 @@ struct svc_rqst {
struct xdr_buf rq_res; struct xdr_buf rq_res;
struct page * rq_pages[RPCSVC_MAXPAGES]; struct page * rq_pages[RPCSVC_MAXPAGES];
struct page * *rq_respages; /* points into rq_pages */ struct page * *rq_respages; /* points into rq_pages */
int rq_resused; /* number of pages used for result */
struct page * *rq_next_page; /* next reply page to use */ struct page * *rq_next_page; /* next reply page to use */
struct kvec rq_vec[RPCSVC_MAXPAGES]; /* generally useful.. */ struct kvec rq_vec[RPCSVC_MAXPAGES]; /* generally useful.. */

View File

@ -213,6 +213,26 @@ static int gssp_call(struct net *net, struct rpc_message *msg)
return status; return status;
} }
static void gssp_free_receive_pages(struct gssx_arg_accept_sec_context *arg)
{
int i;
for (i = 0; i < arg->npages && arg->pages[i]; i++)
__free_page(arg->pages[i]);
}
static int gssp_alloc_receive_pages(struct gssx_arg_accept_sec_context *arg)
{
arg->npages = DIV_ROUND_UP(NGROUPS_MAX * 4, PAGE_SIZE);
arg->pages = kzalloc(arg->npages * sizeof(struct page *), GFP_KERNEL);
/*
* XXX: actual pages are allocated by xdr layer in
* xdr_partial_copy_from_skb.
*/
if (!arg->pages)
return -ENOMEM;
return 0;
}
/* /*
* Public functions * Public functions
@ -261,10 +281,16 @@ int gssp_accept_sec_context_upcall(struct net *net,
arg.context_handle = &ctxh; arg.context_handle = &ctxh;
res.output_token->len = GSSX_max_output_token_sz; res.output_token->len = GSSX_max_output_token_sz;
ret = gssp_alloc_receive_pages(&arg);
if (ret)
return ret;
/* use nfs/ for targ_name ? */ /* use nfs/ for targ_name ? */
ret = gssp_call(net, &msg); ret = gssp_call(net, &msg);
gssp_free_receive_pages(&arg);
/* we need to fetch all data even in case of error so /* we need to fetch all data even in case of error so
* that we can free special strctures is they have been allocated */ * that we can free special strctures is they have been allocated */
data->major_status = res.status.major_status; data->major_status = res.status.major_status;

View File

@ -166,14 +166,15 @@ static int dummy_dec_opt_array(struct xdr_stream *xdr,
return 0; return 0;
} }
static int get_s32(void **p, void *max, s32 *res) static int get_host_u32(struct xdr_stream *xdr, u32 *res)
{ {
void *base = *p; __be32 *p;
void *next = (void *)((char *)base + sizeof(s32));
if (unlikely(next > max || next < base)) p = xdr_inline_decode(xdr, 4);
if (!p)
return -EINVAL; return -EINVAL;
memcpy(res, base, sizeof(s32)); /* Contents of linux creds are all host-endian: */
*p = next; memcpy(res, p, sizeof(u32));
return 0; return 0;
} }
@ -182,9 +183,9 @@ static int gssx_dec_linux_creds(struct xdr_stream *xdr,
{ {
u32 length; u32 length;
__be32 *p; __be32 *p;
void *q, *end; u32 tmp;
s32 tmp; u32 N;
int N, i, err; int i, err;
p = xdr_inline_decode(xdr, 4); p = xdr_inline_decode(xdr, 4);
if (unlikely(p == NULL)) if (unlikely(p == NULL))
@ -192,33 +193,28 @@ static int gssx_dec_linux_creds(struct xdr_stream *xdr,
length = be32_to_cpup(p); length = be32_to_cpup(p);
/* FIXME: we do not want to use the scratch buffer for this one if (length > (3 + NGROUPS_MAX) * sizeof(u32))
* may need to use functions that allows us to access an io vector
* directly */
p = xdr_inline_decode(xdr, length);
if (unlikely(p == NULL))
return -ENOSPC; return -ENOSPC;
q = p;
end = q + length;
/* uid */ /* uid */
err = get_s32(&q, end, &tmp); err = get_host_u32(xdr, &tmp);
if (err) if (err)
return err; return err;
creds->cr_uid = make_kuid(&init_user_ns, tmp); creds->cr_uid = make_kuid(&init_user_ns, tmp);
/* gid */ /* gid */
err = get_s32(&q, end, &tmp); err = get_host_u32(xdr, &tmp);
if (err) if (err)
return err; return err;
creds->cr_gid = make_kgid(&init_user_ns, tmp); creds->cr_gid = make_kgid(&init_user_ns, tmp);
/* number of additional gid's */ /* number of additional gid's */
err = get_s32(&q, end, &tmp); err = get_host_u32(xdr, &tmp);
if (err) if (err)
return err; return err;
N = tmp; N = tmp;
if ((3 + N) * sizeof(u32) != length)
return -EINVAL;
creds->cr_group_info = groups_alloc(N); creds->cr_group_info = groups_alloc(N);
if (creds->cr_group_info == NULL) if (creds->cr_group_info == NULL)
return -ENOMEM; return -ENOMEM;
@ -226,7 +222,7 @@ static int gssx_dec_linux_creds(struct xdr_stream *xdr,
/* gid's */ /* gid's */
for (i = 0; i < N; i++) { for (i = 0; i < N; i++) {
kgid_t kgid; kgid_t kgid;
err = get_s32(&q, end, &tmp); err = get_host_u32(xdr, &tmp);
if (err) if (err)
goto out_free_groups; goto out_free_groups;
err = -EINVAL; err = -EINVAL;
@ -784,6 +780,9 @@ void gssx_enc_accept_sec_context(struct rpc_rqst *req,
/* arg->options */ /* arg->options */
err = dummy_enc_opt_array(xdr, &arg->options); err = dummy_enc_opt_array(xdr, &arg->options);
xdr_inline_pages(&req->rq_rcv_buf,
PAGE_SIZE/2 /* pretty arbitrary */,
arg->pages, 0 /* page base */, arg->npages * PAGE_SIZE);
done: done:
if (err) if (err)
dprintk("RPC: gssx_enc_accept_sec_context: %d\n", err); dprintk("RPC: gssx_enc_accept_sec_context: %d\n", err);

View File

@ -147,6 +147,8 @@ struct gssx_arg_accept_sec_context {
struct gssx_cb *input_cb; struct gssx_cb *input_cb;
u32 ret_deleg_cred; u32 ret_deleg_cred;
struct gssx_option_array options; struct gssx_option_array options;
struct page **pages;
unsigned int npages;
}; };
struct gssx_res_accept_sec_context { struct gssx_res_accept_sec_context {
@ -240,7 +242,8 @@ int gssx_dec_accept_sec_context(struct rpc_rqst *rqstp,
2 * GSSX_max_princ_sz + \ 2 * GSSX_max_princ_sz + \
8 + 8 + 4 + 4 + 4) 8 + 8 + 4 + 4 + 4)
#define GSSX_max_output_token_sz 1024 #define GSSX_max_output_token_sz 1024
#define GSSX_max_creds_sz (4 + 4 + 4 + NGROUPS_MAX * 4) /* grouplist not included; we allocate separate pages for that: */
#define GSSX_max_creds_sz (4 + 4 + 4 /* + NGROUPS_MAX*4 */)
#define GSSX_RES_accept_sec_context_sz (GSSX_default_status_sz + \ #define GSSX_RES_accept_sec_context_sz (GSSX_default_status_sz + \
GSSX_default_ctx_sz + \ GSSX_default_ctx_sz + \
GSSX_max_output_token_sz + \ GSSX_max_output_token_sz + \