mirror of
https://github.com/torvalds/linux.git
synced 2024-12-26 12:52:30 +00:00
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:
commit
cf596766fc
@ -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)
|
||||||
|
@ -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, ¤t_fh->fh_handle);
|
fh_copy_shallow(&dp->dl_fh, ¤t_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;
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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.. */
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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 + \
|
||||||
|
Loading…
Reference in New Issue
Block a user