Merge branch 'for-3.11' of git://linux-nfs.org/~bfields/linux
Pull nfsd changes from Bruce Fields: "Changes this time include: - 4.1 enabled on the server by default: the last 4.1-specific issues I know of are fixed, so we're not going to find the rest of the bugs without more exposure. - Experimental support for NFSv4.2 MAC Labeling (to allow running selinux over NFS), from Dave Quigley. - Fixes for some delicate cache/upcall races that could cause rare server hangs; thanks to Neil Brown and Bodo Stroesser for extreme debugging persistence. - Fixes for some bugs found at the recent NFS bakeathon, mostly v4 and v4.1-specific, but also a generic bug handling fragmented rpc calls" * 'for-3.11' of git://linux-nfs.org/~bfields/linux: (31 commits) nfsd4: support minorversion 1 by default nfsd4: allow destroy_session over destroyed session svcrpc: fix failures to handle -1 uid's sunrpc: Don't schedule an upcall on a replaced cache entry. net/sunrpc: xpt_auth_cache should be ignored when expired. sunrpc/cache: ensure items removed from cache do not have pending upcalls. sunrpc/cache: use cache_fresh_unlocked consistently and correctly. sunrpc/cache: remove races with queuing an upcall. nfsd4: return delegation immediately if lease fails nfsd4: do not throw away 4.1 lock state on last unlock nfsd4: delegation-based open reclaims should bypass permissions svcrpc: don't error out on small tcp fragment svcrpc: fix handling of too-short rpc's nfsd4: minor read_buf cleanup nfsd4: fix decoding of compounds across page boundaries nfsd4: clean up nfs4_open_delegation NFSD: Don't give out read delegations on creates nfsd4: allow client to send no cb_sec flavors nfsd4: fail attempts to request gss on the backchannel nfsd4: implement minimal SP4_MACH_CRED ...
This commit is contained in:
@@ -81,6 +81,22 @@ config NFSD_V4
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config NFSD_V4_SECURITY_LABEL
|
||||
bool "Provide Security Label support for NFSv4 server"
|
||||
depends on NFSD_V4 && SECURITY
|
||||
help
|
||||
|
||||
Say Y here if you want enable fine-grained security label attribute
|
||||
support for NFS version 4. Security labels allow security modules like
|
||||
SELinux and Smack to label files to facilitate enforcement of their policies.
|
||||
Without this an NFSv4 mount will have the same label on each file.
|
||||
|
||||
If you do not wish to enable fine-grained security labels SELinux or
|
||||
Smack policies on NFSv4 files, say N.
|
||||
|
||||
WARNING: there is still a chance of backwards-incompatible protocol changes.
|
||||
For now we recommend "Y" only for developers and testers."
|
||||
|
||||
config NFSD_FAULT_INJECTION
|
||||
bool "NFS server manual fault injection"
|
||||
depends on NFSD_V4 && DEBUG_KERNEL
|
||||
|
@@ -42,6 +42,36 @@
|
||||
#include "current_stateid.h"
|
||||
#include "netns.h"
|
||||
|
||||
#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
|
||||
#include <linux/security.h>
|
||||
|
||||
static inline void
|
||||
nfsd4_security_inode_setsecctx(struct svc_fh *resfh, struct xdr_netobj *label, u32 *bmval)
|
||||
{
|
||||
struct inode *inode = resfh->fh_dentry->d_inode;
|
||||
int status;
|
||||
|
||||
mutex_lock(&inode->i_mutex);
|
||||
status = security_inode_setsecctx(resfh->fh_dentry,
|
||||
label->data, label->len);
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
|
||||
if (status)
|
||||
/*
|
||||
* XXX: We should really fail the whole open, but we may
|
||||
* already have created a new file, so it may be too
|
||||
* late. For now this seems the least of evils:
|
||||
*/
|
||||
bmval[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
|
||||
|
||||
return;
|
||||
}
|
||||
#else
|
||||
static inline void
|
||||
nfsd4_security_inode_setsecctx(struct svc_fh *resfh, struct xdr_netobj *label, u32 *bmval)
|
||||
{ }
|
||||
#endif
|
||||
|
||||
#define NFSDDBG_FACILITY NFSDDBG_PROC
|
||||
|
||||
static u32 nfsd_attrmask[] = {
|
||||
@@ -239,6 +269,9 @@ do_open_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, stru
|
||||
(u32 *)open->op_verf.data,
|
||||
&open->op_truncate, &open->op_created);
|
||||
|
||||
if (!status && open->op_label.len)
|
||||
nfsd4_security_inode_setsecctx(resfh, &open->op_label, open->op_bmval);
|
||||
|
||||
/*
|
||||
* Following rfc 3530 14.2.16, use the returned bitmask
|
||||
* to indicate which attributes we used to store the
|
||||
@@ -263,7 +296,8 @@ do_open_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, stru
|
||||
|
||||
nfsd4_set_open_owner_reply_cache(cstate, open, resfh);
|
||||
accmode = NFSD_MAY_NOP;
|
||||
if (open->op_created)
|
||||
if (open->op_created ||
|
||||
open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR)
|
||||
accmode |= NFSD_MAY_OWNER_OVERRIDE;
|
||||
status = do_open_permission(rqstp, resfh, open, accmode);
|
||||
set_change_info(&open->op_cinfo, current_fh);
|
||||
@@ -637,6 +671,9 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
if (status)
|
||||
goto out;
|
||||
|
||||
if (create->cr_label.len)
|
||||
nfsd4_security_inode_setsecctx(&resfh, &create->cr_label, create->cr_bmval);
|
||||
|
||||
if (create->cr_acl != NULL)
|
||||
do_set_nfs4_acl(rqstp, &resfh, create->cr_acl,
|
||||
create->cr_bmval);
|
||||
@@ -916,6 +953,11 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
setattr->sa_acl);
|
||||
if (status)
|
||||
goto out;
|
||||
if (setattr->sa_label.len)
|
||||
status = nfsd4_set_nfs4_label(rqstp, &cstate->current_fh,
|
||||
&setattr->sa_label);
|
||||
if (status)
|
||||
goto out;
|
||||
status = nfsd_setattr(rqstp, &cstate->current_fh, &setattr->sa_iattr,
|
||||
0, (time_t)0);
|
||||
out:
|
||||
|
@@ -97,19 +97,20 @@ nfs4_lock_state(void)
|
||||
|
||||
static void free_session(struct nfsd4_session *);
|
||||
|
||||
void nfsd4_put_session(struct nfsd4_session *ses)
|
||||
{
|
||||
atomic_dec(&ses->se_ref);
|
||||
}
|
||||
|
||||
static bool is_session_dead(struct nfsd4_session *ses)
|
||||
{
|
||||
return ses->se_flags & NFS4_SESSION_DEAD;
|
||||
}
|
||||
|
||||
static __be32 mark_session_dead_locked(struct nfsd4_session *ses)
|
||||
void nfsd4_put_session(struct nfsd4_session *ses)
|
||||
{
|
||||
if (atomic_read(&ses->se_ref))
|
||||
if (atomic_dec_and_test(&ses->se_ref) && is_session_dead(ses))
|
||||
free_session(ses);
|
||||
}
|
||||
|
||||
static __be32 mark_session_dead_locked(struct nfsd4_session *ses, int ref_held_by_me)
|
||||
{
|
||||
if (atomic_read(&ses->se_ref) > ref_held_by_me)
|
||||
return nfserr_jukebox;
|
||||
ses->se_flags |= NFS4_SESSION_DEAD;
|
||||
return nfs_ok;
|
||||
@@ -364,19 +365,12 @@ static struct nfs4_ol_stateid * nfs4_alloc_stateid(struct nfs4_client *clp)
|
||||
}
|
||||
|
||||
static struct nfs4_delegation *
|
||||
alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct svc_fh *current_fh, u32 type)
|
||||
alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct svc_fh *current_fh)
|
||||
{
|
||||
struct nfs4_delegation *dp;
|
||||
struct nfs4_file *fp = stp->st_file;
|
||||
|
||||
dprintk("NFSD alloc_init_deleg\n");
|
||||
/*
|
||||
* Major work on the lease subsystem (for example, to support
|
||||
* calbacks on stat) will be required before we can support
|
||||
* write delegations properly.
|
||||
*/
|
||||
if (type != NFS4_OPEN_DELEGATE_READ)
|
||||
return NULL;
|
||||
if (fp->fi_had_conflict)
|
||||
return NULL;
|
||||
if (num_delegations > max_delegations)
|
||||
@@ -397,7 +391,7 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct sv
|
||||
INIT_LIST_HEAD(&dp->dl_recall_lru);
|
||||
get_nfs4_file(fp);
|
||||
dp->dl_file = fp;
|
||||
dp->dl_type = type;
|
||||
dp->dl_type = NFS4_OPEN_DELEGATE_READ;
|
||||
fh_copy_shallow(&dp->dl_fh, ¤t_fh->fh_handle);
|
||||
dp->dl_time = 0;
|
||||
atomic_set(&dp->dl_count, 1);
|
||||
@@ -1188,6 +1182,9 @@ static int copy_cred(struct svc_cred *target, struct svc_cred *source)
|
||||
target->cr_gid = source->cr_gid;
|
||||
target->cr_group_info = source->cr_group_info;
|
||||
get_group_info(target->cr_group_info);
|
||||
target->cr_gss_mech = source->cr_gss_mech;
|
||||
if (source->cr_gss_mech)
|
||||
gss_mech_get(source->cr_gss_mech);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1262,6 +1259,31 @@ same_creds(struct svc_cred *cr1, struct svc_cred *cr2)
|
||||
return 0 == strcmp(cr1->cr_principal, cr2->cr_principal);
|
||||
}
|
||||
|
||||
static bool svc_rqst_integrity_protected(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct svc_cred *cr = &rqstp->rq_cred;
|
||||
u32 service;
|
||||
|
||||
service = gss_pseudoflavor_to_service(cr->cr_gss_mech, cr->cr_flavor);
|
||||
return service == RPC_GSS_SVC_INTEGRITY ||
|
||||
service == RPC_GSS_SVC_PRIVACY;
|
||||
}
|
||||
|
||||
static bool mach_creds_match(struct nfs4_client *cl, struct svc_rqst *rqstp)
|
||||
{
|
||||
struct svc_cred *cr = &rqstp->rq_cred;
|
||||
|
||||
if (!cl->cl_mach_cred)
|
||||
return true;
|
||||
if (cl->cl_cred.cr_gss_mech != cr->cr_gss_mech)
|
||||
return false;
|
||||
if (!svc_rqst_integrity_protected(rqstp))
|
||||
return false;
|
||||
if (!cr->cr_principal)
|
||||
return false;
|
||||
return 0 == strcmp(cl->cl_cred.cr_principal, cr->cr_principal);
|
||||
}
|
||||
|
||||
static void gen_clid(struct nfs4_client *clp, struct nfsd_net *nn)
|
||||
{
|
||||
static u32 current_clientid = 1;
|
||||
@@ -1639,16 +1661,16 @@ nfsd4_exchange_id(struct svc_rqst *rqstp,
|
||||
if (exid->flags & ~EXCHGID4_FLAG_MASK_A)
|
||||
return nfserr_inval;
|
||||
|
||||
/* Currently only support SP4_NONE */
|
||||
switch (exid->spa_how) {
|
||||
case SP4_MACH_CRED:
|
||||
if (!svc_rqst_integrity_protected(rqstp))
|
||||
return nfserr_inval;
|
||||
case SP4_NONE:
|
||||
break;
|
||||
default: /* checked by xdr code */
|
||||
WARN_ON_ONCE(1);
|
||||
case SP4_SSV:
|
||||
return nfserr_encr_alg_unsupp;
|
||||
case SP4_MACH_CRED:
|
||||
return nfserr_serverfault; /* no excuse :-/ */
|
||||
}
|
||||
|
||||
/* Cases below refer to rfc 5661 section 18.35.4: */
|
||||
@@ -1663,6 +1685,10 @@ nfsd4_exchange_id(struct svc_rqst *rqstp,
|
||||
status = nfserr_inval;
|
||||
goto out;
|
||||
}
|
||||
if (!mach_creds_match(conf, rqstp)) {
|
||||
status = nfserr_wrong_cred;
|
||||
goto out;
|
||||
}
|
||||
if (!creds_match) { /* case 9 */
|
||||
status = nfserr_perm;
|
||||
goto out;
|
||||
@@ -1709,7 +1735,8 @@ out_new:
|
||||
status = nfserr_jukebox;
|
||||
goto out;
|
||||
}
|
||||
new->cl_minorversion = 1;
|
||||
new->cl_minorversion = cstate->minorversion;
|
||||
new->cl_mach_cred = (exid->spa_how == SP4_MACH_CRED);
|
||||
|
||||
gen_clid(new, nn);
|
||||
add_to_unconfirmed(new);
|
||||
@@ -1839,6 +1866,24 @@ static __be32 check_backchannel_attrs(struct nfsd4_channel_attrs *ca)
|
||||
return nfs_ok;
|
||||
}
|
||||
|
||||
static __be32 nfsd4_check_cb_sec(struct nfsd4_cb_sec *cbs)
|
||||
{
|
||||
switch (cbs->flavor) {
|
||||
case RPC_AUTH_NULL:
|
||||
case RPC_AUTH_UNIX:
|
||||
return nfs_ok;
|
||||
default:
|
||||
/*
|
||||
* GSS case: the spec doesn't allow us to return this
|
||||
* error. But it also doesn't allow us not to support
|
||||
* GSS.
|
||||
* I'd rather this fail hard than return some error the
|
||||
* client might think it can already handle:
|
||||
*/
|
||||
return nfserr_encr_alg_unsupp;
|
||||
}
|
||||
}
|
||||
|
||||
__be32
|
||||
nfsd4_create_session(struct svc_rqst *rqstp,
|
||||
struct nfsd4_compound_state *cstate,
|
||||
@@ -1854,6 +1899,9 @@ nfsd4_create_session(struct svc_rqst *rqstp,
|
||||
|
||||
if (cr_ses->flags & ~SESSION4_FLAG_MASK_A)
|
||||
return nfserr_inval;
|
||||
status = nfsd4_check_cb_sec(&cr_ses->cb_sec);
|
||||
if (status)
|
||||
return status;
|
||||
status = check_forechannel_attrs(&cr_ses->fore_channel, nn);
|
||||
if (status)
|
||||
return status;
|
||||
@@ -1874,6 +1922,9 @@ nfsd4_create_session(struct svc_rqst *rqstp,
|
||||
WARN_ON_ONCE(conf && unconf);
|
||||
|
||||
if (conf) {
|
||||
status = nfserr_wrong_cred;
|
||||
if (!mach_creds_match(conf, rqstp))
|
||||
goto out_free_conn;
|
||||
cs_slot = &conf->cl_cs_slot;
|
||||
status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0);
|
||||
if (status == nfserr_replay_cache) {
|
||||
@@ -1890,6 +1941,9 @@ nfsd4_create_session(struct svc_rqst *rqstp,
|
||||
status = nfserr_clid_inuse;
|
||||
goto out_free_conn;
|
||||
}
|
||||
status = nfserr_wrong_cred;
|
||||
if (!mach_creds_match(unconf, rqstp))
|
||||
goto out_free_conn;
|
||||
cs_slot = &unconf->cl_cs_slot;
|
||||
status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0);
|
||||
if (status) {
|
||||
@@ -1957,7 +2011,11 @@ __be32 nfsd4_backchannel_ctl(struct svc_rqst *rqstp, struct nfsd4_compound_state
|
||||
{
|
||||
struct nfsd4_session *session = cstate->session;
|
||||
struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
|
||||
__be32 status;
|
||||
|
||||
status = nfsd4_check_cb_sec(&bc->bc_cb_sec);
|
||||
if (status)
|
||||
return status;
|
||||
spin_lock(&nn->client_lock);
|
||||
session->se_cb_prog = bc->bc_cb_program;
|
||||
session->se_cb_sec = bc->bc_cb_sec;
|
||||
@@ -1986,6 +2044,9 @@ __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp,
|
||||
status = nfserr_badsession;
|
||||
if (!session)
|
||||
goto out;
|
||||
status = nfserr_wrong_cred;
|
||||
if (!mach_creds_match(session->se_client, rqstp))
|
||||
goto out;
|
||||
status = nfsd4_map_bcts_dir(&bcts->dir);
|
||||
if (status)
|
||||
goto out;
|
||||
@@ -2014,6 +2075,7 @@ nfsd4_destroy_session(struct svc_rqst *r,
|
||||
{
|
||||
struct nfsd4_session *ses;
|
||||
__be32 status;
|
||||
int ref_held_by_me = 0;
|
||||
struct nfsd_net *nn = net_generic(SVC_NET(r), nfsd_net_id);
|
||||
|
||||
nfs4_lock_state();
|
||||
@@ -2021,6 +2083,7 @@ nfsd4_destroy_session(struct svc_rqst *r,
|
||||
if (nfsd4_compound_in_session(cstate->session, &sessionid->sessionid)) {
|
||||
if (!nfsd4_last_compound_op(r))
|
||||
goto out;
|
||||
ref_held_by_me++;
|
||||
}
|
||||
dump_sessionid(__func__, &sessionid->sessionid);
|
||||
spin_lock(&nn->client_lock);
|
||||
@@ -2028,17 +2091,22 @@ nfsd4_destroy_session(struct svc_rqst *r,
|
||||
status = nfserr_badsession;
|
||||
if (!ses)
|
||||
goto out_client_lock;
|
||||
status = mark_session_dead_locked(ses);
|
||||
if (status)
|
||||
status = nfserr_wrong_cred;
|
||||
if (!mach_creds_match(ses->se_client, r))
|
||||
goto out_client_lock;
|
||||
nfsd4_get_session_locked(ses);
|
||||
status = mark_session_dead_locked(ses, 1 + ref_held_by_me);
|
||||
if (status)
|
||||
goto out_put_session;
|
||||
unhash_session(ses);
|
||||
spin_unlock(&nn->client_lock);
|
||||
|
||||
nfsd4_probe_callback_sync(ses->se_client);
|
||||
|
||||
spin_lock(&nn->client_lock);
|
||||
free_session(ses);
|
||||
status = nfs_ok;
|
||||
out_put_session:
|
||||
nfsd4_put_session(ses);
|
||||
out_client_lock:
|
||||
spin_unlock(&nn->client_lock);
|
||||
out:
|
||||
@@ -2058,26 +2126,31 @@ static struct nfsd4_conn *__nfsd4_find_conn(struct svc_xprt *xpt, struct nfsd4_s
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void nfsd4_sequence_check_conn(struct nfsd4_conn *new, struct nfsd4_session *ses)
|
||||
static __be32 nfsd4_sequence_check_conn(struct nfsd4_conn *new, struct nfsd4_session *ses)
|
||||
{
|
||||
struct nfs4_client *clp = ses->se_client;
|
||||
struct nfsd4_conn *c;
|
||||
__be32 status = nfs_ok;
|
||||
int ret;
|
||||
|
||||
spin_lock(&clp->cl_lock);
|
||||
c = __nfsd4_find_conn(new->cn_xprt, ses);
|
||||
if (c) {
|
||||
spin_unlock(&clp->cl_lock);
|
||||
free_conn(new);
|
||||
return;
|
||||
}
|
||||
if (c)
|
||||
goto out_free;
|
||||
status = nfserr_conn_not_bound_to_session;
|
||||
if (clp->cl_mach_cred)
|
||||
goto out_free;
|
||||
__nfsd4_hash_conn(new, ses);
|
||||
spin_unlock(&clp->cl_lock);
|
||||
ret = nfsd4_register_conn(new);
|
||||
if (ret)
|
||||
/* oops; xprt is already down: */
|
||||
nfsd4_conn_lost(&new->cn_xpt_user);
|
||||
return;
|
||||
return nfs_ok;
|
||||
out_free:
|
||||
spin_unlock(&clp->cl_lock);
|
||||
free_conn(new);
|
||||
return status;
|
||||
}
|
||||
|
||||
static bool nfsd4_session_too_many_ops(struct svc_rqst *rqstp, struct nfsd4_session *session)
|
||||
@@ -2169,8 +2242,10 @@ nfsd4_sequence(struct svc_rqst *rqstp,
|
||||
if (status)
|
||||
goto out_put_session;
|
||||
|
||||
nfsd4_sequence_check_conn(conn, session);
|
||||
status = nfsd4_sequence_check_conn(conn, session);
|
||||
conn = NULL;
|
||||
if (status)
|
||||
goto out_put_session;
|
||||
|
||||
/* Success! bump slot seqid */
|
||||
slot->sl_seqid = seq->seqid;
|
||||
@@ -2232,7 +2307,10 @@ nfsd4_destroy_clientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *csta
|
||||
status = nfserr_stale_clientid;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!mach_creds_match(clp, rqstp)) {
|
||||
status = nfserr_wrong_cred;
|
||||
goto out;
|
||||
}
|
||||
expire_client(clp);
|
||||
out:
|
||||
nfs4_unlock_state();
|
||||
@@ -2940,13 +3018,13 @@ static struct file_lock *nfs4_alloc_init_lease(struct nfs4_delegation *dp, int f
|
||||
return fl;
|
||||
}
|
||||
|
||||
static int nfs4_setlease(struct nfs4_delegation *dp, int flag)
|
||||
static int nfs4_setlease(struct nfs4_delegation *dp)
|
||||
{
|
||||
struct nfs4_file *fp = dp->dl_file;
|
||||
struct file_lock *fl;
|
||||
int status;
|
||||
|
||||
fl = nfs4_alloc_init_lease(dp, flag);
|
||||
fl = nfs4_alloc_init_lease(dp, NFS4_OPEN_DELEGATE_READ);
|
||||
if (!fl)
|
||||
return -ENOMEM;
|
||||
fl->fl_file = find_readable_file(fp);
|
||||
@@ -2964,12 +3042,12 @@ static int nfs4_setlease(struct nfs4_delegation *dp, int flag)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nfs4_set_delegation(struct nfs4_delegation *dp, int flag)
|
||||
static int nfs4_set_delegation(struct nfs4_delegation *dp)
|
||||
{
|
||||
struct nfs4_file *fp = dp->dl_file;
|
||||
|
||||
if (!fp->fi_lease)
|
||||
return nfs4_setlease(dp, flag);
|
||||
return nfs4_setlease(dp);
|
||||
spin_lock(&recall_lock);
|
||||
if (fp->fi_had_conflict) {
|
||||
spin_unlock(&recall_lock);
|
||||
@@ -3005,6 +3083,9 @@ static void nfsd4_open_deleg_none_ext(struct nfsd4_open *open, int status)
|
||||
|
||||
/*
|
||||
* Attempt to hand out a delegation.
|
||||
*
|
||||
* Note we don't support write delegations, and won't until the vfs has
|
||||
* proper support for them.
|
||||
*/
|
||||
static void
|
||||
nfs4_open_delegation(struct net *net, struct svc_fh *fh,
|
||||
@@ -3013,39 +3094,45 @@ nfs4_open_delegation(struct net *net, struct svc_fh *fh,
|
||||
struct nfs4_delegation *dp;
|
||||
struct nfs4_openowner *oo = container_of(stp->st_stateowner, struct nfs4_openowner, oo_owner);
|
||||
int cb_up;
|
||||
int status = 0, flag = 0;
|
||||
int status = 0;
|
||||
|
||||
cb_up = nfsd4_cb_channel_good(oo->oo_owner.so_client);
|
||||
flag = NFS4_OPEN_DELEGATE_NONE;
|
||||
open->op_recall = 0;
|
||||
switch (open->op_claim_type) {
|
||||
case NFS4_OPEN_CLAIM_PREVIOUS:
|
||||
if (!cb_up)
|
||||
open->op_recall = 1;
|
||||
flag = open->op_delegate_type;
|
||||
if (flag == NFS4_OPEN_DELEGATE_NONE)
|
||||
goto out;
|
||||
if (open->op_delegate_type != NFS4_OPEN_DELEGATE_READ)
|
||||
goto out_no_deleg;
|
||||
break;
|
||||
case NFS4_OPEN_CLAIM_NULL:
|
||||
/* Let's not give out any delegations till everyone's
|
||||
* had the chance to reclaim theirs.... */
|
||||
/*
|
||||
* Let's not give out any delegations till everyone's
|
||||
* had the chance to reclaim theirs....
|
||||
*/
|
||||
if (locks_in_grace(net))
|
||||
goto out;
|
||||
goto out_no_deleg;
|
||||
if (!cb_up || !(oo->oo_flags & NFS4_OO_CONFIRMED))
|
||||
goto out;
|
||||
goto out_no_deleg;
|
||||
/*
|
||||
* Also, if the file was opened for write or
|
||||
* create, there's a good chance the client's
|
||||
* about to write to it, resulting in an
|
||||
* immediate recall (since we don't support
|
||||
* write delegations):
|
||||
*/
|
||||
if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE)
|
||||
flag = NFS4_OPEN_DELEGATE_WRITE;
|
||||
else
|
||||
flag = NFS4_OPEN_DELEGATE_READ;
|
||||
goto out_no_deleg;
|
||||
if (open->op_create == NFS4_OPEN_CREATE)
|
||||
goto out_no_deleg;
|
||||
break;
|
||||
default:
|
||||
goto out;
|
||||
goto out_no_deleg;
|
||||
}
|
||||
|
||||
dp = alloc_init_deleg(oo->oo_owner.so_client, stp, fh, flag);
|
||||
dp = alloc_init_deleg(oo->oo_owner.so_client, stp, fh);
|
||||
if (dp == NULL)
|
||||
goto out_no_deleg;
|
||||
status = nfs4_set_delegation(dp, flag);
|
||||
status = nfs4_set_delegation(dp);
|
||||
if (status)
|
||||
goto out_free;
|
||||
|
||||
@@ -3053,24 +3140,23 @@ nfs4_open_delegation(struct net *net, struct svc_fh *fh,
|
||||
|
||||
dprintk("NFSD: delegation stateid=" STATEID_FMT "\n",
|
||||
STATEID_VAL(&dp->dl_stid.sc_stateid));
|
||||
out:
|
||||
open->op_delegate_type = flag;
|
||||
if (flag == NFS4_OPEN_DELEGATE_NONE) {
|
||||
if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS &&
|
||||
open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE)
|
||||
dprintk("NFSD: WARNING: refusing delegation reclaim\n");
|
||||
|
||||
/* 4.1 client asking for a delegation? */
|
||||
if (open->op_deleg_want)
|
||||
nfsd4_open_deleg_none_ext(open, status);
|
||||
}
|
||||
open->op_delegate_type = NFS4_OPEN_DELEGATE_READ;
|
||||
return;
|
||||
out_free:
|
||||
unhash_stid(&dp->dl_stid);
|
||||
nfs4_put_delegation(dp);
|
||||
out_no_deleg:
|
||||
flag = NFS4_OPEN_DELEGATE_NONE;
|
||||
goto out;
|
||||
open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE;
|
||||
if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS &&
|
||||
open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE) {
|
||||
dprintk("NFSD: WARNING: refusing delegation reclaim\n");
|
||||
open->op_recall = 1;
|
||||
}
|
||||
|
||||
/* 4.1 client asking for a delegation? */
|
||||
if (open->op_deleg_want)
|
||||
nfsd4_open_deleg_none_ext(open, status);
|
||||
return;
|
||||
}
|
||||
|
||||
static void nfsd4_deleg_xgrade_none_ext(struct nfsd4_open *open,
|
||||
@@ -3427,7 +3513,7 @@ grace_disallows_io(struct net *net, struct inode *inode)
|
||||
/* Returns true iff a is later than b: */
|
||||
static bool stateid_generation_after(stateid_t *a, stateid_t *b)
|
||||
{
|
||||
return (s32)a->si_generation - (s32)b->si_generation > 0;
|
||||
return (s32)(a->si_generation - b->si_generation) > 0;
|
||||
}
|
||||
|
||||
static __be32 check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_session)
|
||||
@@ -4435,7 +4521,6 @@ __be32
|
||||
nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
struct nfsd4_locku *locku)
|
||||
{
|
||||
struct nfs4_lockowner *lo;
|
||||
struct nfs4_ol_stateid *stp;
|
||||
struct file *filp = NULL;
|
||||
struct file_lock *file_lock = NULL;
|
||||
@@ -4468,10 +4553,9 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
status = nfserr_jukebox;
|
||||
goto out;
|
||||
}
|
||||
lo = lockowner(stp->st_stateowner);
|
||||
locks_init_lock(file_lock);
|
||||
file_lock->fl_type = F_UNLCK;
|
||||
file_lock->fl_owner = (fl_owner_t)lo;
|
||||
file_lock->fl_owner = (fl_owner_t)lockowner(stp->st_stateowner);
|
||||
file_lock->fl_pid = current->tgid;
|
||||
file_lock->fl_file = filp;
|
||||
file_lock->fl_flags = FL_POSIX;
|
||||
@@ -4490,11 +4574,6 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
update_stateid(&stp->st_stid.sc_stateid);
|
||||
memcpy(&locku->lu_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
|
||||
|
||||
if (nfsd4_has_session(cstate) && !check_for_locks(stp->st_file, lo)) {
|
||||
WARN_ON_ONCE(cstate->replay_owner);
|
||||
release_lockowner(lo);
|
||||
}
|
||||
|
||||
out:
|
||||
nfsd4_bump_seqid(cstate, status);
|
||||
if (!cstate->replay_owner)
|
||||
|
@@ -55,6 +55,11 @@
|
||||
#include "cache.h"
|
||||
#include "netns.h"
|
||||
|
||||
#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
|
||||
#include <linux/security.h>
|
||||
#endif
|
||||
|
||||
|
||||
#define NFSDDBG_FACILITY NFSDDBG_XDR
|
||||
|
||||
/*
|
||||
@@ -134,6 +139,19 @@ xdr_error: \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static void next_decode_page(struct nfsd4_compoundargs *argp)
|
||||
{
|
||||
argp->pagelist++;
|
||||
argp->p = page_address(argp->pagelist[0]);
|
||||
if (argp->pagelen < PAGE_SIZE) {
|
||||
argp->end = argp->p + (argp->pagelen>>2);
|
||||
argp->pagelen = 0;
|
||||
} else {
|
||||
argp->end = argp->p + (PAGE_SIZE>>2);
|
||||
argp->pagelen -= PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
static __be32 *read_buf(struct nfsd4_compoundargs *argp, u32 nbytes)
|
||||
{
|
||||
/* We want more bytes than seem to be available.
|
||||
@@ -161,16 +179,7 @@ static __be32 *read_buf(struct nfsd4_compoundargs *argp, u32 nbytes)
|
||||
* guarantee p points to at least nbytes bytes.
|
||||
*/
|
||||
memcpy(p, argp->p, avail);
|
||||
/* step to next page */
|
||||
argp->p = page_address(argp->pagelist[0]);
|
||||
argp->pagelist++;
|
||||
if (argp->pagelen < PAGE_SIZE) {
|
||||
argp->end = argp->p + (argp->pagelen>>2);
|
||||
argp->pagelen = 0;
|
||||
} else {
|
||||
argp->end = argp->p + (PAGE_SIZE>>2);
|
||||
argp->pagelen -= PAGE_SIZE;
|
||||
}
|
||||
next_decode_page(argp);
|
||||
memcpy(((char*)p)+avail, argp->p, (nbytes - avail));
|
||||
argp->p += XDR_QUADLEN(nbytes - avail);
|
||||
return p;
|
||||
@@ -242,7 +251,8 @@ nfsd4_decode_bitmap(struct nfsd4_compoundargs *argp, u32 *bmval)
|
||||
|
||||
static __be32
|
||||
nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval,
|
||||
struct iattr *iattr, struct nfs4_acl **acl)
|
||||
struct iattr *iattr, struct nfs4_acl **acl,
|
||||
struct xdr_netobj *label)
|
||||
{
|
||||
int expected_len, len = 0;
|
||||
u32 dummy32;
|
||||
@@ -380,6 +390,32 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval,
|
||||
goto xdr_error;
|
||||
}
|
||||
}
|
||||
|
||||
label->len = 0;
|
||||
#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
|
||||
if (bmval[2] & FATTR4_WORD2_SECURITY_LABEL) {
|
||||
READ_BUF(4);
|
||||
len += 4;
|
||||
READ32(dummy32); /* lfs: we don't use it */
|
||||
READ_BUF(4);
|
||||
len += 4;
|
||||
READ32(dummy32); /* pi: we don't use it either */
|
||||
READ_BUF(4);
|
||||
len += 4;
|
||||
READ32(dummy32);
|
||||
READ_BUF(dummy32);
|
||||
if (dummy32 > NFSD4_MAX_SEC_LABEL_LEN)
|
||||
return nfserr_badlabel;
|
||||
len += (XDR_QUADLEN(dummy32) << 2);
|
||||
READMEM(buf, dummy32);
|
||||
label->data = kzalloc(dummy32 + 1, GFP_KERNEL);
|
||||
if (!label->data)
|
||||
return nfserr_jukebox;
|
||||
defer_free(argp, kfree, label->data);
|
||||
memcpy(label->data, buf, dummy32);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (bmval[0] & ~NFSD_WRITEABLE_ATTRS_WORD0
|
||||
|| bmval[1] & ~NFSD_WRITEABLE_ATTRS_WORD1
|
||||
|| bmval[2] & ~NFSD_WRITEABLE_ATTRS_WORD2)
|
||||
@@ -428,7 +464,11 @@ static __be32 nfsd4_decode_cb_sec(struct nfsd4_compoundargs *argp, struct nfsd4_
|
||||
/* callback_sec_params4 */
|
||||
READ_BUF(4);
|
||||
READ32(nr_secflavs);
|
||||
cbs->flavor = (u32)(-1);
|
||||
if (nr_secflavs)
|
||||
cbs->flavor = (u32)(-1);
|
||||
else
|
||||
/* Is this legal? Be generous, take it to mean AUTH_NONE: */
|
||||
cbs->flavor = 0;
|
||||
for (i = 0; i < nr_secflavs; ++i) {
|
||||
READ_BUF(4);
|
||||
READ32(dummy);
|
||||
@@ -576,7 +616,7 @@ nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create
|
||||
return status;
|
||||
|
||||
status = nfsd4_decode_fattr(argp, create->cr_bmval, &create->cr_iattr,
|
||||
&create->cr_acl);
|
||||
&create->cr_acl, &create->cr_label);
|
||||
if (status)
|
||||
goto out;
|
||||
|
||||
@@ -827,7 +867,7 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open)
|
||||
case NFS4_CREATE_UNCHECKED:
|
||||
case NFS4_CREATE_GUARDED:
|
||||
status = nfsd4_decode_fattr(argp, open->op_bmval,
|
||||
&open->op_iattr, &open->op_acl);
|
||||
&open->op_iattr, &open->op_acl, &open->op_label);
|
||||
if (status)
|
||||
goto out;
|
||||
break;
|
||||
@@ -841,7 +881,7 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open)
|
||||
READ_BUF(NFS4_VERIFIER_SIZE);
|
||||
COPYMEM(open->op_verf.data, NFS4_VERIFIER_SIZE);
|
||||
status = nfsd4_decode_fattr(argp, open->op_bmval,
|
||||
&open->op_iattr, &open->op_acl);
|
||||
&open->op_iattr, &open->op_acl, &open->op_label);
|
||||
if (status)
|
||||
goto out;
|
||||
break;
|
||||
@@ -1063,7 +1103,7 @@ nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *seta
|
||||
if (status)
|
||||
return status;
|
||||
return nfsd4_decode_fattr(argp, setattr->sa_bmval, &setattr->sa_iattr,
|
||||
&setattr->sa_acl);
|
||||
&setattr->sa_acl, &setattr->sa_label);
|
||||
}
|
||||
|
||||
static __be32
|
||||
@@ -1567,6 +1607,7 @@ struct nfsd4_minorversion_ops {
|
||||
static struct nfsd4_minorversion_ops nfsd4_minorversion[] = {
|
||||
[0] = { nfsd4_dec_ops, ARRAY_SIZE(nfsd4_dec_ops) },
|
||||
[1] = { nfsd41_dec_ops, ARRAY_SIZE(nfsd41_dec_ops) },
|
||||
[2] = { nfsd41_dec_ops, ARRAY_SIZE(nfsd41_dec_ops) },
|
||||
};
|
||||
|
||||
static __be32
|
||||
@@ -1953,6 +1994,36 @@ nfsd4_encode_aclname(struct svc_rqst *rqstp, struct nfs4_ace *ace,
|
||||
FATTR4_WORD0_RDATTR_ERROR)
|
||||
#define WORD1_ABSENT_FS_ATTRS FATTR4_WORD1_MOUNTED_ON_FILEID
|
||||
|
||||
#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
|
||||
static inline __be32
|
||||
nfsd4_encode_security_label(struct svc_rqst *rqstp, void *context, int len, __be32 **pp, int *buflen)
|
||||
{
|
||||
__be32 *p = *pp;
|
||||
|
||||
if (*buflen < ((XDR_QUADLEN(len) << 2) + 4 + 4 + 4))
|
||||
return nfserr_resource;
|
||||
|
||||
/*
|
||||
* For now we use a 0 here to indicate the null translation; in
|
||||
* the future we may place a call to translation code here.
|
||||
*/
|
||||
if ((*buflen -= 8) < 0)
|
||||
return nfserr_resource;
|
||||
|
||||
WRITE32(0); /* lfs */
|
||||
WRITE32(0); /* pi */
|
||||
p = xdr_encode_opaque(p, context, len);
|
||||
*buflen -= (XDR_QUADLEN(len) << 2) + 4;
|
||||
|
||||
*pp = p;
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static inline __be32
|
||||
nfsd4_encode_security_label(struct svc_rqst *rqstp, void *context, int len, __be32 **pp, int *buflen)
|
||||
{ return 0; }
|
||||
#endif
|
||||
|
||||
static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err)
|
||||
{
|
||||
/* As per referral draft: */
|
||||
@@ -2012,6 +2083,9 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
|
||||
int err;
|
||||
int aclsupport = 0;
|
||||
struct nfs4_acl *acl = NULL;
|
||||
void *context = NULL;
|
||||
int contextlen;
|
||||
bool contextsupport = false;
|
||||
struct nfsd4_compoundres *resp = rqstp->rq_resp;
|
||||
u32 minorversion = resp->cstate.minorversion;
|
||||
struct path path = {
|
||||
@@ -2065,6 +2139,21 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
|
||||
if ((bmval[2] & FATTR4_WORD2_SECURITY_LABEL) ||
|
||||
bmval[0] & FATTR4_WORD0_SUPPORTED_ATTRS) {
|
||||
err = security_inode_getsecctx(dentry->d_inode,
|
||||
&context, &contextlen);
|
||||
contextsupport = (err == 0);
|
||||
if (bmval2 & FATTR4_WORD2_SECURITY_LABEL) {
|
||||
if (err == -EOPNOTSUPP)
|
||||
bmval2 &= ~FATTR4_WORD2_SECURITY_LABEL;
|
||||
else if (err)
|
||||
goto out_nfserr;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_NFSD_V4_SECURITY_LABEL */
|
||||
|
||||
if (bmval2) {
|
||||
if ((buflen -= 16) < 0)
|
||||
goto out_resource;
|
||||
@@ -2093,6 +2182,8 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
|
||||
|
||||
if (!aclsupport)
|
||||
word0 &= ~FATTR4_WORD0_ACL;
|
||||
if (!contextsupport)
|
||||
word2 &= ~FATTR4_WORD2_SECURITY_LABEL;
|
||||
if (!word2) {
|
||||
if ((buflen -= 12) < 0)
|
||||
goto out_resource;
|
||||
@@ -2400,6 +2491,12 @@ out_acl:
|
||||
get_parent_attributes(exp, &stat);
|
||||
WRITE64(stat.ino);
|
||||
}
|
||||
if (bmval2 & FATTR4_WORD2_SECURITY_LABEL) {
|
||||
status = nfsd4_encode_security_label(rqstp, context,
|
||||
contextlen, &p, &buflen);
|
||||
if (status)
|
||||
goto out;
|
||||
}
|
||||
if (bmval2 & FATTR4_WORD2_SUPPATTR_EXCLCREAT) {
|
||||
WRITE32(3);
|
||||
WRITE32(NFSD_SUPPATTR_EXCLCREAT_WORD0);
|
||||
@@ -2412,6 +2509,10 @@ out_acl:
|
||||
status = nfs_ok;
|
||||
|
||||
out:
|
||||
#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
|
||||
if (context)
|
||||
security_release_secctx(context, contextlen);
|
||||
#endif /* CONFIG_NFSD_V4_SECURITY_LABEL */
|
||||
kfree(acl);
|
||||
if (fhp == &tempfh)
|
||||
fh_put(&tempfh);
|
||||
@@ -3176,16 +3277,18 @@ nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4
|
||||
{
|
||||
__be32 *p;
|
||||
|
||||
RESERVE_SPACE(12);
|
||||
RESERVE_SPACE(16);
|
||||
if (nfserr) {
|
||||
WRITE32(2);
|
||||
WRITE32(3);
|
||||
WRITE32(0);
|
||||
WRITE32(0);
|
||||
WRITE32(0);
|
||||
}
|
||||
else {
|
||||
WRITE32(2);
|
||||
WRITE32(3);
|
||||
WRITE32(setattr->sa_bmval[0]);
|
||||
WRITE32(setattr->sa_bmval[1]);
|
||||
WRITE32(setattr->sa_bmval[2]);
|
||||
}
|
||||
ADJUST_ARGS();
|
||||
return nfserr;
|
||||
@@ -3226,6 +3329,14 @@ nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_w
|
||||
return nfserr;
|
||||
}
|
||||
|
||||
static const u32 nfs4_minimal_spo_must_enforce[2] = {
|
||||
[1] = 1 << (OP_BIND_CONN_TO_SESSION - 32) |
|
||||
1 << (OP_EXCHANGE_ID - 32) |
|
||||
1 << (OP_CREATE_SESSION - 32) |
|
||||
1 << (OP_DESTROY_SESSION - 32) |
|
||||
1 << (OP_DESTROY_CLIENTID - 32)
|
||||
};
|
||||
|
||||
static __be32
|
||||
nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr,
|
||||
struct nfsd4_exchange_id *exid)
|
||||
@@ -3264,6 +3375,20 @@ nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr,
|
||||
/* state_protect4_r. Currently only support SP4_NONE */
|
||||
BUG_ON(exid->spa_how != SP4_NONE);
|
||||
WRITE32(exid->spa_how);
|
||||
switch (exid->spa_how) {
|
||||
case SP4_NONE:
|
||||
break;
|
||||
case SP4_MACH_CRED:
|
||||
/* spo_must_enforce bitmap: */
|
||||
WRITE32(2);
|
||||
WRITE32(nfs4_minimal_spo_must_enforce[0]);
|
||||
WRITE32(nfs4_minimal_spo_must_enforce[1]);
|
||||
/* empty spo_must_allow bitmap: */
|
||||
WRITE32(0);
|
||||
break;
|
||||
default:
|
||||
WARN_ON_ONCE(1);
|
||||
}
|
||||
|
||||
/* The server_owner struct */
|
||||
WRITE64(minor_id); /* Minor id */
|
||||
@@ -3635,13 +3760,17 @@ nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compo
|
||||
iov->iov_len = ((char*)resp->p) - (char*)iov->iov_base;
|
||||
BUG_ON(iov->iov_len > PAGE_SIZE);
|
||||
if (nfsd4_has_session(cs)) {
|
||||
struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
|
||||
struct nfs4_client *clp = cs->session->se_client;
|
||||
if (cs->status != nfserr_replay_cache) {
|
||||
nfsd4_store_cache_entry(resp);
|
||||
cs->slot->sl_flags &= ~NFSD4_SLOT_INUSE;
|
||||
}
|
||||
/* Renew the clientid on success and on replay */
|
||||
put_client_renew(cs->session->se_client);
|
||||
spin_lock(&nn->client_lock);
|
||||
nfsd4_put_session(cs->session);
|
||||
spin_unlock(&nn->client_lock);
|
||||
put_client_renew(clp);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
@@ -24,7 +24,7 @@
|
||||
/*
|
||||
* nfsd version
|
||||
*/
|
||||
#define NFSD_SUPPORTED_MINOR_VERSION 1
|
||||
#define NFSD_SUPPORTED_MINOR_VERSION 2
|
||||
/*
|
||||
* Maximum blocksizes supported by daemon under various circumstances.
|
||||
*/
|
||||
@@ -328,6 +328,13 @@ void nfsd_lockd_shutdown(void);
|
||||
#define NFSD4_1_SUPPORTED_ATTRS_WORD2 \
|
||||
(NFSD4_SUPPORTED_ATTRS_WORD2 | FATTR4_WORD2_SUPPATTR_EXCLCREAT)
|
||||
|
||||
#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
|
||||
#define NFSD4_2_SUPPORTED_ATTRS_WORD2 \
|
||||
(NFSD4_1_SUPPORTED_ATTRS_WORD2 | FATTR4_WORD2_SECURITY_LABEL)
|
||||
#else
|
||||
#define NFSD4_2_SUPPORTED_ATTRS_WORD2 0
|
||||
#endif
|
||||
|
||||
static inline u32 nfsd_suppattrs0(u32 minorversion)
|
||||
{
|
||||
return minorversion ? NFSD4_1_SUPPORTED_ATTRS_WORD0
|
||||
@@ -342,8 +349,11 @@ static inline u32 nfsd_suppattrs1(u32 minorversion)
|
||||
|
||||
static inline u32 nfsd_suppattrs2(u32 minorversion)
|
||||
{
|
||||
return minorversion ? NFSD4_1_SUPPORTED_ATTRS_WORD2
|
||||
: NFSD4_SUPPORTED_ATTRS_WORD2;
|
||||
switch (minorversion) {
|
||||
default: return NFSD4_2_SUPPORTED_ATTRS_WORD2;
|
||||
case 1: return NFSD4_1_SUPPORTED_ATTRS_WORD2;
|
||||
case 0: return NFSD4_SUPPORTED_ATTRS_WORD2;
|
||||
}
|
||||
}
|
||||
|
||||
/* These will return ERR_INVAL if specified in GETATTR or READDIR. */
|
||||
@@ -356,7 +366,11 @@ static inline u32 nfsd_suppattrs2(u32 minorversion)
|
||||
#define NFSD_WRITEABLE_ATTRS_WORD1 \
|
||||
(FATTR4_WORD1_MODE | FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP \
|
||||
| FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_MODIFY_SET)
|
||||
#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
|
||||
#define NFSD_WRITEABLE_ATTRS_WORD2 FATTR4_WORD2_SECURITY_LABEL
|
||||
#else
|
||||
#define NFSD_WRITEABLE_ATTRS_WORD2 0
|
||||
#endif
|
||||
|
||||
#define NFSD_SUPPATTR_EXCLCREAT_WORD0 \
|
||||
NFSD_WRITEABLE_ATTRS_WORD0
|
||||
|
@@ -116,7 +116,7 @@ struct svc_program nfsd_program = {
|
||||
|
||||
};
|
||||
|
||||
u32 nfsd_supported_minorversion;
|
||||
u32 nfsd_supported_minorversion = 1;
|
||||
|
||||
int nfsd_vers(int vers, enum vers_op change)
|
||||
{
|
||||
|
@@ -246,6 +246,7 @@ struct nfs4_client {
|
||||
nfs4_verifier cl_verifier; /* generated by client */
|
||||
time_t cl_time; /* time of last lease renewal */
|
||||
struct sockaddr_storage cl_addr; /* client ipaddress */
|
||||
bool cl_mach_cred; /* SP4_MACH_CRED in force */
|
||||
struct svc_cred cl_cred; /* setclientid principal */
|
||||
clientid_t cl_clientid; /* generated by server */
|
||||
nfs4_verifier cl_confirm; /* generated by server */
|
||||
|
@@ -28,6 +28,7 @@
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/exportfs.h>
|
||||
#include <linux/writeback.h>
|
||||
#include <linux/security.h>
|
||||
|
||||
#ifdef CONFIG_NFSD_V3
|
||||
#include "xdr3.h"
|
||||
@@ -621,6 +622,33 @@ int nfsd4_is_junction(struct dentry *dentry)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
|
||||
__be32 nfsd4_set_nfs4_label(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
||||
struct xdr_netobj *label)
|
||||
{
|
||||
__be32 error;
|
||||
int host_error;
|
||||
struct dentry *dentry;
|
||||
|
||||
error = fh_verify(rqstp, fhp, 0 /* S_IFREG */, NFSD_MAY_SATTR);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
dentry = fhp->fh_dentry;
|
||||
|
||||
mutex_lock(&dentry->d_inode->i_mutex);
|
||||
host_error = security_inode_setsecctx(dentry, label->data, label->len);
|
||||
mutex_unlock(&dentry->d_inode->i_mutex);
|
||||
return nfserrno(host_error);
|
||||
}
|
||||
#else
|
||||
__be32 nfsd4_set_nfs4_label(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
||||
struct xdr_netobj *label)
|
||||
{
|
||||
return nfserr_notsupp;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* defined(CONFIG_NFSD_V4) */
|
||||
|
||||
#ifdef CONFIG_NFSD_V3
|
||||
|
@@ -39,7 +39,6 @@
|
||||
typedef int (*nfsd_dirop_t)(struct inode *, struct dentry *, int, int);
|
||||
|
||||
/* nfsd/vfs.c */
|
||||
int fh_lock_parent(struct svc_fh *, struct dentry *);
|
||||
int nfsd_racache_init(int);
|
||||
void nfsd_racache_shutdown(void);
|
||||
int nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp,
|
||||
@@ -56,6 +55,8 @@ int nfsd_mountpoint(struct dentry *, struct svc_export *);
|
||||
__be32 nfsd4_set_nfs4_acl(struct svc_rqst *, struct svc_fh *,
|
||||
struct nfs4_acl *);
|
||||
int nfsd4_get_nfs4_acl(struct svc_rqst *, struct dentry *, struct nfs4_acl **);
|
||||
__be32 nfsd4_set_nfs4_label(struct svc_rqst *, struct svc_fh *,
|
||||
struct xdr_netobj *);
|
||||
#endif /* CONFIG_NFSD_V4 */
|
||||
__be32 nfsd_create(struct svc_rqst *, struct svc_fh *,
|
||||
char *name, int len, struct iattr *attrs,
|
||||
@@ -92,17 +93,13 @@ __be32 nfsd_remove(struct svc_rqst *,
|
||||
struct svc_fh *, char *, int);
|
||||
__be32 nfsd_unlink(struct svc_rqst *, struct svc_fh *, int type,
|
||||
char *name, int len);
|
||||
int nfsd_truncate(struct svc_rqst *, struct svc_fh *,
|
||||
unsigned long size);
|
||||
__be32 nfsd_readdir(struct svc_rqst *, struct svc_fh *,
|
||||
loff_t *, struct readdir_cd *, filldir_t);
|
||||
__be32 nfsd_statfs(struct svc_rqst *, struct svc_fh *,
|
||||
struct kstatfs *, int access);
|
||||
|
||||
int nfsd_notify_change(struct inode *, struct iattr *);
|
||||
__be32 nfsd_permission(struct svc_rqst *, struct svc_export *,
|
||||
struct dentry *, int);
|
||||
int nfsd_sync_dir(struct dentry *dp);
|
||||
|
||||
#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
|
||||
struct posix_acl *nfsd_get_posix_acl(struct svc_fh *, int);
|
||||
|
@@ -40,6 +40,7 @@
|
||||
#include "state.h"
|
||||
#include "nfsd.h"
|
||||
|
||||
#define NFSD4_MAX_SEC_LABEL_LEN 2048
|
||||
#define NFSD4_MAX_TAGLEN 128
|
||||
#define XDR_LEN(n) (((n) + 3) & ~3)
|
||||
|
||||
@@ -118,6 +119,7 @@ struct nfsd4_create {
|
||||
struct iattr cr_iattr; /* request */
|
||||
struct nfsd4_change_info cr_cinfo; /* response */
|
||||
struct nfs4_acl *cr_acl;
|
||||
struct xdr_netobj cr_label;
|
||||
};
|
||||
#define cr_linklen u.link.namelen
|
||||
#define cr_linkname u.link.name
|
||||
@@ -246,6 +248,7 @@ struct nfsd4_open {
|
||||
struct nfs4_file *op_file; /* used during processing */
|
||||
struct nfs4_ol_stateid *op_stp; /* used during processing */
|
||||
struct nfs4_acl *op_acl;
|
||||
struct xdr_netobj op_label;
|
||||
};
|
||||
#define op_iattr iattr
|
||||
|
||||
@@ -330,6 +333,7 @@ struct nfsd4_setattr {
|
||||
u32 sa_bmval[3]; /* request */
|
||||
struct iattr sa_iattr; /* request */
|
||||
struct nfs4_acl *sa_acl;
|
||||
struct xdr_netobj sa_label;
|
||||
};
|
||||
|
||||
struct nfsd4_setclientid {
|
||||
|
Reference in New Issue
Block a user