|
@@ -77,15 +77,68 @@ static int _nfs4_recover_proc_open(struct nfs4_opendata *data);
|
|
|
static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *);
|
|
|
static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *, struct nfs4_state *);
|
|
|
static void nfs_fixup_referral_attributes(struct nfs_fattr *fattr);
|
|
|
-static int nfs4_proc_getattr(struct nfs_server *, struct nfs_fh *, struct nfs_fattr *);
|
|
|
-static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr);
|
|
|
+static int nfs4_proc_getattr(struct nfs_server *, struct nfs_fh *, struct nfs_fattr *, struct nfs4_label *label);
|
|
|
+static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr, struct nfs4_label *label);
|
|
|
static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
|
|
|
struct nfs_fattr *fattr, struct iattr *sattr,
|
|
|
- struct nfs4_state *state);
|
|
|
+ struct nfs4_state *state, struct nfs4_label *ilabel,
|
|
|
+ struct nfs4_label *olabel);
|
|
|
#ifdef CONFIG_NFS_V4_1
|
|
|
-static int nfs41_test_stateid(struct nfs_server *, nfs4_stateid *);
|
|
|
-static int nfs41_free_stateid(struct nfs_server *, nfs4_stateid *);
|
|
|
+static int nfs41_test_stateid(struct nfs_server *, nfs4_stateid *,
|
|
|
+ struct rpc_cred *);
|
|
|
+static int nfs41_free_stateid(struct nfs_server *, nfs4_stateid *,
|
|
|
+ struct rpc_cred *);
|
|
|
#endif
|
|
|
+
|
|
|
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
|
|
|
+static inline struct nfs4_label *
|
|
|
+nfs4_label_init_security(struct inode *dir, struct dentry *dentry,
|
|
|
+ struct iattr *sattr, struct nfs4_label *label)
|
|
|
+{
|
|
|
+ int err;
|
|
|
+
|
|
|
+ if (label == NULL)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL) == 0)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ if (NFS_SERVER(dir)->nfs_client->cl_minorversion < 2)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ err = security_dentry_init_security(dentry, sattr->ia_mode,
|
|
|
+ &dentry->d_name, (void **)&label->label, &label->len);
|
|
|
+ if (err == 0)
|
|
|
+ return label;
|
|
|
+
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+static inline void
|
|
|
+nfs4_label_release_security(struct nfs4_label *label)
|
|
|
+{
|
|
|
+ if (label)
|
|
|
+ security_release_secctx(label->label, label->len);
|
|
|
+}
|
|
|
+static inline u32 *nfs4_bitmask(struct nfs_server *server, struct nfs4_label *label)
|
|
|
+{
|
|
|
+ if (label)
|
|
|
+ return server->attr_bitmask;
|
|
|
+
|
|
|
+ return server->attr_bitmask_nl;
|
|
|
+}
|
|
|
+#else
|
|
|
+static inline struct nfs4_label *
|
|
|
+nfs4_label_init_security(struct inode *dir, struct dentry *dentry,
|
|
|
+ struct iattr *sattr, struct nfs4_label *l)
|
|
|
+{ return NULL; }
|
|
|
+static inline void
|
|
|
+nfs4_label_release_security(struct nfs4_label *label)
|
|
|
+{ return; }
|
|
|
+static inline u32 *
|
|
|
+nfs4_bitmask(struct nfs_server *server, struct nfs4_label *label)
|
|
|
+{ return server->attr_bitmask; }
|
|
|
+#endif
|
|
|
+
|
|
|
/* Prevent leaks of NFSv4 errors into userland */
|
|
|
static int nfs4_map_errors(int err)
|
|
|
{
|
|
@@ -134,7 +187,10 @@ const u32 nfs4_fattr_bitmap[3] = {
|
|
|
| FATTR4_WORD1_SPACE_USED
|
|
|
| FATTR4_WORD1_TIME_ACCESS
|
|
|
| FATTR4_WORD1_TIME_METADATA
|
|
|
- | FATTR4_WORD1_TIME_MODIFY
|
|
|
+ | FATTR4_WORD1_TIME_MODIFY,
|
|
|
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
|
|
|
+ FATTR4_WORD2_SECURITY_LABEL
|
|
|
+#endif
|
|
|
};
|
|
|
|
|
|
static const u32 nfs4_pnfs_open_bitmap[3] = {
|
|
@@ -161,7 +217,7 @@ static const u32 nfs4_open_noattr_bitmap[3] = {
|
|
|
| FATTR4_WORD0_FILEID,
|
|
|
};
|
|
|
|
|
|
-const u32 nfs4_statfs_bitmap[2] = {
|
|
|
+const u32 nfs4_statfs_bitmap[3] = {
|
|
|
FATTR4_WORD0_FILES_AVAIL
|
|
|
| FATTR4_WORD0_FILES_FREE
|
|
|
| FATTR4_WORD0_FILES_TOTAL,
|
|
@@ -170,7 +226,7 @@ const u32 nfs4_statfs_bitmap[2] = {
|
|
|
| FATTR4_WORD1_SPACE_TOTAL
|
|
|
};
|
|
|
|
|
|
-const u32 nfs4_pathconf_bitmap[2] = {
|
|
|
+const u32 nfs4_pathconf_bitmap[3] = {
|
|
|
FATTR4_WORD0_MAXLINK
|
|
|
| FATTR4_WORD0_MAXNAME,
|
|
|
0
|
|
@@ -185,7 +241,7 @@ const u32 nfs4_fsinfo_bitmap[3] = { FATTR4_WORD0_MAXFILESIZE
|
|
|
FATTR4_WORD2_LAYOUT_BLKSIZE
|
|
|
};
|
|
|
|
|
|
-const u32 nfs4_fs_locations_bitmap[2] = {
|
|
|
+const u32 nfs4_fs_locations_bitmap[3] = {
|
|
|
FATTR4_WORD0_TYPE
|
|
|
| FATTR4_WORD0_CHANGE
|
|
|
| FATTR4_WORD0_SIZE
|
|
@@ -201,7 +257,7 @@ const u32 nfs4_fs_locations_bitmap[2] = {
|
|
|
| FATTR4_WORD1_TIME_ACCESS
|
|
|
| FATTR4_WORD1_TIME_METADATA
|
|
|
| FATTR4_WORD1_TIME_MODIFY
|
|
|
- | FATTR4_WORD1_MOUNTED_ON_FILEID
|
|
|
+ | FATTR4_WORD1_MOUNTED_ON_FILEID,
|
|
|
};
|
|
|
|
|
|
static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dentry,
|
|
@@ -762,6 +818,7 @@ struct nfs4_opendata {
|
|
|
struct nfs4_string owner_name;
|
|
|
struct nfs4_string group_name;
|
|
|
struct nfs_fattr f_attr;
|
|
|
+ struct nfs4_label *f_label;
|
|
|
struct dentry *dir;
|
|
|
struct dentry *dentry;
|
|
|
struct nfs4_state_owner *owner;
|
|
@@ -807,6 +864,7 @@ nfs4_map_atomic_open_claim(struct nfs_server *server,
|
|
|
static void nfs4_init_opendata_res(struct nfs4_opendata *p)
|
|
|
{
|
|
|
p->o_res.f_attr = &p->f_attr;
|
|
|
+ p->o_res.f_label = p->f_label;
|
|
|
p->o_res.seqid = p->o_arg.seqid;
|
|
|
p->c_res.seqid = p->c_arg.seqid;
|
|
|
p->o_res.server = p->o_arg.server;
|
|
@@ -818,6 +876,7 @@ static void nfs4_init_opendata_res(struct nfs4_opendata *p)
|
|
|
static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
|
|
|
struct nfs4_state_owner *sp, fmode_t fmode, int flags,
|
|
|
const struct iattr *attrs,
|
|
|
+ struct nfs4_label *label,
|
|
|
enum open_claim_type4 claim,
|
|
|
gfp_t gfp_mask)
|
|
|
{
|
|
@@ -829,9 +888,14 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
|
|
|
p = kzalloc(sizeof(*p), gfp_mask);
|
|
|
if (p == NULL)
|
|
|
goto err;
|
|
|
+
|
|
|
+ p->f_label = nfs4_label_alloc(server, gfp_mask);
|
|
|
+ if (IS_ERR(p->f_label))
|
|
|
+ goto err_free_p;
|
|
|
+
|
|
|
p->o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid, gfp_mask);
|
|
|
if (p->o_arg.seqid == NULL)
|
|
|
- goto err_free;
|
|
|
+ goto err_free_label;
|
|
|
nfs_sb_active(dentry->d_sb);
|
|
|
p->dentry = dget(dentry);
|
|
|
p->dir = parent;
|
|
@@ -852,8 +916,9 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
|
|
|
p->o_arg.id.uniquifier = sp->so_seqid.owner_id;
|
|
|
p->o_arg.name = &dentry->d_name;
|
|
|
p->o_arg.server = server;
|
|
|
- p->o_arg.bitmask = server->attr_bitmask;
|
|
|
+ p->o_arg.bitmask = nfs4_bitmask(server, label);
|
|
|
p->o_arg.open_bitmap = &nfs4_fattr_bitmap[0];
|
|
|
+ p->o_arg.label = label;
|
|
|
p->o_arg.claim = nfs4_map_atomic_open_claim(server, claim);
|
|
|
switch (p->o_arg.claim) {
|
|
|
case NFS4_OPEN_CLAIM_NULL:
|
|
@@ -884,7 +949,10 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
|
|
|
nfs4_init_opendata_res(p);
|
|
|
kref_init(&p->kref);
|
|
|
return p;
|
|
|
-err_free:
|
|
|
+
|
|
|
+err_free_label:
|
|
|
+ nfs4_label_free(p->f_label);
|
|
|
+err_free_p:
|
|
|
kfree(p);
|
|
|
err:
|
|
|
dput(parent);
|
|
@@ -901,6 +969,9 @@ static void nfs4_opendata_free(struct kref *kref)
|
|
|
if (p->state != NULL)
|
|
|
nfs4_put_open_state(p->state);
|
|
|
nfs4_put_state_owner(p->owner);
|
|
|
+
|
|
|
+ nfs4_label_free(p->f_label);
|
|
|
+
|
|
|
dput(p->dir);
|
|
|
dput(p->dentry);
|
|
|
nfs_sb_deactive(sb);
|
|
@@ -1179,6 +1250,8 @@ _nfs4_opendata_reclaim_to_nfs4_state(struct nfs4_opendata *data)
|
|
|
if (ret)
|
|
|
goto err;
|
|
|
|
|
|
+ nfs_setsecurity(inode, &data->f_attr, data->f_label);
|
|
|
+
|
|
|
if (data->o_res.delegation_type != 0)
|
|
|
nfs4_opendata_check_deleg(data, state);
|
|
|
update_open_stateid(state, &data->o_res.stateid, NULL,
|
|
@@ -1205,7 +1278,7 @@ _nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data)
|
|
|
ret = -EAGAIN;
|
|
|
if (!(data->f_attr.valid & NFS_ATTR_FATTR))
|
|
|
goto err;
|
|
|
- inode = nfs_fhget(data->dir->d_sb, &data->o_res.fh, &data->f_attr);
|
|
|
+ inode = nfs_fhget(data->dir->d_sb, &data->o_res.fh, &data->f_attr, data->f_label);
|
|
|
ret = PTR_ERR(inode);
|
|
|
if (IS_ERR(inode))
|
|
|
goto err;
|
|
@@ -1258,7 +1331,7 @@ static struct nfs4_opendata *nfs4_open_recoverdata_alloc(struct nfs_open_context
|
|
|
struct nfs4_opendata *opendata;
|
|
|
|
|
|
opendata = nfs4_opendata_alloc(ctx->dentry, state->owner, 0, 0,
|
|
|
- NULL, claim, GFP_NOFS);
|
|
|
+ NULL, NULL, claim, GFP_NOFS);
|
|
|
if (opendata == NULL)
|
|
|
return ERR_PTR(-ENOMEM);
|
|
|
opendata->state = state;
|
|
@@ -1784,7 +1857,7 @@ static int _nfs4_proc_open(struct nfs4_opendata *data)
|
|
|
return status;
|
|
|
}
|
|
|
if (!(o_res->f_attr->valid & NFS_ATTR_FATTR))
|
|
|
- _nfs4_proc_getattr(server, &o_res->fh, o_res->f_attr);
|
|
|
+ _nfs4_proc_getattr(server, &o_res->fh, o_res->f_attr, o_res->f_label);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -1855,18 +1928,30 @@ static void nfs41_clear_delegation_stateid(struct nfs4_state *state)
|
|
|
{
|
|
|
struct nfs_server *server = NFS_SERVER(state->inode);
|
|
|
nfs4_stateid *stateid = &state->stateid;
|
|
|
- int status;
|
|
|
+ struct nfs_delegation *delegation;
|
|
|
+ struct rpc_cred *cred = NULL;
|
|
|
+ int status = -NFS4ERR_BAD_STATEID;
|
|
|
|
|
|
/* If a state reset has been done, test_stateid is unneeded */
|
|
|
if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0)
|
|
|
return;
|
|
|
|
|
|
- status = nfs41_test_stateid(server, stateid);
|
|
|
+ /* Get the delegation credential for use by test/free_stateid */
|
|
|
+ rcu_read_lock();
|
|
|
+ delegation = rcu_dereference(NFS_I(state->inode)->delegation);
|
|
|
+ if (delegation != NULL &&
|
|
|
+ nfs4_stateid_match(&delegation->stateid, stateid)) {
|
|
|
+ cred = get_rpccred(delegation->cred);
|
|
|
+ rcu_read_unlock();
|
|
|
+ status = nfs41_test_stateid(server, stateid, cred);
|
|
|
+ } else
|
|
|
+ rcu_read_unlock();
|
|
|
+
|
|
|
if (status != NFS_OK) {
|
|
|
/* Free the stateid unless the server explicitly
|
|
|
* informs us the stateid is unrecognized. */
|
|
|
if (status != -NFS4ERR_BAD_STATEID)
|
|
|
- nfs41_free_stateid(server, stateid);
|
|
|
+ nfs41_free_stateid(server, stateid, cred);
|
|
|
nfs_remove_bad_delegation(state->inode);
|
|
|
|
|
|
write_seqlock(&state->seqlock);
|
|
@@ -1874,6 +1959,9 @@ static void nfs41_clear_delegation_stateid(struct nfs4_state *state)
|
|
|
write_sequnlock(&state->seqlock);
|
|
|
clear_bit(NFS_DELEGATED_STATE, &state->flags);
|
|
|
}
|
|
|
+
|
|
|
+ if (cred != NULL)
|
|
|
+ put_rpccred(cred);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -1888,6 +1976,7 @@ static int nfs41_check_open_stateid(struct nfs4_state *state)
|
|
|
{
|
|
|
struct nfs_server *server = NFS_SERVER(state->inode);
|
|
|
nfs4_stateid *stateid = &state->open_stateid;
|
|
|
+ struct rpc_cred *cred = state->owner->so_cred;
|
|
|
int status;
|
|
|
|
|
|
/* If a state reset has been done, test_stateid is unneeded */
|
|
@@ -1896,12 +1985,12 @@ static int nfs41_check_open_stateid(struct nfs4_state *state)
|
|
|
(test_bit(NFS_O_RDWR_STATE, &state->flags) == 0))
|
|
|
return -NFS4ERR_BAD_STATEID;
|
|
|
|
|
|
- status = nfs41_test_stateid(server, stateid);
|
|
|
+ status = nfs41_test_stateid(server, stateid, cred);
|
|
|
if (status != NFS_OK) {
|
|
|
/* Free the stateid unless the server explicitly
|
|
|
* informs us the stateid is unrecognized. */
|
|
|
if (status != -NFS4ERR_BAD_STATEID)
|
|
|
- nfs41_free_stateid(server, stateid);
|
|
|
+ nfs41_free_stateid(server, stateid, cred);
|
|
|
|
|
|
clear_bit(NFS_O_RDONLY_STATE, &state->flags);
|
|
|
clear_bit(NFS_O_WRONLY_STATE, &state->flags);
|
|
@@ -1942,10 +2031,11 @@ static inline void nfs4_exclusive_attrset(struct nfs4_opendata *opendata, struct
|
|
|
static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata,
|
|
|
fmode_t fmode,
|
|
|
int flags,
|
|
|
- struct nfs4_state **res)
|
|
|
+ struct nfs_open_context *ctx)
|
|
|
{
|
|
|
struct nfs4_state_owner *sp = opendata->owner;
|
|
|
struct nfs_server *server = sp->so_server;
|
|
|
+ struct dentry *dentry;
|
|
|
struct nfs4_state *state;
|
|
|
unsigned int seq;
|
|
|
int ret;
|
|
@@ -1963,13 +2053,31 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata,
|
|
|
if (server->caps & NFS_CAP_POSIX_LOCK)
|
|
|
set_bit(NFS_STATE_POSIX_LOCKS, &state->flags);
|
|
|
|
|
|
+ dentry = opendata->dentry;
|
|
|
+ if (dentry->d_inode == NULL) {
|
|
|
+ /* FIXME: Is this d_drop() ever needed? */
|
|
|
+ d_drop(dentry);
|
|
|
+ dentry = d_add_unique(dentry, igrab(state->inode));
|
|
|
+ if (dentry == NULL) {
|
|
|
+ dentry = opendata->dentry;
|
|
|
+ } else if (dentry != ctx->dentry) {
|
|
|
+ dput(ctx->dentry);
|
|
|
+ ctx->dentry = dget(dentry);
|
|
|
+ }
|
|
|
+ nfs_set_verifier(dentry,
|
|
|
+ nfs_save_change_attribute(opendata->dir->d_inode));
|
|
|
+ }
|
|
|
+
|
|
|
ret = nfs4_opendata_access(sp->so_cred, opendata, state, fmode, flags);
|
|
|
if (ret != 0)
|
|
|
goto out;
|
|
|
|
|
|
- if (read_seqcount_retry(&sp->so_reclaim_seqcount, seq))
|
|
|
- nfs4_schedule_stateid_recovery(server, state);
|
|
|
- *res = state;
|
|
|
+ ctx->state = state;
|
|
|
+ if (dentry->d_inode == state->inode) {
|
|
|
+ nfs_inode_attach_open_context(ctx);
|
|
|
+ if (read_seqcount_retry(&sp->so_reclaim_seqcount, seq))
|
|
|
+ nfs4_schedule_stateid_recovery(server, state);
|
|
|
+ }
|
|
|
out:
|
|
|
return ret;
|
|
|
}
|
|
@@ -1978,19 +2086,21 @@ out:
|
|
|
* Returns a referenced nfs4_state
|
|
|
*/
|
|
|
static int _nfs4_do_open(struct inode *dir,
|
|
|
- struct dentry *dentry,
|
|
|
- fmode_t fmode,
|
|
|
+ struct nfs_open_context *ctx,
|
|
|
int flags,
|
|
|
struct iattr *sattr,
|
|
|
- struct rpc_cred *cred,
|
|
|
- struct nfs4_state **res,
|
|
|
- struct nfs4_threshold **ctx_th)
|
|
|
+ struct nfs4_label *label)
|
|
|
{
|
|
|
struct nfs4_state_owner *sp;
|
|
|
struct nfs4_state *state = NULL;
|
|
|
struct nfs_server *server = NFS_SERVER(dir);
|
|
|
struct nfs4_opendata *opendata;
|
|
|
+ struct dentry *dentry = ctx->dentry;
|
|
|
+ struct rpc_cred *cred = ctx->cred;
|
|
|
+ struct nfs4_threshold **ctx_th = &ctx->mdsthreshold;
|
|
|
+ fmode_t fmode = ctx->mode & (FMODE_READ|FMODE_WRITE|FMODE_EXEC);
|
|
|
enum open_claim_type4 claim = NFS4_OPEN_CLAIM_NULL;
|
|
|
+ struct nfs4_label *olabel = NULL;
|
|
|
int status;
|
|
|
|
|
|
/* Protect against reboot recovery conflicts */
|
|
@@ -2009,22 +2119,31 @@ static int _nfs4_do_open(struct inode *dir,
|
|
|
if (dentry->d_inode)
|
|
|
claim = NFS4_OPEN_CLAIM_FH;
|
|
|
opendata = nfs4_opendata_alloc(dentry, sp, fmode, flags, sattr,
|
|
|
- claim, GFP_KERNEL);
|
|
|
+ label, claim, GFP_KERNEL);
|
|
|
if (opendata == NULL)
|
|
|
goto err_put_state_owner;
|
|
|
|
|
|
+ if (label) {
|
|
|
+ olabel = nfs4_label_alloc(server, GFP_KERNEL);
|
|
|
+ if (IS_ERR(olabel)) {
|
|
|
+ status = PTR_ERR(olabel);
|
|
|
+ goto err_opendata_put;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
if (ctx_th && server->attr_bitmask[2] & FATTR4_WORD2_MDSTHRESHOLD) {
|
|
|
opendata->f_attr.mdsthreshold = pnfs_mdsthreshold_alloc();
|
|
|
if (!opendata->f_attr.mdsthreshold)
|
|
|
- goto err_opendata_put;
|
|
|
+ goto err_free_label;
|
|
|
opendata->o_arg.open_bitmap = &nfs4_pnfs_open_bitmap[0];
|
|
|
}
|
|
|
if (dentry->d_inode != NULL)
|
|
|
opendata->state = nfs4_get_open_state(dentry->d_inode, sp);
|
|
|
|
|
|
- status = _nfs4_open_and_get_state(opendata, fmode, flags, &state);
|
|
|
+ status = _nfs4_open_and_get_state(opendata, fmode, flags, ctx);
|
|
|
if (status != 0)
|
|
|
- goto err_opendata_put;
|
|
|
+ goto err_free_label;
|
|
|
+ state = ctx->state;
|
|
|
|
|
|
if ((opendata->o_arg.open_flags & O_EXCL) &&
|
|
|
(opendata->o_arg.createmode != NFS4_CREATE_GUARDED)) {
|
|
@@ -2033,10 +2152,12 @@ static int _nfs4_do_open(struct inode *dir,
|
|
|
nfs_fattr_init(opendata->o_res.f_attr);
|
|
|
status = nfs4_do_setattr(state->inode, cred,
|
|
|
opendata->o_res.f_attr, sattr,
|
|
|
- state);
|
|
|
- if (status == 0)
|
|
|
+ state, label, olabel);
|
|
|
+ if (status == 0) {
|
|
|
nfs_setattr_update_inode(state->inode, sattr);
|
|
|
- nfs_post_op_update_inode(state->inode, opendata->o_res.f_attr);
|
|
|
+ nfs_post_op_update_inode(state->inode, opendata->o_res.f_attr);
|
|
|
+ nfs_setsecurity(state->inode, opendata->o_res.f_attr, olabel);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
if (pnfs_use_threshold(ctx_th, opendata->f_attr.mdsthreshold, server))
|
|
@@ -2045,38 +2166,37 @@ static int _nfs4_do_open(struct inode *dir,
|
|
|
kfree(opendata->f_attr.mdsthreshold);
|
|
|
opendata->f_attr.mdsthreshold = NULL;
|
|
|
|
|
|
+ nfs4_label_free(olabel);
|
|
|
+
|
|
|
nfs4_opendata_put(opendata);
|
|
|
nfs4_put_state_owner(sp);
|
|
|
- *res = state;
|
|
|
return 0;
|
|
|
+err_free_label:
|
|
|
+ nfs4_label_free(olabel);
|
|
|
err_opendata_put:
|
|
|
kfree(opendata->f_attr.mdsthreshold);
|
|
|
nfs4_opendata_put(opendata);
|
|
|
err_put_state_owner:
|
|
|
nfs4_put_state_owner(sp);
|
|
|
out_err:
|
|
|
- *res = NULL;
|
|
|
return status;
|
|
|
}
|
|
|
|
|
|
|
|
|
static struct nfs4_state *nfs4_do_open(struct inode *dir,
|
|
|
- struct dentry *dentry,
|
|
|
- fmode_t fmode,
|
|
|
+ struct nfs_open_context *ctx,
|
|
|
int flags,
|
|
|
struct iattr *sattr,
|
|
|
- struct rpc_cred *cred,
|
|
|
- struct nfs4_threshold **ctx_th)
|
|
|
+ struct nfs4_label *label)
|
|
|
{
|
|
|
struct nfs_server *server = NFS_SERVER(dir);
|
|
|
struct nfs4_exception exception = { };
|
|
|
struct nfs4_state *res;
|
|
|
int status;
|
|
|
|
|
|
- fmode &= FMODE_READ|FMODE_WRITE|FMODE_EXEC;
|
|
|
do {
|
|
|
- status = _nfs4_do_open(dir, dentry, fmode, flags, sattr, cred,
|
|
|
- &res, ctx_th);
|
|
|
+ status = _nfs4_do_open(dir, ctx, flags, sattr, label);
|
|
|
+ res = ctx->state;
|
|
|
if (status == 0)
|
|
|
break;
|
|
|
/* NOTE: BAD_SEQID means the server and client disagree about the
|
|
@@ -2122,7 +2242,8 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir,
|
|
|
|
|
|
static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
|
|
|
struct nfs_fattr *fattr, struct iattr *sattr,
|
|
|
- struct nfs4_state *state)
|
|
|
+ struct nfs4_state *state, struct nfs4_label *ilabel,
|
|
|
+ struct nfs4_label *olabel)
|
|
|
{
|
|
|
struct nfs_server *server = NFS_SERVER(inode);
|
|
|
struct nfs_setattrargs arg = {
|
|
@@ -2130,9 +2251,11 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
|
|
|
.iap = sattr,
|
|
|
.server = server,
|
|
|
.bitmask = server->attr_bitmask,
|
|
|
+ .label = ilabel,
|
|
|
};
|
|
|
struct nfs_setattrres res = {
|
|
|
.fattr = fattr,
|
|
|
+ .label = olabel,
|
|
|
.server = server,
|
|
|
};
|
|
|
struct rpc_message msg = {
|
|
@@ -2146,6 +2269,10 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
|
|
|
bool truncate;
|
|
|
int status;
|
|
|
|
|
|
+ arg.bitmask = nfs4_bitmask(server, ilabel);
|
|
|
+ if (ilabel)
|
|
|
+ arg.bitmask = nfs4_bitmask(server, olabel);
|
|
|
+
|
|
|
nfs_fattr_init(fattr);
|
|
|
|
|
|
/* Servers should only apply open mode checks for file size changes */
|
|
@@ -2172,7 +2299,8 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
|
|
|
|
|
|
static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
|
|
|
struct nfs_fattr *fattr, struct iattr *sattr,
|
|
|
- struct nfs4_state *state)
|
|
|
+ struct nfs4_state *state, struct nfs4_label *ilabel,
|
|
|
+ struct nfs4_label *olabel)
|
|
|
{
|
|
|
struct nfs_server *server = NFS_SERVER(inode);
|
|
|
struct nfs4_exception exception = {
|
|
@@ -2181,7 +2309,7 @@ static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
|
|
|
};
|
|
|
int err;
|
|
|
do {
|
|
|
- err = _nfs4_do_setattr(inode, cred, fattr, sattr, state);
|
|
|
+ err = _nfs4_do_setattr(inode, cred, fattr, sattr, state, ilabel, olabel);
|
|
|
switch (err) {
|
|
|
case -NFS4ERR_OPENMODE:
|
|
|
if (!(sattr->ia_valid & ATTR_SIZE)) {
|
|
@@ -2426,14 +2554,18 @@ static struct inode *
|
|
|
nfs4_atomic_open(struct inode *dir, struct nfs_open_context *ctx, int open_flags, struct iattr *attr)
|
|
|
{
|
|
|
struct nfs4_state *state;
|
|
|
+ struct nfs4_label l = {0, 0, 0, NULL}, *label = NULL;
|
|
|
+
|
|
|
+ label = nfs4_label_init_security(dir, ctx->dentry, attr, &l);
|
|
|
|
|
|
/* Protect against concurrent sillydeletes */
|
|
|
- state = nfs4_do_open(dir, ctx->dentry, ctx->mode, open_flags, attr,
|
|
|
- ctx->cred, &ctx->mdsthreshold);
|
|
|
+ state = nfs4_do_open(dir, ctx, open_flags, attr, label);
|
|
|
+
|
|
|
+ nfs4_label_release_security(label);
|
|
|
+
|
|
|
if (IS_ERR(state))
|
|
|
return ERR_CAST(state);
|
|
|
- ctx->state = state;
|
|
|
- return igrab(state->inode);
|
|
|
+ return state->inode;
|
|
|
}
|
|
|
|
|
|
static void nfs4_close_context(struct nfs_open_context *ctx, int is_sync)
|
|
@@ -2489,7 +2621,17 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
|
|
|
server->caps |= NFS_CAP_CTIME;
|
|
|
if (res.attr_bitmask[1] & FATTR4_WORD1_TIME_MODIFY)
|
|
|
server->caps |= NFS_CAP_MTIME;
|
|
|
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
|
|
|
+ if (res.attr_bitmask[2] & FATTR4_WORD2_SECURITY_LABEL)
|
|
|
+ server->caps |= NFS_CAP_SECURITY_LABEL;
|
|
|
+#endif
|
|
|
+ memcpy(server->attr_bitmask_nl, res.attr_bitmask,
|
|
|
+ sizeof(server->attr_bitmask));
|
|
|
|
|
|
+ if (server->caps & NFS_CAP_SECURITY_LABEL) {
|
|
|
+ server->attr_bitmask_nl[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
|
|
|
+ res.attr_bitmask[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
|
|
|
+ }
|
|
|
memcpy(server->cache_consistency_bitmask, res.attr_bitmask, sizeof(server->cache_consistency_bitmask));
|
|
|
server->cache_consistency_bitmask[0] &= FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE;
|
|
|
server->cache_consistency_bitmask[1] &= FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY;
|
|
@@ -2515,8 +2657,9 @@ int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle)
|
|
|
static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
|
|
|
struct nfs_fsinfo *info)
|
|
|
{
|
|
|
+ u32 bitmask[3];
|
|
|
struct nfs4_lookup_root_arg args = {
|
|
|
- .bitmask = nfs4_fattr_bitmap,
|
|
|
+ .bitmask = bitmask,
|
|
|
};
|
|
|
struct nfs4_lookup_res res = {
|
|
|
.server = server,
|
|
@@ -2529,6 +2672,13 @@ static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
|
|
|
.rpc_resp = &res,
|
|
|
};
|
|
|
|
|
|
+ bitmask[0] = nfs4_fattr_bitmap[0];
|
|
|
+ bitmask[1] = nfs4_fattr_bitmap[1];
|
|
|
+ /*
|
|
|
+ * Process the label in the upcoming getfattr
|
|
|
+ */
|
|
|
+ bitmask[2] = nfs4_fattr_bitmap[2] & ~FATTR4_WORD2_SECURITY_LABEL;
|
|
|
+
|
|
|
nfs_fattr_init(info->fattr);
|
|
|
return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
|
|
|
}
|
|
@@ -2648,6 +2798,7 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *mntfh,
|
|
|
{
|
|
|
int error;
|
|
|
struct nfs_fattr *fattr = info->fattr;
|
|
|
+ struct nfs4_label *label = NULL;
|
|
|
|
|
|
error = nfs4_server_capabilities(server, mntfh);
|
|
|
if (error < 0) {
|
|
@@ -2655,16 +2806,23 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *mntfh,
|
|
|
return error;
|
|
|
}
|
|
|
|
|
|
- error = nfs4_proc_getattr(server, mntfh, fattr);
|
|
|
+ label = nfs4_label_alloc(server, GFP_KERNEL);
|
|
|
+ if (IS_ERR(label))
|
|
|
+ return PTR_ERR(label);
|
|
|
+
|
|
|
+ error = nfs4_proc_getattr(server, mntfh, fattr, label);
|
|
|
if (error < 0) {
|
|
|
dprintk("nfs4_get_root: getattr error = %d\n", -error);
|
|
|
- return error;
|
|
|
+ goto err_free_label;
|
|
|
}
|
|
|
|
|
|
if (fattr->valid & NFS_ATTR_FATTR_FSID &&
|
|
|
!nfs_fsid_equal(&server->fsid, &fattr->fsid))
|
|
|
memcpy(&server->fsid, &fattr->fsid, sizeof(server->fsid));
|
|
|
|
|
|
+err_free_label:
|
|
|
+ nfs4_label_free(label);
|
|
|
+
|
|
|
return error;
|
|
|
}
|
|
|
|
|
@@ -2711,7 +2869,8 @@ out:
|
|
|
return status;
|
|
|
}
|
|
|
|
|
|
-static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr)
|
|
|
+static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
|
|
|
+ struct nfs_fattr *fattr, struct nfs4_label *label)
|
|
|
{
|
|
|
struct nfs4_getattr_arg args = {
|
|
|
.fh = fhandle,
|
|
@@ -2719,6 +2878,7 @@ static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
|
|
|
};
|
|
|
struct nfs4_getattr_res res = {
|
|
|
.fattr = fattr,
|
|
|
+ .label = label,
|
|
|
.server = server,
|
|
|
};
|
|
|
struct rpc_message msg = {
|
|
@@ -2726,18 +2886,21 @@ static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
|
|
|
.rpc_argp = &args,
|
|
|
.rpc_resp = &res,
|
|
|
};
|
|
|
-
|
|
|
+
|
|
|
+ args.bitmask = nfs4_bitmask(server, label);
|
|
|
+
|
|
|
nfs_fattr_init(fattr);
|
|
|
return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
|
|
|
}
|
|
|
|
|
|
-static int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr)
|
|
|
+static int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
|
|
|
+ struct nfs_fattr *fattr, struct nfs4_label *label)
|
|
|
{
|
|
|
struct nfs4_exception exception = { };
|
|
|
int err;
|
|
|
do {
|
|
|
err = nfs4_handle_exception(server,
|
|
|
- _nfs4_proc_getattr(server, fhandle, fattr),
|
|
|
+ _nfs4_proc_getattr(server, fhandle, fattr, label),
|
|
|
&exception);
|
|
|
} while (exception.retry);
|
|
|
return err;
|
|
@@ -2767,6 +2930,7 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
|
|
|
struct inode *inode = dentry->d_inode;
|
|
|
struct rpc_cred *cred = NULL;
|
|
|
struct nfs4_state *state = NULL;
|
|
|
+ struct nfs4_label *label = NULL;
|
|
|
int status;
|
|
|
|
|
|
if (pnfs_ld_layoutret_on_setattr(inode))
|
|
@@ -2793,15 +2957,22 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- status = nfs4_do_setattr(inode, cred, fattr, sattr, state);
|
|
|
- if (status == 0)
|
|
|
+ label = nfs4_label_alloc(NFS_SERVER(inode), GFP_KERNEL);
|
|
|
+ if (IS_ERR(label))
|
|
|
+ return PTR_ERR(label);
|
|
|
+
|
|
|
+ status = nfs4_do_setattr(inode, cred, fattr, sattr, state, NULL, label);
|
|
|
+ if (status == 0) {
|
|
|
nfs_setattr_update_inode(inode, sattr);
|
|
|
+ nfs_setsecurity(inode, fattr, label);
|
|
|
+ }
|
|
|
+ nfs4_label_free(label);
|
|
|
return status;
|
|
|
}
|
|
|
|
|
|
static int _nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir,
|
|
|
const struct qstr *name, struct nfs_fh *fhandle,
|
|
|
- struct nfs_fattr *fattr)
|
|
|
+ struct nfs_fattr *fattr, struct nfs4_label *label)
|
|
|
{
|
|
|
struct nfs_server *server = NFS_SERVER(dir);
|
|
|
int status;
|
|
@@ -2813,6 +2984,7 @@ static int _nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir,
|
|
|
struct nfs4_lookup_res res = {
|
|
|
.server = server,
|
|
|
.fattr = fattr,
|
|
|
+ .label = label,
|
|
|
.fh = fhandle,
|
|
|
};
|
|
|
struct rpc_message msg = {
|
|
@@ -2821,6 +2993,8 @@ static int _nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir,
|
|
|
.rpc_resp = &res,
|
|
|
};
|
|
|
|
|
|
+ args.bitmask = nfs4_bitmask(server, label);
|
|
|
+
|
|
|
nfs_fattr_init(fattr);
|
|
|
|
|
|
dprintk("NFS call lookup %s\n", name->name);
|
|
@@ -2839,13 +3013,13 @@ static void nfs_fixup_secinfo_attributes(struct nfs_fattr *fattr)
|
|
|
|
|
|
static int nfs4_proc_lookup_common(struct rpc_clnt **clnt, struct inode *dir,
|
|
|
struct qstr *name, struct nfs_fh *fhandle,
|
|
|
- struct nfs_fattr *fattr)
|
|
|
+ struct nfs_fattr *fattr, struct nfs4_label *label)
|
|
|
{
|
|
|
struct nfs4_exception exception = { };
|
|
|
struct rpc_clnt *client = *clnt;
|
|
|
int err;
|
|
|
do {
|
|
|
- err = _nfs4_proc_lookup(client, dir, name, fhandle, fattr);
|
|
|
+ err = _nfs4_proc_lookup(client, dir, name, fhandle, fattr, label);
|
|
|
switch (err) {
|
|
|
case -NFS4ERR_BADNAME:
|
|
|
err = -ENOENT;
|
|
@@ -2879,12 +3053,13 @@ out:
|
|
|
}
|
|
|
|
|
|
static int nfs4_proc_lookup(struct inode *dir, struct qstr *name,
|
|
|
- struct nfs_fh *fhandle, struct nfs_fattr *fattr)
|
|
|
+ struct nfs_fh *fhandle, struct nfs_fattr *fattr,
|
|
|
+ struct nfs4_label *label)
|
|
|
{
|
|
|
int status;
|
|
|
struct rpc_clnt *client = NFS_CLIENT(dir);
|
|
|
|
|
|
- status = nfs4_proc_lookup_common(&client, dir, name, fhandle, fattr);
|
|
|
+ status = nfs4_proc_lookup_common(&client, dir, name, fhandle, fattr, label);
|
|
|
if (client != NFS_CLIENT(dir)) {
|
|
|
rpc_shutdown_client(client);
|
|
|
nfs_fixup_secinfo_attributes(fattr);
|
|
@@ -2899,7 +3074,7 @@ nfs4_proc_lookup_mountpoint(struct inode *dir, struct qstr *name,
|
|
|
int status;
|
|
|
struct rpc_clnt *client = rpc_clone_client(NFS_CLIENT(dir));
|
|
|
|
|
|
- status = nfs4_proc_lookup_common(&client, dir, name, fhandle, fattr);
|
|
|
+ status = nfs4_proc_lookup_common(&client, dir, name, fhandle, fattr, NULL);
|
|
|
if (status < 0) {
|
|
|
rpc_shutdown_client(client);
|
|
|
return ERR_PTR(status);
|
|
@@ -2924,7 +3099,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
|
|
|
.rpc_cred = entry->cred,
|
|
|
};
|
|
|
int mode = entry->mask;
|
|
|
- int status;
|
|
|
+ int status = 0;
|
|
|
|
|
|
/*
|
|
|
* Determine which access bits we want to ask for...
|
|
@@ -3029,6 +3204,7 @@ static int
|
|
|
nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
|
|
|
int flags)
|
|
|
{
|
|
|
+ struct nfs4_label l, *ilabel = NULL;
|
|
|
struct nfs_open_context *ctx;
|
|
|
struct nfs4_state *state;
|
|
|
int status = 0;
|
|
@@ -3037,19 +3213,16 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
|
|
|
if (IS_ERR(ctx))
|
|
|
return PTR_ERR(ctx);
|
|
|
|
|
|
+ ilabel = nfs4_label_init_security(dir, dentry, sattr, &l);
|
|
|
+
|
|
|
sattr->ia_mode &= ~current_umask();
|
|
|
- state = nfs4_do_open(dir, dentry, ctx->mode,
|
|
|
- flags, sattr, ctx->cred,
|
|
|
- &ctx->mdsthreshold);
|
|
|
- d_drop(dentry);
|
|
|
+ state = nfs4_do_open(dir, ctx, flags, sattr, ilabel);
|
|
|
if (IS_ERR(state)) {
|
|
|
status = PTR_ERR(state);
|
|
|
goto out;
|
|
|
}
|
|
|
- d_add(dentry, igrab(state->inode));
|
|
|
- nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
|
|
|
- ctx->state = state;
|
|
|
out:
|
|
|
+ nfs4_label_release_security(ilabel);
|
|
|
put_nfs_open_context(ctx);
|
|
|
return status;
|
|
|
}
|
|
@@ -3098,6 +3271,8 @@ static void nfs4_proc_unlink_setup(struct rpc_message *msg, struct inode *dir)
|
|
|
res->server = server;
|
|
|
msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE];
|
|
|
nfs41_init_sequence(&args->seq_args, &res->seq_res, 1);
|
|
|
+
|
|
|
+ nfs_fattr_init(res->dir_attr);
|
|
|
}
|
|
|
|
|
|
static void nfs4_proc_unlink_rpc_prepare(struct rpc_task *task, struct nfs_unlinkdata *data)
|
|
@@ -3173,7 +3348,7 @@ static int _nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name,
|
|
|
.rpc_resp = &res,
|
|
|
};
|
|
|
int status = -ENOMEM;
|
|
|
-
|
|
|
+
|
|
|
status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
|
|
|
if (!status) {
|
|
|
update_changeattr(old_dir, &res.old_cinfo);
|
|
@@ -3207,6 +3382,7 @@ static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *
|
|
|
};
|
|
|
struct nfs4_link_res res = {
|
|
|
.server = server,
|
|
|
+ .label = NULL,
|
|
|
};
|
|
|
struct rpc_message msg = {
|
|
|
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LINK],
|
|
@@ -3219,11 +3395,24 @@ static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *
|
|
|
if (res.fattr == NULL)
|
|
|
goto out;
|
|
|
|
|
|
+ res.label = nfs4_label_alloc(server, GFP_KERNEL);
|
|
|
+ if (IS_ERR(res.label)) {
|
|
|
+ status = PTR_ERR(res.label);
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+ arg.bitmask = nfs4_bitmask(server, res.label);
|
|
|
+
|
|
|
status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
|
|
|
if (!status) {
|
|
|
update_changeattr(dir, &res.cinfo);
|
|
|
- nfs_post_op_update_inode(inode, res.fattr);
|
|
|
+ status = nfs_post_op_update_inode(inode, res.fattr);
|
|
|
+ if (!status)
|
|
|
+ nfs_setsecurity(inode, res.fattr, res.label);
|
|
|
}
|
|
|
+
|
|
|
+
|
|
|
+ nfs4_label_free(res.label);
|
|
|
+
|
|
|
out:
|
|
|
nfs_free_fattr(res.fattr);
|
|
|
return status;
|
|
@@ -3247,6 +3436,7 @@ struct nfs4_createdata {
|
|
|
struct nfs4_create_res res;
|
|
|
struct nfs_fh fh;
|
|
|
struct nfs_fattr fattr;
|
|
|
+ struct nfs4_label *label;
|
|
|
};
|
|
|
|
|
|
static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir,
|
|
@@ -3258,6 +3448,10 @@ static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir,
|
|
|
if (data != NULL) {
|
|
|
struct nfs_server *server = NFS_SERVER(dir);
|
|
|
|
|
|
+ data->label = nfs4_label_alloc(server, GFP_KERNEL);
|
|
|
+ if (IS_ERR(data->label))
|
|
|
+ goto out_free;
|
|
|
+
|
|
|
data->msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE];
|
|
|
data->msg.rpc_argp = &data->arg;
|
|
|
data->msg.rpc_resp = &data->res;
|
|
@@ -3266,13 +3460,17 @@ static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir,
|
|
|
data->arg.name = name;
|
|
|
data->arg.attrs = sattr;
|
|
|
data->arg.ftype = ftype;
|
|
|
- data->arg.bitmask = server->attr_bitmask;
|
|
|
+ data->arg.bitmask = nfs4_bitmask(server, data->label);
|
|
|
data->res.server = server;
|
|
|
data->res.fh = &data->fh;
|
|
|
data->res.fattr = &data->fattr;
|
|
|
+ data->res.label = data->label;
|
|
|
nfs_fattr_init(data->res.fattr);
|
|
|
}
|
|
|
return data;
|
|
|
+out_free:
|
|
|
+ kfree(data);
|
|
|
+ return NULL;
|
|
|
}
|
|
|
|
|
|
static int nfs4_do_create(struct inode *dir, struct dentry *dentry, struct nfs4_createdata *data)
|
|
@@ -3281,18 +3479,20 @@ static int nfs4_do_create(struct inode *dir, struct dentry *dentry, struct nfs4_
|
|
|
&data->arg.seq_args, &data->res.seq_res, 1);
|
|
|
if (status == 0) {
|
|
|
update_changeattr(dir, &data->res.dir_cinfo);
|
|
|
- status = nfs_instantiate(dentry, data->res.fh, data->res.fattr);
|
|
|
+ status = nfs_instantiate(dentry, data->res.fh, data->res.fattr, data->res.label);
|
|
|
}
|
|
|
return status;
|
|
|
}
|
|
|
|
|
|
static void nfs4_free_createdata(struct nfs4_createdata *data)
|
|
|
{
|
|
|
+ nfs4_label_free(data->label);
|
|
|
kfree(data);
|
|
|
}
|
|
|
|
|
|
static int _nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
|
|
|
- struct page *page, unsigned int len, struct iattr *sattr)
|
|
|
+ struct page *page, unsigned int len, struct iattr *sattr,
|
|
|
+ struct nfs4_label *label)
|
|
|
{
|
|
|
struct nfs4_createdata *data;
|
|
|
int status = -ENAMETOOLONG;
|
|
@@ -3308,6 +3508,7 @@ static int _nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
|
|
|
data->msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SYMLINK];
|
|
|
data->arg.u.symlink.pages = &page;
|
|
|
data->arg.u.symlink.len = len;
|
|
|
+ data->arg.label = label;
|
|
|
|
|
|
status = nfs4_do_create(dir, dentry, data);
|
|
|
|
|
@@ -3320,18 +3521,24 @@ static int nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
|
|
|
struct page *page, unsigned int len, struct iattr *sattr)
|
|
|
{
|
|
|
struct nfs4_exception exception = { };
|
|
|
+ struct nfs4_label l, *label = NULL;
|
|
|
int err;
|
|
|
+
|
|
|
+ label = nfs4_label_init_security(dir, dentry, sattr, &l);
|
|
|
+
|
|
|
do {
|
|
|
err = nfs4_handle_exception(NFS_SERVER(dir),
|
|
|
_nfs4_proc_symlink(dir, dentry, page,
|
|
|
- len, sattr),
|
|
|
+ len, sattr, label),
|
|
|
&exception);
|
|
|
} while (exception.retry);
|
|
|
+
|
|
|
+ nfs4_label_release_security(label);
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
static int _nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
|
|
|
- struct iattr *sattr)
|
|
|
+ struct iattr *sattr, struct nfs4_label *label)
|
|
|
{
|
|
|
struct nfs4_createdata *data;
|
|
|
int status = -ENOMEM;
|
|
@@ -3340,6 +3547,7 @@ static int _nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
|
|
|
if (data == NULL)
|
|
|
goto out;
|
|
|
|
|
|
+ data->arg.label = label;
|
|
|
status = nfs4_do_create(dir, dentry, data);
|
|
|
|
|
|
nfs4_free_createdata(data);
|
|
@@ -3351,14 +3559,19 @@ static int nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
|
|
|
struct iattr *sattr)
|
|
|
{
|
|
|
struct nfs4_exception exception = { };
|
|
|
+ struct nfs4_label l, *label = NULL;
|
|
|
int err;
|
|
|
|
|
|
+ label = nfs4_label_init_security(dir, dentry, sattr, &l);
|
|
|
+
|
|
|
sattr->ia_mode &= ~current_umask();
|
|
|
do {
|
|
|
err = nfs4_handle_exception(NFS_SERVER(dir),
|
|
|
- _nfs4_proc_mkdir(dir, dentry, sattr),
|
|
|
+ _nfs4_proc_mkdir(dir, dentry, sattr, label),
|
|
|
&exception);
|
|
|
} while (exception.retry);
|
|
|
+ nfs4_label_release_security(label);
|
|
|
+
|
|
|
return err;
|
|
|
}
|
|
|
|
|
@@ -3416,7 +3629,7 @@ static int nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
|
|
|
}
|
|
|
|
|
|
static int _nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
|
|
|
- struct iattr *sattr, dev_t rdev)
|
|
|
+ struct iattr *sattr, struct nfs4_label *label, dev_t rdev)
|
|
|
{
|
|
|
struct nfs4_createdata *data;
|
|
|
int mode = sattr->ia_mode;
|
|
@@ -3441,7 +3654,8 @@ static int _nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
|
|
|
status = -EINVAL;
|
|
|
goto out_free;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
+ data->arg.label = label;
|
|
|
status = nfs4_do_create(dir, dentry, data);
|
|
|
out_free:
|
|
|
nfs4_free_createdata(data);
|
|
@@ -3453,14 +3667,20 @@ static int nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
|
|
|
struct iattr *sattr, dev_t rdev)
|
|
|
{
|
|
|
struct nfs4_exception exception = { };
|
|
|
+ struct nfs4_label l, *label = NULL;
|
|
|
int err;
|
|
|
|
|
|
+ label = nfs4_label_init_security(dir, dentry, sattr, &l);
|
|
|
+
|
|
|
sattr->ia_mode &= ~current_umask();
|
|
|
do {
|
|
|
err = nfs4_handle_exception(NFS_SERVER(dir),
|
|
|
- _nfs4_proc_mknod(dir, dentry, sattr, rdev),
|
|
|
+ _nfs4_proc_mknod(dir, dentry, sattr, label, rdev),
|
|
|
&exception);
|
|
|
} while (exception.retry);
|
|
|
+
|
|
|
+ nfs4_label_release_security(label);
|
|
|
+
|
|
|
return err;
|
|
|
}
|
|
|
|
|
@@ -4187,6 +4407,155 @@ static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
|
|
|
+static int _nfs4_get_security_label(struct inode *inode, void *buf,
|
|
|
+ size_t buflen)
|
|
|
+{
|
|
|
+ struct nfs_server *server = NFS_SERVER(inode);
|
|
|
+ struct nfs_fattr fattr;
|
|
|
+ struct nfs4_label label = {0, 0, buflen, buf};
|
|
|
+
|
|
|
+ u32 bitmask[3] = { 0, 0, FATTR4_WORD2_SECURITY_LABEL };
|
|
|
+ struct nfs4_getattr_arg args = {
|
|
|
+ .fh = NFS_FH(inode),
|
|
|
+ .bitmask = bitmask,
|
|
|
+ };
|
|
|
+ struct nfs4_getattr_res res = {
|
|
|
+ .fattr = &fattr,
|
|
|
+ .label = &label,
|
|
|
+ .server = server,
|
|
|
+ };
|
|
|
+ struct rpc_message msg = {
|
|
|
+ .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETATTR],
|
|
|
+ .rpc_argp = &args,
|
|
|
+ .rpc_resp = &res,
|
|
|
+ };
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ nfs_fattr_init(&fattr);
|
|
|
+
|
|
|
+ ret = rpc_call_sync(server->client, &msg, 0);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+ if (!(fattr.valid & NFS_ATTR_FATTR_V4_SECURITY_LABEL))
|
|
|
+ return -ENOENT;
|
|
|
+ if (buflen < label.len)
|
|
|
+ return -ERANGE;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int nfs4_get_security_label(struct inode *inode, void *buf,
|
|
|
+ size_t buflen)
|
|
|
+{
|
|
|
+ struct nfs4_exception exception = { };
|
|
|
+ int err;
|
|
|
+
|
|
|
+ if (!nfs_server_capable(inode, NFS_CAP_SECURITY_LABEL))
|
|
|
+ return -EOPNOTSUPP;
|
|
|
+
|
|
|
+ do {
|
|
|
+ err = nfs4_handle_exception(NFS_SERVER(inode),
|
|
|
+ _nfs4_get_security_label(inode, buf, buflen),
|
|
|
+ &exception);
|
|
|
+ } while (exception.retry);
|
|
|
+ return err;
|
|
|
+}
|
|
|
+
|
|
|
+static int _nfs4_do_set_security_label(struct inode *inode,
|
|
|
+ struct nfs4_label *ilabel,
|
|
|
+ struct nfs_fattr *fattr,
|
|
|
+ struct nfs4_label *olabel)
|
|
|
+{
|
|
|
+
|
|
|
+ struct iattr sattr = {0};
|
|
|
+ struct nfs_server *server = NFS_SERVER(inode);
|
|
|
+ const u32 bitmask[3] = { 0, 0, FATTR4_WORD2_SECURITY_LABEL };
|
|
|
+ struct nfs_setattrargs args = {
|
|
|
+ .fh = NFS_FH(inode),
|
|
|
+ .iap = &sattr,
|
|
|
+ .server = server,
|
|
|
+ .bitmask = bitmask,
|
|
|
+ .label = ilabel,
|
|
|
+ };
|
|
|
+ struct nfs_setattrres res = {
|
|
|
+ .fattr = fattr,
|
|
|
+ .label = olabel,
|
|
|
+ .server = server,
|
|
|
+ };
|
|
|
+ struct rpc_message msg = {
|
|
|
+ .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETATTR],
|
|
|
+ .rpc_argp = &args,
|
|
|
+ .rpc_resp = &res,
|
|
|
+ };
|
|
|
+ int status;
|
|
|
+
|
|
|
+ nfs4_stateid_copy(&args.stateid, &zero_stateid);
|
|
|
+
|
|
|
+ status = rpc_call_sync(server->client, &msg, 0);
|
|
|
+ if (status)
|
|
|
+ dprintk("%s failed: %d\n", __func__, status);
|
|
|
+
|
|
|
+ return status;
|
|
|
+}
|
|
|
+
|
|
|
+static int nfs4_do_set_security_label(struct inode *inode,
|
|
|
+ struct nfs4_label *ilabel,
|
|
|
+ struct nfs_fattr *fattr,
|
|
|
+ struct nfs4_label *olabel)
|
|
|
+{
|
|
|
+ struct nfs4_exception exception = { };
|
|
|
+ int err;
|
|
|
+
|
|
|
+ do {
|
|
|
+ err = nfs4_handle_exception(NFS_SERVER(inode),
|
|
|
+ _nfs4_do_set_security_label(inode, ilabel,
|
|
|
+ fattr, olabel),
|
|
|
+ &exception);
|
|
|
+ } while (exception.retry);
|
|
|
+ return err;
|
|
|
+}
|
|
|
+
|
|
|
+static int
|
|
|
+nfs4_set_security_label(struct dentry *dentry, const void *buf, size_t buflen)
|
|
|
+{
|
|
|
+ struct nfs4_label ilabel, *olabel = NULL;
|
|
|
+ struct nfs_fattr fattr;
|
|
|
+ struct rpc_cred *cred;
|
|
|
+ struct inode *inode = dentry->d_inode;
|
|
|
+ int status;
|
|
|
+
|
|
|
+ if (!nfs_server_capable(inode, NFS_CAP_SECURITY_LABEL))
|
|
|
+ return -EOPNOTSUPP;
|
|
|
+
|
|
|
+ nfs_fattr_init(&fattr);
|
|
|
+
|
|
|
+ ilabel.pi = 0;
|
|
|
+ ilabel.lfs = 0;
|
|
|
+ ilabel.label = (char *)buf;
|
|
|
+ ilabel.len = buflen;
|
|
|
+
|
|
|
+ cred = rpc_lookup_cred();
|
|
|
+ if (IS_ERR(cred))
|
|
|
+ return PTR_ERR(cred);
|
|
|
+
|
|
|
+ olabel = nfs4_label_alloc(NFS_SERVER(inode), GFP_KERNEL);
|
|
|
+ if (IS_ERR(olabel)) {
|
|
|
+ status = -PTR_ERR(olabel);
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ status = nfs4_do_set_security_label(inode, &ilabel, &fattr, olabel);
|
|
|
+ if (status == 0)
|
|
|
+ nfs_setsecurity(inode, &fattr, olabel);
|
|
|
+
|
|
|
+ nfs4_label_free(olabel);
|
|
|
+out:
|
|
|
+ put_rpccred(cred);
|
|
|
+ return status;
|
|
|
+}
|
|
|
+#endif /* CONFIG_NFS_V4_SECURITY_LABEL */
|
|
|
+
|
|
|
+
|
|
|
static int
|
|
|
nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, struct nfs4_state *state)
|
|
|
{
|
|
@@ -4345,7 +4714,7 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program,
|
|
|
/* cb_client4 */
|
|
|
rcu_read_lock();
|
|
|
setclientid.sc_netid_len = scnprintf(setclientid.sc_netid,
|
|
|
- sizeof(setclientid.sc_netid),
|
|
|
+ sizeof(setclientid.sc_netid), "%s",
|
|
|
rpc_peeraddr2str(clp->cl_rpcclient,
|
|
|
RPC_DISPLAY_NETID));
|
|
|
rcu_read_unlock();
|
|
@@ -5056,13 +5425,18 @@ static int nfs41_check_expired_locks(struct nfs4_state *state)
|
|
|
|
|
|
list_for_each_entry(lsp, &state->lock_states, ls_locks) {
|
|
|
if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags)) {
|
|
|
- status = nfs41_test_stateid(server, &lsp->ls_stateid);
|
|
|
+ struct rpc_cred *cred = lsp->ls_state->owner->so_cred;
|
|
|
+
|
|
|
+ status = nfs41_test_stateid(server,
|
|
|
+ &lsp->ls_stateid,
|
|
|
+ cred);
|
|
|
if (status != NFS_OK) {
|
|
|
/* Free the stateid unless the server
|
|
|
* informs us the stateid is unrecognized. */
|
|
|
if (status != -NFS4ERR_BAD_STATEID)
|
|
|
nfs41_free_stateid(server,
|
|
|
- &lsp->ls_stateid);
|
|
|
+ &lsp->ls_stateid,
|
|
|
+ cred);
|
|
|
clear_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags);
|
|
|
ret = status;
|
|
|
}
|
|
@@ -5295,6 +5669,53 @@ static size_t nfs4_xattr_list_nfs4_acl(struct dentry *dentry, char *list,
|
|
|
return len;
|
|
|
}
|
|
|
|
|
|
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
|
|
|
+static inline int nfs4_server_supports_labels(struct nfs_server *server)
|
|
|
+{
|
|
|
+ return server->caps & NFS_CAP_SECURITY_LABEL;
|
|
|
+}
|
|
|
+
|
|
|
+static int nfs4_xattr_set_nfs4_label(struct dentry *dentry, const char *key,
|
|
|
+ const void *buf, size_t buflen,
|
|
|
+ int flags, int type)
|
|
|
+{
|
|
|
+ if (security_ismaclabel(key))
|
|
|
+ return nfs4_set_security_label(dentry, buf, buflen);
|
|
|
+
|
|
|
+ return -EOPNOTSUPP;
|
|
|
+}
|
|
|
+
|
|
|
+static int nfs4_xattr_get_nfs4_label(struct dentry *dentry, const char *key,
|
|
|
+ void *buf, size_t buflen, int type)
|
|
|
+{
|
|
|
+ if (security_ismaclabel(key))
|
|
|
+ return nfs4_get_security_label(dentry->d_inode, buf, buflen);
|
|
|
+ return -EOPNOTSUPP;
|
|
|
+}
|
|
|
+
|
|
|
+static size_t nfs4_xattr_list_nfs4_label(struct dentry *dentry, char *list,
|
|
|
+ size_t list_len, const char *name,
|
|
|
+ size_t name_len, int type)
|
|
|
+{
|
|
|
+ size_t len = 0;
|
|
|
+
|
|
|
+ if (nfs_server_capable(dentry->d_inode, NFS_CAP_SECURITY_LABEL)) {
|
|
|
+ len = security_inode_listsecurity(dentry->d_inode, NULL, 0);
|
|
|
+ if (list && len <= list_len)
|
|
|
+ security_inode_listsecurity(dentry->d_inode, list, len);
|
|
|
+ }
|
|
|
+ return len;
|
|
|
+}
|
|
|
+
|
|
|
+static const struct xattr_handler nfs4_xattr_nfs4_label_handler = {
|
|
|
+ .prefix = XATTR_SECURITY_PREFIX,
|
|
|
+ .list = nfs4_xattr_list_nfs4_label,
|
|
|
+ .get = nfs4_xattr_get_nfs4_label,
|
|
|
+ .set = nfs4_xattr_set_nfs4_label,
|
|
|
+};
|
|
|
+#endif
|
|
|
+
|
|
|
+
|
|
|
/*
|
|
|
* nfs_fhget will use either the mounted_on_fileid or the fileid
|
|
|
*/
|
|
@@ -5318,7 +5739,7 @@ static int _nfs4_proc_fs_locations(struct rpc_clnt *client, struct inode *dir,
|
|
|
struct page *page)
|
|
|
{
|
|
|
struct nfs_server *server = NFS_SERVER(dir);
|
|
|
- u32 bitmask[2] = {
|
|
|
+ u32 bitmask[3] = {
|
|
|
[0] = FATTR4_WORD0_FSID | FATTR4_WORD0_FS_LOCATIONS,
|
|
|
};
|
|
|
struct nfs4_fs_locations_arg args = {
|
|
@@ -5505,7 +5926,8 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred)
|
|
|
struct nfs41_exchange_id_args args = {
|
|
|
.verifier = &verifier,
|
|
|
.client = clp,
|
|
|
- .flags = EXCHGID4_FLAG_SUPP_MOVED_REFER,
|
|
|
+ .flags = EXCHGID4_FLAG_SUPP_MOVED_REFER |
|
|
|
+ EXCHGID4_FLAG_BIND_PRINC_STATEID,
|
|
|
};
|
|
|
struct nfs41_exchange_id_res res = {
|
|
|
0
|
|
@@ -5762,17 +6184,14 @@ int nfs4_proc_get_lease_time(struct nfs_client *clp, struct nfs_fsinfo *fsinfo)
|
|
|
*/
|
|
|
static void nfs4_init_channel_attrs(struct nfs41_create_session_args *args)
|
|
|
{
|
|
|
- struct nfs4_session *session = args->client->cl_session;
|
|
|
- unsigned int mxrqst_sz = session->fc_target_max_rqst_sz,
|
|
|
- mxresp_sz = session->fc_target_max_resp_sz;
|
|
|
+ unsigned int max_rqst_sz, max_resp_sz;
|
|
|
+
|
|
|
+ max_rqst_sz = NFS_MAX_FILE_IO_SIZE + nfs41_maxwrite_overhead;
|
|
|
+ max_resp_sz = NFS_MAX_FILE_IO_SIZE + nfs41_maxread_overhead;
|
|
|
|
|
|
- if (mxrqst_sz == 0)
|
|
|
- mxrqst_sz = NFS_MAX_FILE_IO_SIZE;
|
|
|
- if (mxresp_sz == 0)
|
|
|
- mxresp_sz = NFS_MAX_FILE_IO_SIZE;
|
|
|
/* Fore channel attributes */
|
|
|
- args->fc_attrs.max_rqst_sz = mxrqst_sz;
|
|
|
- args->fc_attrs.max_resp_sz = mxresp_sz;
|
|
|
+ args->fc_attrs.max_rqst_sz = max_rqst_sz;
|
|
|
+ args->fc_attrs.max_resp_sz = max_resp_sz;
|
|
|
args->fc_attrs.max_ops = NFS4_MAX_OPS;
|
|
|
args->fc_attrs.max_reqs = max_session_slots;
|
|
|
|
|
@@ -6159,12 +6578,14 @@ static const struct rpc_call_ops nfs4_reclaim_complete_call_ops = {
|
|
|
/*
|
|
|
* Issue a global reclaim complete.
|
|
|
*/
|
|
|
-static int nfs41_proc_reclaim_complete(struct nfs_client *clp)
|
|
|
+static int nfs41_proc_reclaim_complete(struct nfs_client *clp,
|
|
|
+ struct rpc_cred *cred)
|
|
|
{
|
|
|
struct nfs4_reclaim_complete_data *calldata;
|
|
|
struct rpc_task *task;
|
|
|
struct rpc_message msg = {
|
|
|
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RECLAIM_COMPLETE],
|
|
|
+ .rpc_cred = cred,
|
|
|
};
|
|
|
struct rpc_task_setup task_setup_data = {
|
|
|
.rpc_client = clp->cl_rpcclient,
|
|
@@ -6348,6 +6769,7 @@ nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags)
|
|
|
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LAYOUTGET],
|
|
|
.rpc_argp = &lgp->args,
|
|
|
.rpc_resp = &lgp->res,
|
|
|
+ .rpc_cred = lgp->cred,
|
|
|
};
|
|
|
struct rpc_task_setup task_setup_data = {
|
|
|
.rpc_client = server->client,
|
|
@@ -6451,6 +6873,7 @@ int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp)
|
|
|
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LAYOUTRETURN],
|
|
|
.rpc_argp = &lrp->args,
|
|
|
.rpc_resp = &lrp->res,
|
|
|
+ .rpc_cred = lrp->cred,
|
|
|
};
|
|
|
struct rpc_task_setup task_setup_data = {
|
|
|
.rpc_client = lrp->clp->cl_rpcclient,
|
|
@@ -6520,7 +6943,9 @@ int nfs4_proc_getdevicelist(struct nfs_server *server,
|
|
|
EXPORT_SYMBOL_GPL(nfs4_proc_getdevicelist);
|
|
|
|
|
|
static int
|
|
|
-_nfs4_proc_getdeviceinfo(struct nfs_server *server, struct pnfs_device *pdev)
|
|
|
+_nfs4_proc_getdeviceinfo(struct nfs_server *server,
|
|
|
+ struct pnfs_device *pdev,
|
|
|
+ struct rpc_cred *cred)
|
|
|
{
|
|
|
struct nfs4_getdeviceinfo_args args = {
|
|
|
.pdev = pdev,
|
|
@@ -6532,6 +6957,7 @@ _nfs4_proc_getdeviceinfo(struct nfs_server *server, struct pnfs_device *pdev)
|
|
|
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETDEVICEINFO],
|
|
|
.rpc_argp = &args,
|
|
|
.rpc_resp = &res,
|
|
|
+ .rpc_cred = cred,
|
|
|
};
|
|
|
int status;
|
|
|
|
|
@@ -6542,14 +6968,16 @@ _nfs4_proc_getdeviceinfo(struct nfs_server *server, struct pnfs_device *pdev)
|
|
|
return status;
|
|
|
}
|
|
|
|
|
|
-int nfs4_proc_getdeviceinfo(struct nfs_server *server, struct pnfs_device *pdev)
|
|
|
+int nfs4_proc_getdeviceinfo(struct nfs_server *server,
|
|
|
+ struct pnfs_device *pdev,
|
|
|
+ struct rpc_cred *cred)
|
|
|
{
|
|
|
struct nfs4_exception exception = { };
|
|
|
int err;
|
|
|
|
|
|
do {
|
|
|
err = nfs4_handle_exception(server,
|
|
|
- _nfs4_proc_getdeviceinfo(server, pdev),
|
|
|
+ _nfs4_proc_getdeviceinfo(server, pdev, cred),
|
|
|
&exception);
|
|
|
} while (exception.retry);
|
|
|
return err;
|
|
@@ -6733,7 +7161,9 @@ out:
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
-static int _nfs41_test_stateid(struct nfs_server *server, nfs4_stateid *stateid)
|
|
|
+static int _nfs41_test_stateid(struct nfs_server *server,
|
|
|
+ nfs4_stateid *stateid,
|
|
|
+ struct rpc_cred *cred)
|
|
|
{
|
|
|
int status;
|
|
|
struct nfs41_test_stateid_args args = {
|
|
@@ -6744,6 +7174,7 @@ static int _nfs41_test_stateid(struct nfs_server *server, nfs4_stateid *stateid)
|
|
|
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_TEST_STATEID],
|
|
|
.rpc_argp = &args,
|
|
|
.rpc_resp = &res,
|
|
|
+ .rpc_cred = cred,
|
|
|
};
|
|
|
|
|
|
dprintk("NFS call test_stateid %p\n", stateid);
|
|
@@ -6764,17 +7195,20 @@ static int _nfs41_test_stateid(struct nfs_server *server, nfs4_stateid *stateid)
|
|
|
*
|
|
|
* @server: server / transport on which to perform the operation
|
|
|
* @stateid: state ID to test
|
|
|
+ * @cred: credential
|
|
|
*
|
|
|
* Returns NFS_OK if the server recognizes that "stateid" is valid.
|
|
|
* Otherwise a negative NFS4ERR value is returned if the operation
|
|
|
* failed or the state ID is not currently valid.
|
|
|
*/
|
|
|
-static int nfs41_test_stateid(struct nfs_server *server, nfs4_stateid *stateid)
|
|
|
+static int nfs41_test_stateid(struct nfs_server *server,
|
|
|
+ nfs4_stateid *stateid,
|
|
|
+ struct rpc_cred *cred)
|
|
|
{
|
|
|
struct nfs4_exception exception = { };
|
|
|
int err;
|
|
|
do {
|
|
|
- err = _nfs41_test_stateid(server, stateid);
|
|
|
+ err = _nfs41_test_stateid(server, stateid, cred);
|
|
|
if (err != -NFS4ERR_DELAY)
|
|
|
break;
|
|
|
nfs4_handle_exception(server, err, &exception);
|
|
@@ -6823,10 +7257,12 @@ const struct rpc_call_ops nfs41_free_stateid_ops = {
|
|
|
|
|
|
static struct rpc_task *_nfs41_free_stateid(struct nfs_server *server,
|
|
|
nfs4_stateid *stateid,
|
|
|
+ struct rpc_cred *cred,
|
|
|
bool privileged)
|
|
|
{
|
|
|
struct rpc_message msg = {
|
|
|
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FREE_STATEID],
|
|
|
+ .rpc_cred = cred,
|
|
|
};
|
|
|
struct rpc_task_setup task_setup = {
|
|
|
.rpc_client = server->client,
|
|
@@ -6859,16 +7295,19 @@ static struct rpc_task *_nfs41_free_stateid(struct nfs_server *server,
|
|
|
*
|
|
|
* @server: server / transport on which to perform the operation
|
|
|
* @stateid: state ID to release
|
|
|
+ * @cred: credential
|
|
|
*
|
|
|
* Returns NFS_OK if the server freed "stateid". Otherwise a
|
|
|
* negative NFS4ERR value is returned.
|
|
|
*/
|
|
|
-static int nfs41_free_stateid(struct nfs_server *server, nfs4_stateid *stateid)
|
|
|
+static int nfs41_free_stateid(struct nfs_server *server,
|
|
|
+ nfs4_stateid *stateid,
|
|
|
+ struct rpc_cred *cred)
|
|
|
{
|
|
|
struct rpc_task *task;
|
|
|
int ret;
|
|
|
|
|
|
- task = _nfs41_free_stateid(server, stateid, true);
|
|
|
+ task = _nfs41_free_stateid(server, stateid, cred, true);
|
|
|
if (IS_ERR(task))
|
|
|
return PTR_ERR(task);
|
|
|
ret = rpc_wait_for_completion_task(task);
|
|
@@ -6881,8 +7320,9 @@ static int nfs41_free_stateid(struct nfs_server *server, nfs4_stateid *stateid)
|
|
|
static int nfs41_free_lock_state(struct nfs_server *server, struct nfs4_lock_state *lsp)
|
|
|
{
|
|
|
struct rpc_task *task;
|
|
|
+ struct rpc_cred *cred = lsp->ls_state->owner->so_cred;
|
|
|
|
|
|
- task = _nfs41_free_stateid(server, &lsp->ls_stateid, false);
|
|
|
+ task = _nfs41_free_stateid(server, &lsp->ls_stateid, cred, false);
|
|
|
nfs4_free_lock_state(server, lsp);
|
|
|
if (IS_ERR(task))
|
|
|
return PTR_ERR(task);
|
|
@@ -7004,11 +7444,33 @@ static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = {
|
|
|
};
|
|
|
#endif
|
|
|
|
|
|
+#if defined(CONFIG_NFS_V4_2)
|
|
|
+static const struct nfs4_minor_version_ops nfs_v4_2_minor_ops = {
|
|
|
+ .minor_version = 2,
|
|
|
+ .init_caps = NFS_CAP_READDIRPLUS
|
|
|
+ | NFS_CAP_ATOMIC_OPEN
|
|
|
+ | NFS_CAP_CHANGE_ATTR
|
|
|
+ | NFS_CAP_POSIX_LOCK
|
|
|
+ | NFS_CAP_STATEID_NFSV41
|
|
|
+ | NFS_CAP_ATOMIC_OPEN_V1,
|
|
|
+ .call_sync = nfs4_call_sync_sequence,
|
|
|
+ .match_stateid = nfs41_match_stateid,
|
|
|
+ .find_root_sec = nfs41_find_root_sec,
|
|
|
+ .free_lock_state = nfs41_free_lock_state,
|
|
|
+ .reboot_recovery_ops = &nfs41_reboot_recovery_ops,
|
|
|
+ .nograce_recovery_ops = &nfs41_nograce_recovery_ops,
|
|
|
+ .state_renewal_ops = &nfs41_state_renewal_ops,
|
|
|
+};
|
|
|
+#endif
|
|
|
+
|
|
|
const struct nfs4_minor_version_ops *nfs_v4_minor_ops[] = {
|
|
|
[0] = &nfs_v4_0_minor_ops,
|
|
|
#if defined(CONFIG_NFS_V4_1)
|
|
|
[1] = &nfs_v4_1_minor_ops,
|
|
|
#endif
|
|
|
+#if defined(CONFIG_NFS_V4_2)
|
|
|
+ [2] = &nfs_v4_2_minor_ops,
|
|
|
+#endif
|
|
|
};
|
|
|
|
|
|
const struct inode_operations nfs4_dir_inode_operations = {
|
|
@@ -7108,6 +7570,9 @@ static const struct xattr_handler nfs4_xattr_nfs4_acl_handler = {
|
|
|
|
|
|
const struct xattr_handler *nfs4_xattr_handlers[] = {
|
|
|
&nfs4_xattr_nfs4_acl_handler,
|
|
|
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
|
|
|
+ &nfs4_xattr_nfs4_label_handler,
|
|
|
+#endif
|
|
|
NULL
|
|
|
};
|
|
|
|