mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
Merge tag 'nfsd-7.0' of git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux
Pull nfsd updates from Chuck Lever: "Neil Brown and Jeff Layton contributed a dynamic thread pool sizing mechanism for NFSD. The sunrpc layer now tracks minimum and maximum thread counts per pool, and NFSD adjusts running thread counts based on workload: idle threads exit after a timeout when the pool exceeds its minimum, and new threads spawn automatically when all threads are busy. Administrators control this behavior via the nfsdctl netlink interface. Rick Macklem, FreeBSD NFS maintainer, generously contributed server- side support for the POSIX ACL extension to NFSv4, as specified in draft-ietf-nfsv4-posix-acls. This extension allows NFSv4 clients to get and set POSIX access and default ACLs using native NFSv4 operations, eliminating the need for sideband protocols. The feature is gated by a Kconfig option since the IETF draft has not yet been ratified. Chuck Lever delivered numerous improvements to the xdrgen tool. Error reporting now covers parsing, AST transformation, and invalid declarations. Generated enum decoders validate incoming values against valid enumerator lists. New features include pass-through line support for embedding C directives in XDR specifications, 16-bit integer types, and program number definitions. Several code generation issues were also addressed. When an administrator revokes NFSv4 state for a filesystem via the unlock_fs interface, ongoing async COPY operations referencing that filesystem are now cancelled, with CB_OFFLOAD callbacks notifying affected clients. The remaining patches in this pull request are clean-ups and minor optimizations. Sincere thanks to all contributors, reviewers, testers, and bug reporters who participated in the v7.0 NFSD development cycle" * tag 'nfsd-7.0' of git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux: (45 commits) NFSD: Add POSIX ACL file attributes to SUPPATTR bitmasks NFSD: Add POSIX draft ACL support to the NFSv4 SETATTR operation NFSD: Add support for POSIX draft ACLs for file creation NFSD: Add support for XDR decoding POSIX draft ACLs NFSD: Refactor nfsd_setattr()'s ACL error reporting NFSD: Do not allow NFSv4 (N)VERIFY to check POSIX ACL attributes NFSD: Add nfsd4_encode_fattr4_posix_access_acl NFSD: Add nfsd4_encode_fattr4_posix_default_acl NFSD: Add nfsd4_encode_fattr4_acl_trueform_scope NFSD: Add nfsd4_encode_fattr4_acl_trueform Add RPC language definition of NFSv4 POSIX ACL extension NFSD: Add a Kconfig setting to enable support for NFSv4 POSIX ACLs xdrgen: Implement pass-through lines in specifications nfsd: cancel async COPY operations when admin revokes filesystem state nfsd: add controls to set the minimum number of threads per pool nfsd: adjust number of running nfsd threads based on activity sunrpc: allow svc_recv() to return -ETIMEDOUT and -EBUSY sunrpc: split new thread creation into a separate function sunrpc: introduce the concept of a minimum number of threads per pool sunrpc: track the max number of requested threads in a pool ...
This commit is contained in:
@@ -78,6 +78,9 @@ attribute-sets:
|
||||
-
|
||||
name: scope
|
||||
type: string
|
||||
-
|
||||
name: min-threads
|
||||
type: u32
|
||||
-
|
||||
name: version
|
||||
attributes:
|
||||
@@ -159,6 +162,7 @@ operations:
|
||||
- gracetime
|
||||
- leasetime
|
||||
- scope
|
||||
- min-threads
|
||||
-
|
||||
name: threads-get
|
||||
doc: get the number of running threads
|
||||
@@ -170,6 +174,7 @@ operations:
|
||||
- gracetime
|
||||
- leasetime
|
||||
- scope
|
||||
- min-threads
|
||||
-
|
||||
name: version-set
|
||||
doc: set nfs enabled versions
|
||||
|
||||
@@ -53,6 +53,11 @@ typedef unsigned int uint32_t;
|
||||
*/
|
||||
typedef uint32_t bitmap4<>;
|
||||
|
||||
typedef opaque utf8string<>;
|
||||
typedef utf8string utf8str_cis;
|
||||
typedef utf8string utf8str_cs;
|
||||
typedef utf8string utf8str_mixed;
|
||||
|
||||
/*
|
||||
* Timeval
|
||||
*/
|
||||
@@ -184,3 +189,59 @@ enum open_delegation_type4 {
|
||||
OPEN_DELEGATE_READ_ATTRS_DELEG = 4,
|
||||
OPEN_DELEGATE_WRITE_ATTRS_DELEG = 5
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* The following content was extracted from draft-ietf-nfsv4-posix-acls
|
||||
*/
|
||||
|
||||
enum aclmodel4 {
|
||||
ACL_MODEL_NFS4 = 1,
|
||||
ACL_MODEL_POSIX_DRAFT = 2,
|
||||
ACL_MODEL_NONE = 3
|
||||
};
|
||||
pragma public aclmodel4;
|
||||
|
||||
enum aclscope4 {
|
||||
ACL_SCOPE_FILE_OBJECT = 1,
|
||||
ACL_SCOPE_FILE_SYSTEM = 2,
|
||||
ACL_SCOPE_SERVER = 3
|
||||
};
|
||||
pragma public aclscope4;
|
||||
|
||||
enum posixacetag4 {
|
||||
POSIXACE4_TAG_USER_OBJ = 1,
|
||||
POSIXACE4_TAG_USER = 2,
|
||||
POSIXACE4_TAG_GROUP_OBJ = 3,
|
||||
POSIXACE4_TAG_GROUP = 4,
|
||||
POSIXACE4_TAG_MASK = 5,
|
||||
POSIXACE4_TAG_OTHER = 6
|
||||
};
|
||||
pragma public posixacetag4;
|
||||
|
||||
typedef uint32_t posixaceperm4;
|
||||
pragma public posixaceperm4;
|
||||
|
||||
/* Bit definitions for posixaceperm4. */
|
||||
const POSIXACE4_PERM_EXECUTE = 0x00000001;
|
||||
const POSIXACE4_PERM_WRITE = 0x00000002;
|
||||
const POSIXACE4_PERM_READ = 0x00000004;
|
||||
|
||||
struct posixace4 {
|
||||
posixacetag4 tag;
|
||||
posixaceperm4 perm;
|
||||
utf8str_mixed who;
|
||||
};
|
||||
|
||||
typedef aclmodel4 fattr4_acl_trueform;
|
||||
typedef aclscope4 fattr4_acl_trueform_scope;
|
||||
typedef posixace4 fattr4_posix_default_acl<>;
|
||||
typedef posixace4 fattr4_posix_access_acl<>;
|
||||
|
||||
%/*
|
||||
% * New for POSIX ACL extension
|
||||
% */
|
||||
const FATTR4_ACL_TRUEFORM = 89;
|
||||
const FATTR4_ACL_TRUEFORM_SCOPE = 90;
|
||||
const FATTR4_POSIX_DEFAULT_ACL = 91;
|
||||
const FATTR4_POSIX_ACCESS_ACL = 92;
|
||||
|
||||
+3
-3
@@ -141,7 +141,7 @@ lockd(void *vrqstp)
|
||||
*/
|
||||
while (!svc_thread_should_stop(rqstp)) {
|
||||
nlmsvc_retry_blocked(rqstp);
|
||||
svc_recv(rqstp);
|
||||
svc_recv(rqstp, 0);
|
||||
}
|
||||
if (nlmsvc_ops)
|
||||
nlmsvc_invalidate_all();
|
||||
@@ -340,7 +340,7 @@ static int lockd_get(void)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
error = svc_set_num_threads(serv, NULL, 1);
|
||||
error = svc_set_num_threads(serv, 0, 1);
|
||||
if (error < 0) {
|
||||
svc_destroy(&serv);
|
||||
return error;
|
||||
@@ -368,7 +368,7 @@ static void lockd_put(void)
|
||||
unregister_inet6addr_notifier(&lockd_inet6addr_notifier);
|
||||
#endif
|
||||
|
||||
svc_set_num_threads(nlmsvc_serv, NULL, 0);
|
||||
svc_set_num_threads(nlmsvc_serv, 0, 0);
|
||||
timer_delete_sync(&nlmsvc_retry);
|
||||
svc_destroy(&nlmsvc_serv);
|
||||
dprintk("lockd_down: service destroyed\n");
|
||||
|
||||
@@ -641,10 +641,6 @@ nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file,
|
||||
conflock->fl.c.flc_owner = lock->fl.c.flc_owner;
|
||||
error = vfs_test_lock(file->f_file[mode], &conflock->fl);
|
||||
if (error) {
|
||||
/* We can't currently deal with deferred test requests */
|
||||
if (error == FILE_LOCK_DEFERRED)
|
||||
WARN_ON_ONCE(1);
|
||||
|
||||
ret = nlm_lck_denied_nolocks;
|
||||
goto out;
|
||||
}
|
||||
|
||||
+14
-3
@@ -2262,12 +2262,23 @@ SYSCALL_DEFINE2(flock, unsigned int, fd, unsigned int, cmd)
|
||||
*/
|
||||
int vfs_test_lock(struct file *filp, struct file_lock *fl)
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
WARN_ON_ONCE(fl->fl_ops || fl->fl_lmops);
|
||||
WARN_ON_ONCE(filp != fl->c.flc_file);
|
||||
if (filp->f_op->lock)
|
||||
return filp->f_op->lock(filp, F_GETLK, fl);
|
||||
posix_test_lock(filp, fl);
|
||||
return 0;
|
||||
error = filp->f_op->lock(filp, F_GETLK, fl);
|
||||
else
|
||||
posix_test_lock(filp, fl);
|
||||
|
||||
/*
|
||||
* We don't expect FILE_LOCK_DEFERRED and callers cannot
|
||||
* handle it.
|
||||
*/
|
||||
if (WARN_ON_ONCE(error == FILE_LOCK_DEFERRED))
|
||||
error = -EIO;
|
||||
|
||||
return error;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(vfs_test_lock);
|
||||
|
||||
|
||||
+5
-5
@@ -81,7 +81,7 @@ nfs4_callback_svc(void *vrqstp)
|
||||
set_freezable();
|
||||
|
||||
while (!svc_thread_should_stop(rqstp))
|
||||
svc_recv(rqstp);
|
||||
svc_recv(rqstp, 0);
|
||||
|
||||
svc_exit_thread(rqstp);
|
||||
return 0;
|
||||
@@ -119,9 +119,9 @@ static int nfs_callback_start_svc(int minorversion, struct rpc_xprt *xprt,
|
||||
if (serv->sv_nrthreads == nrservs)
|
||||
return 0;
|
||||
|
||||
ret = svc_set_num_threads(serv, NULL, nrservs);
|
||||
ret = svc_set_num_threads(serv, 0, nrservs);
|
||||
if (ret) {
|
||||
svc_set_num_threads(serv, NULL, 0);
|
||||
svc_set_num_threads(serv, 0, 0);
|
||||
return ret;
|
||||
}
|
||||
dprintk("nfs_callback_up: service started\n");
|
||||
@@ -242,7 +242,7 @@ int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt)
|
||||
cb_info->users++;
|
||||
err_net:
|
||||
if (!cb_info->users) {
|
||||
svc_set_num_threads(cb_info->serv, NULL, 0);
|
||||
svc_set_num_threads(cb_info->serv, 0, 0);
|
||||
svc_destroy(&cb_info->serv);
|
||||
}
|
||||
err_create:
|
||||
@@ -268,7 +268,7 @@ void nfs_callback_down(int minorversion, struct net *net, struct rpc_xprt *xprt)
|
||||
nfs_callback_down_net(minorversion, serv, net);
|
||||
cb_info->users--;
|
||||
if (cb_info->users == 0) {
|
||||
svc_set_num_threads(serv, NULL, 0);
|
||||
svc_set_num_threads(serv, 0, 0);
|
||||
dprintk("nfs_callback_down: service destroyed\n");
|
||||
xprt_svc_destroy_nullify_bc(xprt, &cb_info->serv);
|
||||
}
|
||||
|
||||
@@ -186,3 +186,22 @@ config NFSD_V4_DELEG_TIMESTAMPS
|
||||
draft-ietf-nfsv4-delstid-08 "Extending the Opening of Files". This
|
||||
is currently an experimental feature and is therefore left disabled
|
||||
by default.
|
||||
|
||||
config NFSD_V4_POSIX_ACLS
|
||||
bool "Support NFSv4 POSIX draft ACLs"
|
||||
depends on NFSD_V4
|
||||
default n
|
||||
help
|
||||
Include experimental support for POSIX Access Control Lists
|
||||
(ACLs) in NFSv4 as specified in the IETF draft
|
||||
draft-ietf-nfsv4-posix-acls. This protocol extension enables
|
||||
NFSv4 clients to retrieve and modify POSIX ACLs on exported
|
||||
filesystems that support them.
|
||||
|
||||
This feature is based on an unratified IETF draft
|
||||
specification that may change in ways that impact
|
||||
interoperability with existing clients. Enable only for
|
||||
testing environments or when interoperability with specific
|
||||
clients that implement this draft is required.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
+9
-1
@@ -26,7 +26,15 @@ nfsd-$(CONFIG_NFSD_FLEXFILELAYOUT) += flexfilelayout.o flexfilelayoutxdr.o
|
||||
nfsd-$(CONFIG_NFS_LOCALIO) += localio.o
|
||||
nfsd-$(CONFIG_DEBUG_FS) += debugfs.o
|
||||
|
||||
|
||||
#
|
||||
# XDR code generation (requires Python and additional packages)
|
||||
#
|
||||
# The generated *xdr_gen.{h,c} files are checked into git. Normal kernel
|
||||
# builds do not require the xdrgen tool or its Python dependencies.
|
||||
#
|
||||
# Developers modifying .x files in Documentation/sunrpc/xdr/ should run
|
||||
# "make xdrgen" to regenerate the affected files.
|
||||
#
|
||||
.PHONY: xdrgen
|
||||
|
||||
xdrgen: ../../include/linux/sunrpc/xdrgen/nfs4_1.h nfs4xdr_gen.h nfs4xdr_gen.c
|
||||
|
||||
@@ -49,5 +49,6 @@ int nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry,
|
||||
struct nfs4_acl **acl);
|
||||
__be32 nfsd4_acl_to_attr(enum nfs_ftype4 type, struct nfs4_acl *acl,
|
||||
struct nfsd_attrs *attr);
|
||||
void sort_pacl_range(struct posix_acl *pacl, int start, int end);
|
||||
|
||||
#endif /* LINUX_NFS4_ACL_H */
|
||||
|
||||
+3
-2
@@ -24,11 +24,12 @@ const struct nla_policy nfsd_version_nl_policy[NFSD_A_VERSION_ENABLED + 1] = {
|
||||
};
|
||||
|
||||
/* NFSD_CMD_THREADS_SET - do */
|
||||
static const struct nla_policy nfsd_threads_set_nl_policy[NFSD_A_SERVER_SCOPE + 1] = {
|
||||
static const struct nla_policy nfsd_threads_set_nl_policy[NFSD_A_SERVER_MIN_THREADS + 1] = {
|
||||
[NFSD_A_SERVER_THREADS] = { .type = NLA_U32, },
|
||||
[NFSD_A_SERVER_GRACETIME] = { .type = NLA_U32, },
|
||||
[NFSD_A_SERVER_LEASETIME] = { .type = NLA_U32, },
|
||||
[NFSD_A_SERVER_SCOPE] = { .type = NLA_NUL_STRING, },
|
||||
[NFSD_A_SERVER_MIN_THREADS] = { .type = NLA_U32, },
|
||||
};
|
||||
|
||||
/* NFSD_CMD_VERSION_SET - do */
|
||||
@@ -57,7 +58,7 @@ static const struct genl_split_ops nfsd_nl_ops[] = {
|
||||
.cmd = NFSD_CMD_THREADS_SET,
|
||||
.doit = nfsd_nl_threads_set_doit,
|
||||
.policy = nfsd_threads_set_nl_policy,
|
||||
.maxattr = NFSD_A_SERVER_SCOPE,
|
||||
.maxattr = NFSD_A_SERVER_MIN_THREADS,
|
||||
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
|
||||
},
|
||||
{
|
||||
|
||||
+6
-1
@@ -67,7 +67,6 @@ struct nfsd_net {
|
||||
struct lock_manager nfsd4_manager;
|
||||
bool grace_ended;
|
||||
bool grace_end_forced;
|
||||
bool client_tracking_active;
|
||||
time64_t boot_time;
|
||||
|
||||
struct dentry *nfsd_client_dir;
|
||||
@@ -130,6 +129,12 @@ struct nfsd_net {
|
||||
seqlock_t writeverf_lock;
|
||||
unsigned char writeverf[8];
|
||||
|
||||
/*
|
||||
* Minimum number of threads to run per pool. If 0 then the
|
||||
* min == max requested number of threads.
|
||||
*/
|
||||
unsigned int min_threads;
|
||||
|
||||
u32 clientid_base;
|
||||
u32 clientid_counter;
|
||||
u32 clverifier_counter;
|
||||
|
||||
+1
-1
@@ -45,7 +45,7 @@ static __be32 nfsacld_proc_getacl(struct svc_rqst *rqstp)
|
||||
inode = d_inode(fh->fh_dentry);
|
||||
|
||||
if (argp->mask & ~NFS_ACL_MASK) {
|
||||
resp->status = nfserr_inval;
|
||||
resp->status = nfserr_io;
|
||||
goto out;
|
||||
}
|
||||
resp->mask = argp->mask;
|
||||
|
||||
+13
-4
@@ -369,12 +369,21 @@ pace_gt(struct posix_acl_entry *pace1, struct posix_acl_entry *pace2)
|
||||
return false;
|
||||
}
|
||||
|
||||
static void
|
||||
sort_pacl_range(struct posix_acl *pacl, int start, int end) {
|
||||
/**
|
||||
* sort_pacl_range - sort a range of POSIX ACL entries by tag and id
|
||||
* @pacl: POSIX ACL containing entries to sort
|
||||
* @start: starting index of range to sort
|
||||
* @end: ending index of range to sort (inclusive)
|
||||
*
|
||||
* Sorts ACL entries in place so that USER entries are ordered by UID
|
||||
* and GROUP entries are ordered by GID. Required before calling
|
||||
* posix_acl_valid().
|
||||
*/
|
||||
void sort_pacl_range(struct posix_acl *pacl, int start, int end)
|
||||
{
|
||||
int sorted = 0, i;
|
||||
|
||||
/* We just do a bubble sort; easy to do in place, and we're not
|
||||
* expecting acl's to be long enough to justify anything more. */
|
||||
/* Bubble sort: acceptable here because ACLs are typically short. */
|
||||
while (!sorted) {
|
||||
sorted = 1;
|
||||
for (i = start; i < end; i++) {
|
||||
|
||||
+46
-6
@@ -643,34 +643,74 @@ static __be32 encode_name_from_id(struct xdr_stream *xdr,
|
||||
return idmap_id_to_name(xdr, rqstp, type, id);
|
||||
}
|
||||
|
||||
__be32
|
||||
nfsd_map_name_to_uid(struct svc_rqst *rqstp, const char *name, size_t namelen,
|
||||
kuid_t *uid)
|
||||
/**
|
||||
* nfsd_map_name_to_uid - Map user@domain to local UID
|
||||
* @rqstp: RPC execution context
|
||||
* @name: user@domain name to be mapped
|
||||
* @namelen: length of name, in bytes
|
||||
* @uid: OUT: mapped local UID value
|
||||
*
|
||||
* Returns nfs_ok on success or an NFSv4 status code on failure.
|
||||
*/
|
||||
__be32 nfsd_map_name_to_uid(struct svc_rqst *rqstp, const char *name,
|
||||
size_t namelen, kuid_t *uid)
|
||||
{
|
||||
__be32 status;
|
||||
u32 id = -1;
|
||||
|
||||
/*
|
||||
* The idmap lookup below triggers an upcall that invokes
|
||||
* cache_check(). RQ_USEDEFERRAL must be clear to prevent
|
||||
* cache_check() from setting RQ_DROPME via svc_defer().
|
||||
* NFSv4 servers are not permitted to drop requests. Also
|
||||
* RQ_DROPME will force NFSv4.1 session slot processing to
|
||||
* be skipped.
|
||||
*/
|
||||
WARN_ON_ONCE(test_bit(RQ_USEDEFERRAL, &rqstp->rq_flags));
|
||||
|
||||
if (name == NULL || namelen == 0)
|
||||
return nfserr_inval;
|
||||
|
||||
status = do_name_to_id(rqstp, IDMAP_TYPE_USER, name, namelen, &id);
|
||||
if (status)
|
||||
return status;
|
||||
*uid = make_kuid(nfsd_user_namespace(rqstp), id);
|
||||
if (!uid_valid(*uid))
|
||||
status = nfserr_badowner;
|
||||
return status;
|
||||
}
|
||||
|
||||
__be32
|
||||
nfsd_map_name_to_gid(struct svc_rqst *rqstp, const char *name, size_t namelen,
|
||||
kgid_t *gid)
|
||||
/**
|
||||
* nfsd_map_name_to_gid - Map user@domain to local GID
|
||||
* @rqstp: RPC execution context
|
||||
* @name: user@domain name to be mapped
|
||||
* @namelen: length of name, in bytes
|
||||
* @gid: OUT: mapped local GID value
|
||||
*
|
||||
* Returns nfs_ok on success or an NFSv4 status code on failure.
|
||||
*/
|
||||
__be32 nfsd_map_name_to_gid(struct svc_rqst *rqstp, const char *name,
|
||||
size_t namelen, kgid_t *gid)
|
||||
{
|
||||
__be32 status;
|
||||
u32 id = -1;
|
||||
|
||||
/*
|
||||
* The idmap lookup below triggers an upcall that invokes
|
||||
* cache_check(). RQ_USEDEFERRAL must be clear to prevent
|
||||
* cache_check() from setting RQ_DROPME via svc_defer().
|
||||
* NFSv4 servers are not permitted to drop requests. Also
|
||||
* RQ_DROPME will force NFSv4.1 session slot processing to
|
||||
* be skipped.
|
||||
*/
|
||||
WARN_ON_ONCE(test_bit(RQ_USEDEFERRAL, &rqstp->rq_flags));
|
||||
|
||||
if (name == NULL || namelen == 0)
|
||||
return nfserr_inval;
|
||||
|
||||
status = do_name_to_id(rqstp, IDMAP_TYPE_GROUP, name, namelen, &id);
|
||||
if (status)
|
||||
return status;
|
||||
*gid = make_kgid(nfsd_user_namespace(rqstp), id);
|
||||
if (!gid_valid(*gid))
|
||||
status = nfserr_badowner;
|
||||
|
||||
+216
-49
@@ -81,8 +81,8 @@ static u32 nfsd41_ex_attrmask[] = {
|
||||
};
|
||||
|
||||
static __be32
|
||||
check_attr_support(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
u32 *bmval, u32 *writable)
|
||||
check_attr_support(struct nfsd4_compound_state *cstate, u32 *bmval,
|
||||
u32 *writable)
|
||||
{
|
||||
struct dentry *dentry = cstate->current_fh.fh_dentry;
|
||||
struct svc_export *exp = cstate->current_fh.fh_export;
|
||||
@@ -91,6 +91,10 @@ check_attr_support(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
return nfserr_attrnotsupp;
|
||||
if ((bmval[0] & FATTR4_WORD0_ACL) && !IS_POSIXACL(d_inode(dentry)))
|
||||
return nfserr_attrnotsupp;
|
||||
if ((bmval[2] & (FATTR4_WORD2_POSIX_DEFAULT_ACL |
|
||||
FATTR4_WORD2_POSIX_ACCESS_ACL)) &&
|
||||
!IS_POSIXACL(d_inode(dentry)))
|
||||
return nfserr_attrnotsupp;
|
||||
if ((bmval[2] & FATTR4_WORD2_SECURITY_LABEL) &&
|
||||
!(exp->ex_flags & NFSEXP_SECURITY_LABEL))
|
||||
return nfserr_attrnotsupp;
|
||||
@@ -103,21 +107,25 @@ check_attr_support(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
}
|
||||
|
||||
static __be32
|
||||
nfsd4_check_open_attributes(struct svc_rqst *rqstp,
|
||||
struct nfsd4_compound_state *cstate, struct nfsd4_open *open)
|
||||
nfsd4_check_open_attributes(struct nfsd4_compound_state *cstate,
|
||||
struct nfsd4_open *open)
|
||||
{
|
||||
__be32 status = nfs_ok;
|
||||
|
||||
if (open->op_create == NFS4_OPEN_CREATE) {
|
||||
if (open->op_createmode == NFS4_CREATE_UNCHECKED
|
||||
|| open->op_createmode == NFS4_CREATE_GUARDED)
|
||||
status = check_attr_support(rqstp, cstate,
|
||||
open->op_bmval, nfsd_attrmask);
|
||||
else if (open->op_createmode == NFS4_CREATE_EXCLUSIVE4_1)
|
||||
status = check_attr_support(rqstp, cstate,
|
||||
open->op_bmval, nfsd41_ex_attrmask);
|
||||
}
|
||||
if (open->op_create != NFS4_OPEN_CREATE)
|
||||
return status;
|
||||
|
||||
switch (open->op_createmode) {
|
||||
case NFS4_CREATE_UNCHECKED:
|
||||
case NFS4_CREATE_GUARDED:
|
||||
status = check_attr_support(cstate, open->op_bmval,
|
||||
nfsd_attrmask);
|
||||
break;
|
||||
case NFS4_CREATE_EXCLUSIVE4_1:
|
||||
status = check_attr_support(cstate, open->op_bmval,
|
||||
nfsd41_ex_attrmask);
|
||||
break;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -266,8 +274,20 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
||||
if (host_err)
|
||||
return nfserrno(host_err);
|
||||
|
||||
if (is_create_with_attrs(open))
|
||||
nfsd4_acl_to_attr(NF4REG, open->op_acl, &attrs);
|
||||
if (open->op_acl) {
|
||||
if (open->op_dpacl || open->op_pacl) {
|
||||
status = nfserr_inval;
|
||||
goto out_write;
|
||||
}
|
||||
if (is_create_with_attrs(open))
|
||||
nfsd4_acl_to_attr(NF4REG, open->op_acl, &attrs);
|
||||
} else if (is_create_with_attrs(open)) {
|
||||
/* The dpacl and pacl will get released by nfsd_attrs_free(). */
|
||||
attrs.na_dpacl = open->op_dpacl;
|
||||
attrs.na_pacl = open->op_pacl;
|
||||
open->op_dpacl = NULL;
|
||||
open->op_pacl = NULL;
|
||||
}
|
||||
|
||||
child = start_creating(&nop_mnt_idmap, parent,
|
||||
&QSTR_LEN(open->op_fname, open->op_fnamelen));
|
||||
@@ -378,8 +398,12 @@ set_attr:
|
||||
|
||||
if (attrs.na_labelerr)
|
||||
open->op_bmval[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
|
||||
if (attrs.na_aclerr)
|
||||
if (attrs.na_paclerr || attrs.na_dpaclerr)
|
||||
open->op_bmval[0] &= ~FATTR4_WORD0_ACL;
|
||||
if (attrs.na_dpaclerr)
|
||||
open->op_bmval[2] &= ~FATTR4_WORD2_POSIX_DEFAULT_ACL;
|
||||
if (attrs.na_paclerr)
|
||||
open->op_bmval[2] &= ~FATTR4_WORD2_POSIX_ACCESS_ACL;
|
||||
out:
|
||||
end_creating(child);
|
||||
nfsd_attrs_free(&attrs);
|
||||
@@ -547,8 +571,10 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
open->op_rqstp = rqstp;
|
||||
|
||||
/* This check required by spec. */
|
||||
if (open->op_create && open->op_claim_type != NFS4_OPEN_CLAIM_NULL)
|
||||
return nfserr_inval;
|
||||
if (open->op_create && open->op_claim_type != NFS4_OPEN_CLAIM_NULL) {
|
||||
status = nfserr_inval;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
open->op_created = false;
|
||||
/*
|
||||
@@ -557,8 +583,10 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
*/
|
||||
if (nfsd4_has_session(cstate) &&
|
||||
!test_bit(NFSD4_CLIENT_RECLAIM_COMPLETE, &cstate->clp->cl_flags) &&
|
||||
open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS)
|
||||
return nfserr_grace;
|
||||
open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS) {
|
||||
status = nfserr_grace;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
if (nfsd4_has_session(cstate))
|
||||
copy_clientid(&open->op_clientid, cstate->session);
|
||||
@@ -584,7 +612,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
goto out;
|
||||
}
|
||||
|
||||
status = nfsd4_check_open_attributes(rqstp, cstate, open);
|
||||
status = nfsd4_check_open_attributes(cstate, open);
|
||||
if (status)
|
||||
goto out;
|
||||
|
||||
@@ -645,6 +673,9 @@ out:
|
||||
}
|
||||
nfsd4_cleanup_open_state(cstate, open);
|
||||
nfsd4_bump_seqid(cstate, status);
|
||||
out_err:
|
||||
posix_acl_release(open->op_dpacl);
|
||||
posix_acl_release(open->op_pacl);
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -785,23 +816,34 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
struct nfsd_attrs attrs = {
|
||||
.na_iattr = &create->cr_iattr,
|
||||
.na_seclabel = &create->cr_label,
|
||||
.na_dpacl = create->cr_dpacl,
|
||||
.na_pacl = create->cr_pacl,
|
||||
};
|
||||
struct svc_fh resfh;
|
||||
__be32 status;
|
||||
dev_t rdev;
|
||||
|
||||
create->cr_dpacl = NULL;
|
||||
create->cr_pacl = NULL;
|
||||
|
||||
fh_init(&resfh, NFS4_FHSIZE);
|
||||
|
||||
status = fh_verify(rqstp, &cstate->current_fh, S_IFDIR, NFSD_MAY_NOP);
|
||||
if (status)
|
||||
return status;
|
||||
goto out_aftermask;
|
||||
|
||||
status = check_attr_support(rqstp, cstate, create->cr_bmval,
|
||||
nfsd_attrmask);
|
||||
status = check_attr_support(cstate, create->cr_bmval, nfsd_attrmask);
|
||||
if (status)
|
||||
return status;
|
||||
goto out_aftermask;
|
||||
|
||||
status = nfsd4_acl_to_attr(create->cr_type, create->cr_acl, &attrs);
|
||||
if (create->cr_acl) {
|
||||
if (create->cr_dpacl || create->cr_pacl) {
|
||||
status = nfserr_inval;
|
||||
goto out_aftermask;
|
||||
}
|
||||
status = nfsd4_acl_to_attr(create->cr_type, create->cr_acl,
|
||||
&attrs);
|
||||
}
|
||||
current->fs->umask = create->cr_umask;
|
||||
switch (create->cr_type) {
|
||||
case NF4LNK:
|
||||
@@ -860,14 +902,19 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
|
||||
if (attrs.na_labelerr)
|
||||
create->cr_bmval[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
|
||||
if (attrs.na_aclerr)
|
||||
if (attrs.na_paclerr || attrs.na_dpaclerr)
|
||||
create->cr_bmval[0] &= ~FATTR4_WORD0_ACL;
|
||||
if (attrs.na_dpaclerr)
|
||||
create->cr_bmval[2] &= ~FATTR4_WORD2_POSIX_DEFAULT_ACL;
|
||||
if (attrs.na_paclerr)
|
||||
create->cr_bmval[2] &= ~FATTR4_WORD2_POSIX_ACCESS_ACL;
|
||||
set_change_info(&create->cr_cinfo, &cstate->current_fh);
|
||||
fh_dup2(&cstate->current_fh, &resfh);
|
||||
out:
|
||||
fh_put(&resfh);
|
||||
out_umask:
|
||||
current->fs->umask = 0;
|
||||
out_aftermask:
|
||||
nfsd_attrs_free(&attrs);
|
||||
return status;
|
||||
}
|
||||
@@ -1172,6 +1219,8 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
struct nfsd_attrs attrs = {
|
||||
.na_iattr = &setattr->sa_iattr,
|
||||
.na_seclabel = &setattr->sa_label,
|
||||
.na_pacl = setattr->sa_pacl,
|
||||
.na_dpacl = setattr->sa_dpacl,
|
||||
};
|
||||
bool save_no_wcc, deleg_attrs;
|
||||
struct nfs4_stid *st = NULL;
|
||||
@@ -1179,6 +1228,10 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
__be32 status = nfs_ok;
|
||||
int err;
|
||||
|
||||
/* Transfer ownership to attrs for cleanup via nfsd_attrs_free() */
|
||||
setattr->sa_pacl = NULL;
|
||||
setattr->sa_dpacl = NULL;
|
||||
|
||||
deleg_attrs = setattr->sa_bmval[2] & (FATTR4_WORD2_TIME_DELEG_ACCESS |
|
||||
FATTR4_WORD2_TIME_DELEG_MODIFY);
|
||||
|
||||
@@ -1192,7 +1245,7 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
&cstate->current_fh, &setattr->sa_stateid,
|
||||
flags, NULL, &st);
|
||||
if (status)
|
||||
return status;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
if (deleg_attrs) {
|
||||
@@ -1210,18 +1263,24 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
if (st)
|
||||
nfs4_put_stid(st);
|
||||
if (status)
|
||||
return status;
|
||||
goto out_err;
|
||||
|
||||
err = fh_want_write(&cstate->current_fh);
|
||||
if (err)
|
||||
return nfserrno(err);
|
||||
if (err) {
|
||||
status = nfserrno(err);
|
||||
goto out_err;
|
||||
}
|
||||
status = nfs_ok;
|
||||
|
||||
status = check_attr_support(rqstp, cstate, setattr->sa_bmval,
|
||||
nfsd_attrmask);
|
||||
status = check_attr_support(cstate, setattr->sa_bmval, nfsd_attrmask);
|
||||
if (status)
|
||||
goto out;
|
||||
|
||||
if (setattr->sa_acl && (attrs.na_dpacl || attrs.na_pacl)) {
|
||||
status = nfserr_inval;
|
||||
goto out;
|
||||
}
|
||||
|
||||
inode = cstate->current_fh.fh_dentry->d_inode;
|
||||
status = nfsd4_acl_to_attr(S_ISDIR(inode->i_mode) ? NF4DIR : NF4REG,
|
||||
setattr->sa_acl, &attrs);
|
||||
@@ -1235,10 +1294,13 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
if (!status)
|
||||
status = nfserrno(attrs.na_labelerr);
|
||||
if (!status)
|
||||
status = nfserrno(attrs.na_aclerr);
|
||||
status = nfserrno(attrs.na_dpaclerr);
|
||||
if (!status)
|
||||
status = nfserrno(attrs.na_paclerr);
|
||||
out:
|
||||
nfsd_attrs_free(&attrs);
|
||||
fh_drop_write(&cstate->current_fh);
|
||||
out_err:
|
||||
nfsd_attrs_free(&attrs);
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -1430,14 +1492,26 @@ static void nfs4_put_copy(struct nfsd4_copy *copy)
|
||||
kfree(copy);
|
||||
}
|
||||
|
||||
static void release_copy_files(struct nfsd4_copy *copy);
|
||||
|
||||
static void nfsd4_stop_copy(struct nfsd4_copy *copy)
|
||||
{
|
||||
trace_nfsd_copy_async_cancel(copy);
|
||||
if (!test_and_set_bit(NFSD4_COPY_F_STOPPED, ©->cp_flags)) {
|
||||
kthread_stop(copy->copy_task);
|
||||
copy->nfserr = nfs_ok;
|
||||
if (!test_bit(NFSD4_COPY_F_CB_ERROR, ©->cp_flags))
|
||||
copy->nfserr = nfs_ok;
|
||||
set_bit(NFSD4_COPY_F_COMPLETED, ©->cp_flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* The copy was removed from async_copies before this function
|
||||
* was called, so the reaper cannot clean it up. Release files
|
||||
* here regardless of who won the STOPPED race. If the thread
|
||||
* set STOPPED, it has finished using the files. If STOPPED
|
||||
* was set here, kthread_stop() waited for the thread to exit.
|
||||
*/
|
||||
release_copy_files(copy);
|
||||
nfs4_put_copy(copy);
|
||||
}
|
||||
|
||||
@@ -1465,6 +1539,72 @@ void nfsd4_shutdown_copy(struct nfs4_client *clp)
|
||||
while ((copy = nfsd4_unhash_copy(clp)) != NULL)
|
||||
nfsd4_stop_copy(copy);
|
||||
}
|
||||
|
||||
static bool nfsd4_copy_on_sb(const struct nfsd4_copy *copy,
|
||||
const struct super_block *sb)
|
||||
{
|
||||
if (copy->nf_src &&
|
||||
file_inode(copy->nf_src->nf_file)->i_sb == sb)
|
||||
return true;
|
||||
if (copy->nf_dst &&
|
||||
file_inode(copy->nf_dst->nf_file)->i_sb == sb)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* nfsd4_cancel_copy_by_sb - cancel async copy operations on @sb
|
||||
* @net: net namespace containing the copy operations
|
||||
* @sb: targeted superblock
|
||||
*/
|
||||
void nfsd4_cancel_copy_by_sb(struct net *net, struct super_block *sb)
|
||||
{
|
||||
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
|
||||
struct nfsd4_copy *copy, *tmp;
|
||||
struct nfs4_client *clp;
|
||||
unsigned int idhashval;
|
||||
LIST_HEAD(to_cancel);
|
||||
|
||||
spin_lock(&nn->client_lock);
|
||||
for (idhashval = 0; idhashval < CLIENT_HASH_SIZE; idhashval++) {
|
||||
struct list_head *head = &nn->conf_id_hashtbl[idhashval];
|
||||
|
||||
list_for_each_entry(clp, head, cl_idhash) {
|
||||
spin_lock(&clp->async_lock);
|
||||
list_for_each_entry_safe(copy, tmp,
|
||||
&clp->async_copies, copies) {
|
||||
if (nfsd4_copy_on_sb(copy, sb)) {
|
||||
refcount_inc(©->refcount);
|
||||
/*
|
||||
* Hold a reference on the client while
|
||||
* nfsd4_stop_copy() runs. Unlike
|
||||
* nfsd4_unhash_copy(), cp_clp is not
|
||||
* NULLed here because nfsd4_send_cb_offload()
|
||||
* needs a valid client to send CB_OFFLOAD.
|
||||
* That function takes its own reference to
|
||||
* survive callback flight.
|
||||
*/
|
||||
kref_get(&clp->cl_nfsdfs.cl_ref);
|
||||
copy->nfserr = nfserr_admin_revoked;
|
||||
set_bit(NFSD4_COPY_F_CB_ERROR,
|
||||
©->cp_flags);
|
||||
list_move(©->copies, &to_cancel);
|
||||
}
|
||||
}
|
||||
spin_unlock(&clp->async_lock);
|
||||
}
|
||||
}
|
||||
spin_unlock(&nn->client_lock);
|
||||
|
||||
list_for_each_entry_safe(copy, tmp, &to_cancel, copies) {
|
||||
struct nfs4_client *clp = copy->cp_clp;
|
||||
|
||||
list_del_init(©->copies);
|
||||
nfsd4_stop_copy(copy);
|
||||
nfsd4_put_client(clp);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NFSD_V4_2_INTER_SSC
|
||||
|
||||
extern struct file *nfs42_ssc_open(struct vfsmount *ss_mnt,
|
||||
@@ -1754,6 +1894,7 @@ static void nfsd4_cb_offload_release(struct nfsd4_callback *cb)
|
||||
container_of(cbo, struct nfsd4_copy, cp_cb_offload);
|
||||
|
||||
set_bit(NFSD4_COPY_F_OFFLOAD_DONE, ©->cp_flags);
|
||||
nfsd4_put_client(cb->cb_clp);
|
||||
}
|
||||
|
||||
static int nfsd4_cb_offload_done(struct nfsd4_callback *cb,
|
||||
@@ -1873,10 +2014,14 @@ static void dup_copy_fields(struct nfsd4_copy *src, struct nfsd4_copy *dst)
|
||||
|
||||
static void release_copy_files(struct nfsd4_copy *copy)
|
||||
{
|
||||
if (copy->nf_src)
|
||||
if (copy->nf_src) {
|
||||
nfsd_file_put(copy->nf_src);
|
||||
if (copy->nf_dst)
|
||||
copy->nf_src = NULL;
|
||||
}
|
||||
if (copy->nf_dst) {
|
||||
nfsd_file_put(copy->nf_dst);
|
||||
copy->nf_dst = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void cleanup_async_copy(struct nfsd4_copy *copy)
|
||||
@@ -1895,18 +2040,34 @@ static void cleanup_async_copy(struct nfsd4_copy *copy)
|
||||
static void nfsd4_send_cb_offload(struct nfsd4_copy *copy)
|
||||
{
|
||||
struct nfsd4_cb_offload *cbo = ©->cp_cb_offload;
|
||||
struct nfs4_client *clp = copy->cp_clp;
|
||||
|
||||
/*
|
||||
* cp_clp is NULL when called via nfsd4_shutdown_copy() during
|
||||
* client destruction. Skip the callback; the client is gone.
|
||||
*/
|
||||
if (!clp) {
|
||||
set_bit(NFSD4_COPY_F_OFFLOAD_DONE, ©->cp_flags);
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(&cbo->co_res, ©->cp_res, sizeof(copy->cp_res));
|
||||
memcpy(&cbo->co_fh, ©->fh, sizeof(copy->fh));
|
||||
cbo->co_nfserr = copy->nfserr;
|
||||
cbo->co_retries = 5;
|
||||
|
||||
nfsd4_init_cb(&cbo->co_cb, copy->cp_clp, &nfsd4_cb_offload_ops,
|
||||
/*
|
||||
* Hold a reference on the client while the callback is in flight.
|
||||
* Released in nfsd4_cb_offload_release().
|
||||
*/
|
||||
kref_get(&clp->cl_nfsdfs.cl_ref);
|
||||
|
||||
nfsd4_init_cb(&cbo->co_cb, clp, &nfsd4_cb_offload_ops,
|
||||
NFSPROC4_CLNT_CB_OFFLOAD);
|
||||
nfsd41_cb_referring_call(&cbo->co_cb, &cbo->co_referring_sessionid,
|
||||
cbo->co_referring_slotid,
|
||||
cbo->co_referring_seqno);
|
||||
trace_nfsd_cb_offload(copy->cp_clp, &cbo->co_res.cb_stateid,
|
||||
trace_nfsd_cb_offload(clp, &cbo->co_res.cb_stateid,
|
||||
&cbo->co_fh, copy->cp_count, copy->nfserr);
|
||||
nfsd4_try_run_cb(&cbo->co_cb);
|
||||
}
|
||||
@@ -1921,6 +2082,7 @@ static void nfsd4_send_cb_offload(struct nfsd4_copy *copy)
|
||||
static int nfsd4_do_async_copy(void *data)
|
||||
{
|
||||
struct nfsd4_copy *copy = (struct nfsd4_copy *)data;
|
||||
__be32 nfserr = nfs_ok;
|
||||
|
||||
trace_nfsd_copy_async(copy);
|
||||
if (nfsd4_ssc_is_inter(copy)) {
|
||||
@@ -1931,23 +2093,25 @@ static int nfsd4_do_async_copy(void *data)
|
||||
if (IS_ERR(filp)) {
|
||||
switch (PTR_ERR(filp)) {
|
||||
case -EBADF:
|
||||
copy->nfserr = nfserr_wrong_type;
|
||||
nfserr = nfserr_wrong_type;
|
||||
break;
|
||||
default:
|
||||
copy->nfserr = nfserr_offload_denied;
|
||||
nfserr = nfserr_offload_denied;
|
||||
}
|
||||
/* ss_mnt will be unmounted by the laundromat */
|
||||
goto do_callback;
|
||||
}
|
||||
copy->nfserr = nfsd4_do_copy(copy, filp, copy->nf_dst->nf_file,
|
||||
false);
|
||||
nfserr = nfsd4_do_copy(copy, filp, copy->nf_dst->nf_file,
|
||||
false);
|
||||
nfsd4_cleanup_inter_ssc(copy->ss_nsui, filp, copy->nf_dst);
|
||||
} else {
|
||||
copy->nfserr = nfsd4_do_copy(copy, copy->nf_src->nf_file,
|
||||
copy->nf_dst->nf_file, false);
|
||||
nfserr = nfsd4_do_copy(copy, copy->nf_src->nf_file,
|
||||
copy->nf_dst->nf_file, false);
|
||||
}
|
||||
|
||||
do_callback:
|
||||
if (!test_bit(NFSD4_COPY_F_CB_ERROR, ©->cp_flags))
|
||||
copy->nfserr = nfserr;
|
||||
/* The kthread exits forthwith. Ensure that a subsequent
|
||||
* OFFLOAD_CANCEL won't try to kill it again. */
|
||||
set_bit(NFSD4_COPY_F_STOPPED, ©->cp_flags);
|
||||
@@ -2271,7 +2435,7 @@ _nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
status = check_attr_support(rqstp, cstate, verify->ve_bmval, NULL);
|
||||
status = check_attr_support(cstate, verify->ve_bmval, NULL);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
@@ -2281,6 +2445,11 @@ _nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
if (verify->ve_attrlen & 3)
|
||||
return nfserr_inval;
|
||||
|
||||
/* The POSIX draft ACLs cannot be tested via (N)VERIFY. */
|
||||
if (verify->ve_bmval[2] & (FATTR4_WORD2_POSIX_DEFAULT_ACL |
|
||||
FATTR4_WORD2_POSIX_ACCESS_ACL))
|
||||
return nfserr_inval;
|
||||
|
||||
/* count in words:
|
||||
* bitmap_len(1) + bitmap(2) + attr_len(1) = 4
|
||||
*/
|
||||
@@ -3016,8 +3185,6 @@ encode_op:
|
||||
BUG_ON(cstate->replay_owner);
|
||||
out:
|
||||
cstate->status = status;
|
||||
/* Reset deferral mechanism for RPC deferrals */
|
||||
set_bit(RQ_USEDEFERRAL, &rqstp->rq_flags);
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
|
||||
+29
-23
@@ -1253,7 +1253,7 @@ static void nfsd4_finalize_deleg_timestamps(struct nfs4_delegation *dp, struct f
|
||||
if (ret) {
|
||||
struct inode *inode = file_inode(f);
|
||||
|
||||
pr_notice_ratelimited("Unable to update timestamps on inode %02x:%02x:%lu: %d\n",
|
||||
pr_notice_ratelimited("nfsd: Unable to update timestamps on inode %02x:%02x:%lu: %d\n",
|
||||
MAJOR(inode->i_sb->s_dev),
|
||||
MINOR(inode->i_sb->s_dev),
|
||||
inode->i_ino, ret);
|
||||
@@ -2413,7 +2413,13 @@ static void __free_client(struct kref *k)
|
||||
kmem_cache_free(client_slab, clp);
|
||||
}
|
||||
|
||||
static void drop_client(struct nfs4_client *clp)
|
||||
/**
|
||||
* nfsd4_put_client - release a reference on an nfs4_client
|
||||
* @clp: the client to be released
|
||||
*
|
||||
* When the last reference is released, the client is freed.
|
||||
*/
|
||||
void nfsd4_put_client(struct nfs4_client *clp)
|
||||
{
|
||||
kref_put(&clp->cl_nfsdfs.cl_ref, __free_client);
|
||||
}
|
||||
@@ -2435,7 +2441,7 @@ free_client(struct nfs4_client *clp)
|
||||
clp->cl_nfsd_dentry = NULL;
|
||||
wake_up_all(&expiry_wq);
|
||||
}
|
||||
drop_client(clp);
|
||||
nfsd4_put_client(clp);
|
||||
}
|
||||
|
||||
/* must be called under the client_lock */
|
||||
@@ -2833,7 +2839,7 @@ static int client_info_show(struct seq_file *m, void *v)
|
||||
spin_unlock(&clp->cl_lock);
|
||||
seq_puts(m, "\n");
|
||||
|
||||
drop_client(clp);
|
||||
nfsd4_put_client(clp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -3099,7 +3105,7 @@ static int client_states_open(struct inode *inode, struct file *file)
|
||||
|
||||
ret = seq_open(file, &states_seq_ops);
|
||||
if (ret) {
|
||||
drop_client(clp);
|
||||
nfsd4_put_client(clp);
|
||||
return ret;
|
||||
}
|
||||
s = file->private_data;
|
||||
@@ -3113,7 +3119,7 @@ static int client_opens_release(struct inode *inode, struct file *file)
|
||||
struct nfs4_client *clp = m->private;
|
||||
|
||||
/* XXX: alternatively, we could get/drop in seq start/stop */
|
||||
drop_client(clp);
|
||||
nfsd4_put_client(clp);
|
||||
return seq_release(inode, file);
|
||||
}
|
||||
|
||||
@@ -3169,7 +3175,7 @@ static ssize_t client_ctl_write(struct file *file, const char __user *buf,
|
||||
if (!clp)
|
||||
return -ENXIO;
|
||||
force_expire_client(clp);
|
||||
drop_client(clp);
|
||||
nfsd4_put_client(clp);
|
||||
return 7;
|
||||
}
|
||||
|
||||
@@ -3204,7 +3210,7 @@ nfsd4_cb_recall_any_release(struct nfsd4_callback *cb)
|
||||
{
|
||||
struct nfs4_client *clp = cb->cb_clp;
|
||||
|
||||
drop_client(clp);
|
||||
nfsd4_put_client(clp);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -6353,7 +6359,8 @@ nfs4_open_delegation(struct svc_rqst *rqstp, struct nfsd4_open *open,
|
||||
dp->dl_ctime = stat.ctime;
|
||||
dp->dl_mtime = stat.mtime;
|
||||
spin_lock(&f->f_lock);
|
||||
f->f_mode |= FMODE_NOCMTIME;
|
||||
if (deleg_ts)
|
||||
f->f_mode |= FMODE_NOCMTIME;
|
||||
spin_unlock(&f->f_lock);
|
||||
trace_nfsd_deleg_write(&dp->dl_stid.sc_stateid);
|
||||
} else {
|
||||
@@ -6637,14 +6644,14 @@ bool nfsd4_force_end_grace(struct nfsd_net *nn)
|
||||
{
|
||||
if (!nn->client_tracking_ops)
|
||||
return false;
|
||||
spin_lock(&nn->client_lock);
|
||||
if (nn->grace_ended || !nn->client_tracking_active) {
|
||||
spin_unlock(&nn->client_lock);
|
||||
if (READ_ONCE(nn->grace_ended))
|
||||
return false;
|
||||
}
|
||||
/* laundromat_work must be initialised now, though it might be disabled */
|
||||
WRITE_ONCE(nn->grace_end_forced, true);
|
||||
/* mod_delayed_work() doesn't queue work after
|
||||
* nfs4_state_shutdown_net() has called disable_delayed_work_sync()
|
||||
*/
|
||||
mod_delayed_work(laundry_wq, &nn->laundromat_work, 0);
|
||||
spin_unlock(&nn->client_lock);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -8980,7 +8987,6 @@ static int nfs4_state_create_net(struct net *net)
|
||||
nn->boot_time = ktime_get_real_seconds();
|
||||
nn->grace_ended = false;
|
||||
nn->grace_end_forced = false;
|
||||
nn->client_tracking_active = false;
|
||||
nn->nfsd4_manager.block_opens = true;
|
||||
INIT_LIST_HEAD(&nn->nfsd4_manager.list);
|
||||
INIT_LIST_HEAD(&nn->client_lru);
|
||||
@@ -8995,6 +9001,8 @@ static int nfs4_state_create_net(struct net *net)
|
||||
INIT_LIST_HEAD(&nn->blocked_locks_lru);
|
||||
|
||||
INIT_DELAYED_WORK(&nn->laundromat_work, laundromat_main);
|
||||
/* Make sure this cannot run until client tracking is initialised */
|
||||
disable_delayed_work(&nn->laundromat_work);
|
||||
INIT_WORK(&nn->nfsd_shrinker_work, nfsd4_state_shrinker_worker);
|
||||
get_net(net);
|
||||
|
||||
@@ -9062,9 +9070,7 @@ nfs4_state_start_net(struct net *net)
|
||||
locks_start_grace(net, &nn->nfsd4_manager);
|
||||
nfsd4_client_tracking_init(net);
|
||||
/* safe for laundromat to run now */
|
||||
spin_lock(&nn->client_lock);
|
||||
nn->client_tracking_active = true;
|
||||
spin_unlock(&nn->client_lock);
|
||||
enable_delayed_work(&nn->laundromat_work);
|
||||
if (nn->track_reclaim_completes && nn->reclaim_str_hashtbl_size == 0)
|
||||
goto skip_grace;
|
||||
printk(KERN_INFO "NFSD: starting %lld-second grace period (net %x)\n",
|
||||
@@ -9113,10 +9119,7 @@ nfs4_state_shutdown_net(struct net *net)
|
||||
|
||||
shrinker_free(nn->nfsd_client_shrinker);
|
||||
cancel_work_sync(&nn->nfsd_shrinker_work);
|
||||
spin_lock(&nn->client_lock);
|
||||
nn->client_tracking_active = false;
|
||||
spin_unlock(&nn->client_lock);
|
||||
cancel_delayed_work_sync(&nn->laundromat_work);
|
||||
disable_delayed_work_sync(&nn->laundromat_work);
|
||||
locks_end_grace(&nn->nfsd4_manager);
|
||||
|
||||
INIT_LIST_HEAD(&reaplist);
|
||||
@@ -9520,8 +9523,10 @@ nfsd_get_dir_deleg(struct nfsd4_compound_state *cstate,
|
||||
spin_unlock(&clp->cl_lock);
|
||||
spin_unlock(&state_lock);
|
||||
|
||||
if (!status)
|
||||
if (!status) {
|
||||
put_nfs4_file(fp);
|
||||
return dp;
|
||||
}
|
||||
|
||||
/* Something failed. Drop the lease and clean up the stid */
|
||||
kernel_setlease(fp->fi_deleg_file->nf_file, F_UNLCK, NULL, (void **)&dp);
|
||||
@@ -9529,5 +9534,6 @@ out_put_stid:
|
||||
nfs4_put_stid(&dp->dl_stid);
|
||||
out_delegees:
|
||||
put_deleg_file(fp);
|
||||
put_nfs4_file(fp);
|
||||
return ERR_PTR(status);
|
||||
}
|
||||
|
||||
+357
-6
@@ -43,6 +43,7 @@
|
||||
#include <linux/sunrpc/addr.h>
|
||||
#include <linux/xattr.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/nfsacl.h>
|
||||
|
||||
#include <uapi/linux/xattr.h>
|
||||
|
||||
@@ -377,10 +378,111 @@ nfsd4_decode_security_label(struct nfsd4_compoundargs *argp,
|
||||
return nfs_ok;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NFSD_V4_POSIX_ACLS
|
||||
|
||||
static short nfsd4_posixacetag4_to_tag(posixacetag4 tag)
|
||||
{
|
||||
switch (tag) {
|
||||
case POSIXACE4_TAG_USER_OBJ: return ACL_USER_OBJ;
|
||||
case POSIXACE4_TAG_GROUP_OBJ: return ACL_GROUP_OBJ;
|
||||
case POSIXACE4_TAG_USER: return ACL_USER;
|
||||
case POSIXACE4_TAG_GROUP: return ACL_GROUP;
|
||||
case POSIXACE4_TAG_MASK: return ACL_MASK;
|
||||
case POSIXACE4_TAG_OTHER: return ACL_OTHER;
|
||||
}
|
||||
return ACL_OTHER;
|
||||
}
|
||||
|
||||
static __be32
|
||||
nfsd4_decode_posixace4(struct nfsd4_compoundargs *argp,
|
||||
struct posix_acl_entry *ace)
|
||||
{
|
||||
posixaceperm4 perm;
|
||||
__be32 *p, status;
|
||||
posixacetag4 tag;
|
||||
u32 len;
|
||||
|
||||
if (!xdrgen_decode_posixacetag4(argp->xdr, &tag))
|
||||
return nfserr_bad_xdr;
|
||||
ace->e_tag = nfsd4_posixacetag4_to_tag(tag);
|
||||
|
||||
if (!xdrgen_decode_posixaceperm4(argp->xdr, &perm))
|
||||
return nfserr_bad_xdr;
|
||||
if (perm & ~S_IRWXO)
|
||||
return nfserr_bad_xdr;
|
||||
ace->e_perm = perm;
|
||||
|
||||
if (xdr_stream_decode_u32(argp->xdr, &len) < 0)
|
||||
return nfserr_bad_xdr;
|
||||
p = xdr_inline_decode(argp->xdr, len);
|
||||
if (!p)
|
||||
return nfserr_bad_xdr;
|
||||
switch (tag) {
|
||||
case POSIXACE4_TAG_USER:
|
||||
if (len > 0)
|
||||
status = nfsd_map_name_to_uid(argp->rqstp,
|
||||
(char *)p, len, &ace->e_uid);
|
||||
else
|
||||
status = nfserr_bad_xdr;
|
||||
break;
|
||||
case POSIXACE4_TAG_GROUP:
|
||||
if (len > 0)
|
||||
status = nfsd_map_name_to_gid(argp->rqstp,
|
||||
(char *)p, len, &ace->e_gid);
|
||||
else
|
||||
status = nfserr_bad_xdr;
|
||||
break;
|
||||
default:
|
||||
status = nfs_ok;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static noinline __be32
|
||||
nfsd4_decode_posixacl(struct nfsd4_compoundargs *argp, struct posix_acl **acl)
|
||||
{
|
||||
struct posix_acl_entry *ace;
|
||||
__be32 status;
|
||||
u32 count;
|
||||
|
||||
if (xdr_stream_decode_u32(argp->xdr, &count) < 0)
|
||||
return nfserr_bad_xdr;
|
||||
|
||||
*acl = posix_acl_alloc(count, GFP_KERNEL);
|
||||
if (*acl == NULL)
|
||||
return nfserr_resource;
|
||||
|
||||
(*acl)->a_count = count;
|
||||
for (ace = (*acl)->a_entries; ace < (*acl)->a_entries + count; ace++) {
|
||||
status = nfsd4_decode_posixace4(argp, ace);
|
||||
if (status) {
|
||||
posix_acl_release(*acl);
|
||||
*acl = NULL;
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* posix_acl_valid() requires the ACEs to be sorted.
|
||||
* If they are already sorted, sort_pacl_range() will return
|
||||
* after one pass through the ACEs, since it implements bubble sort.
|
||||
* Note that a count == 0 is used to delete a POSIX ACL and a count
|
||||
* of 1 or 2 will always be found invalid by posix_acl_valid().
|
||||
*/
|
||||
if (count >= 3)
|
||||
sort_pacl_range(*acl, 0, count - 1);
|
||||
|
||||
return nfs_ok;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_NFSD_V4_POSIX_ACLS */
|
||||
|
||||
static __be32
|
||||
nfsd4_decode_fattr4(struct nfsd4_compoundargs *argp, u32 *bmval, u32 bmlen,
|
||||
struct iattr *iattr, struct nfs4_acl **acl,
|
||||
struct xdr_netobj *label, int *umask)
|
||||
struct xdr_netobj *label, int *umask,
|
||||
struct posix_acl **dpaclp, struct posix_acl **paclp)
|
||||
{
|
||||
unsigned int starting_pos;
|
||||
u32 attrlist4_count;
|
||||
@@ -543,9 +645,40 @@ nfsd4_decode_fattr4(struct nfsd4_compoundargs *argp, u32 *bmval, u32 bmlen,
|
||||
ATTR_MTIME | ATTR_MTIME_SET | ATTR_DELEG;
|
||||
}
|
||||
|
||||
*dpaclp = NULL;
|
||||
*paclp = NULL;
|
||||
#ifdef CONFIG_NFSD_V4_POSIX_ACLS
|
||||
if (bmval[2] & FATTR4_WORD2_POSIX_DEFAULT_ACL) {
|
||||
struct posix_acl *dpacl;
|
||||
|
||||
status = nfsd4_decode_posixacl(argp, &dpacl);
|
||||
if (status)
|
||||
return status;
|
||||
*dpaclp = dpacl;
|
||||
}
|
||||
if (bmval[2] & FATTR4_WORD2_POSIX_ACCESS_ACL) {
|
||||
struct posix_acl *pacl;
|
||||
|
||||
status = nfsd4_decode_posixacl(argp, &pacl);
|
||||
if (status) {
|
||||
posix_acl_release(*dpaclp);
|
||||
*dpaclp = NULL;
|
||||
return status;
|
||||
}
|
||||
*paclp = pacl;
|
||||
}
|
||||
#endif /* CONFIG_NFSD_V4_POSIX_ACLS */
|
||||
|
||||
/* request sanity: did attrlist4 contain the expected number of words? */
|
||||
if (attrlist4_count != xdr_stream_pos(argp->xdr) - starting_pos)
|
||||
if (attrlist4_count != xdr_stream_pos(argp->xdr) - starting_pos) {
|
||||
#ifdef CONFIG_NFSD_V4_POSIX_ACLS
|
||||
posix_acl_release(*dpaclp);
|
||||
posix_acl_release(*paclp);
|
||||
*dpaclp = NULL;
|
||||
*paclp = NULL;
|
||||
#endif
|
||||
return nfserr_bad_xdr;
|
||||
}
|
||||
|
||||
return nfs_ok;
|
||||
}
|
||||
@@ -849,7 +982,8 @@ nfsd4_decode_create(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
|
||||
status = nfsd4_decode_fattr4(argp, create->cr_bmval,
|
||||
ARRAY_SIZE(create->cr_bmval),
|
||||
&create->cr_iattr, &create->cr_acl,
|
||||
&create->cr_label, &create->cr_umask);
|
||||
&create->cr_label, &create->cr_umask,
|
||||
&create->cr_dpacl, &create->cr_pacl);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
@@ -1000,7 +1134,8 @@ nfsd4_decode_createhow4(struct nfsd4_compoundargs *argp, struct nfsd4_open *open
|
||||
status = nfsd4_decode_fattr4(argp, open->op_bmval,
|
||||
ARRAY_SIZE(open->op_bmval),
|
||||
&open->op_iattr, &open->op_acl,
|
||||
&open->op_label, &open->op_umask);
|
||||
&open->op_label, &open->op_umask,
|
||||
&open->op_dpacl, &open->op_pacl);
|
||||
if (status)
|
||||
return status;
|
||||
break;
|
||||
@@ -1018,7 +1153,8 @@ nfsd4_decode_createhow4(struct nfsd4_compoundargs *argp, struct nfsd4_open *open
|
||||
status = nfsd4_decode_fattr4(argp, open->op_bmval,
|
||||
ARRAY_SIZE(open->op_bmval),
|
||||
&open->op_iattr, &open->op_acl,
|
||||
&open->op_label, &open->op_umask);
|
||||
&open->op_label, &open->op_umask,
|
||||
&open->op_dpacl, &open->op_pacl);
|
||||
if (status)
|
||||
return status;
|
||||
break;
|
||||
@@ -1345,7 +1481,8 @@ nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
|
||||
return nfsd4_decode_fattr4(argp, setattr->sa_bmval,
|
||||
ARRAY_SIZE(setattr->sa_bmval),
|
||||
&setattr->sa_iattr, &setattr->sa_acl,
|
||||
&setattr->sa_label, NULL);
|
||||
&setattr->sa_label, NULL, &setattr->sa_dpacl,
|
||||
&setattr->sa_pacl);
|
||||
}
|
||||
|
||||
static __be32
|
||||
@@ -2849,6 +2986,89 @@ nfsd4_encode_security_label(struct xdr_stream *xdr, struct svc_rqst *rqstp,
|
||||
{ return 0; }
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NFSD_V4_POSIX_ACLS
|
||||
|
||||
static int nfsd4_posix_tagtotype(short tag)
|
||||
{
|
||||
switch (tag) {
|
||||
case ACL_USER_OBJ: return POSIXACE4_TAG_USER_OBJ;
|
||||
case ACL_GROUP_OBJ: return POSIXACE4_TAG_GROUP_OBJ;
|
||||
case ACL_USER: return POSIXACE4_TAG_USER;
|
||||
case ACL_GROUP: return POSIXACE4_TAG_GROUP;
|
||||
case ACL_MASK: return POSIXACE4_TAG_MASK;
|
||||
case ACL_OTHER: return POSIXACE4_TAG_OTHER;
|
||||
default: return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static __be32
|
||||
nfsd4_encode_posixace4(struct xdr_stream *xdr, struct svc_rqst *rqstp,
|
||||
struct posix_acl_entry *acep)
|
||||
{
|
||||
__be32 status;
|
||||
int type;
|
||||
|
||||
type = nfsd4_posix_tagtotype(acep->e_tag);
|
||||
if (type < 0)
|
||||
return nfserr_resource;
|
||||
if (!xdrgen_encode_posixacetag4(xdr, type))
|
||||
return nfserr_resource;
|
||||
if (!xdrgen_encode_posixaceperm4(xdr, acep->e_perm))
|
||||
return nfserr_resource;
|
||||
|
||||
/* who */
|
||||
switch (acep->e_tag) {
|
||||
case ACL_USER_OBJ:
|
||||
case ACL_GROUP_OBJ:
|
||||
case ACL_MASK:
|
||||
case ACL_OTHER:
|
||||
if (xdr_stream_encode_u32(xdr, 0) != XDR_UNIT)
|
||||
return nfserr_resource;
|
||||
break;
|
||||
case ACL_USER:
|
||||
status = nfsd4_encode_user(xdr, rqstp, acep->e_uid);
|
||||
if (status != nfs_ok)
|
||||
return status;
|
||||
break;
|
||||
case ACL_GROUP:
|
||||
status = nfsd4_encode_group(xdr, rqstp, acep->e_gid);
|
||||
if (status != nfs_ok)
|
||||
return status;
|
||||
break;
|
||||
default:
|
||||
return nfserr_resource;
|
||||
}
|
||||
return nfs_ok;
|
||||
}
|
||||
|
||||
static __be32
|
||||
nfsd4_encode_posixacl(struct xdr_stream *xdr, struct svc_rqst *rqstp,
|
||||
struct posix_acl *acl)
|
||||
{
|
||||
__be32 status;
|
||||
int i;
|
||||
|
||||
if (!acl) {
|
||||
if (xdr_stream_encode_u32(xdr, 0) != XDR_UNIT)
|
||||
return nfserr_resource;
|
||||
return nfs_ok;
|
||||
}
|
||||
|
||||
if (acl->a_count > NFS_ACL_MAX_ENTRIES)
|
||||
return nfserr_resource;
|
||||
if (xdr_stream_encode_u32(xdr, acl->a_count) != XDR_UNIT)
|
||||
return nfserr_resource;
|
||||
for (i = 0; i < acl->a_count; i++) {
|
||||
status = nfsd4_encode_posixace4(xdr, rqstp, &acl->a_entries[i]);
|
||||
if (status != nfs_ok)
|
||||
return status;
|
||||
}
|
||||
|
||||
return nfs_ok;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_NFSD_V4_POSIX_ACL */
|
||||
|
||||
static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *bmval2, u32 *rdattr_err)
|
||||
{
|
||||
/* As per referral draft: */
|
||||
@@ -2929,6 +3149,10 @@ struct nfsd4_fattr_args {
|
||||
u64 change_attr;
|
||||
#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
|
||||
struct lsm_context context;
|
||||
#endif
|
||||
#ifdef CONFIG_NFSD_V4_POSIX_ACLS
|
||||
struct posix_acl *dpacl;
|
||||
struct posix_acl *pacl;
|
||||
#endif
|
||||
u32 rdattr_err;
|
||||
bool contextsupport;
|
||||
@@ -3470,6 +3694,42 @@ static __be32 nfsd4_encode_fattr4_open_arguments(struct xdr_stream *xdr,
|
||||
return nfs_ok;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NFSD_V4_POSIX_ACLS
|
||||
|
||||
static __be32 nfsd4_encode_fattr4_acl_trueform(struct xdr_stream *xdr,
|
||||
const struct nfsd4_fattr_args *args)
|
||||
{
|
||||
aclmodel4 trueform = ACL_MODEL_NONE;
|
||||
|
||||
if (IS_POSIXACL(d_inode(args->dentry)))
|
||||
trueform = ACL_MODEL_POSIX_DRAFT;
|
||||
if (!xdrgen_encode_aclmodel4(xdr, trueform))
|
||||
return nfserr_resource;
|
||||
return nfs_ok;
|
||||
}
|
||||
|
||||
static __be32 nfsd4_encode_fattr4_acl_trueform_scope(struct xdr_stream *xdr,
|
||||
const struct nfsd4_fattr_args *args)
|
||||
{
|
||||
if (!xdrgen_encode_aclscope4(xdr, ACL_SCOPE_FILE_SYSTEM))
|
||||
return nfserr_resource;
|
||||
return nfs_ok;
|
||||
}
|
||||
|
||||
static __be32 nfsd4_encode_fattr4_posix_default_acl(struct xdr_stream *xdr,
|
||||
const struct nfsd4_fattr_args *args)
|
||||
{
|
||||
return nfsd4_encode_posixacl(xdr, args->rqstp, args->dpacl);
|
||||
}
|
||||
|
||||
static __be32 nfsd4_encode_fattr4_posix_access_acl(struct xdr_stream *xdr,
|
||||
const struct nfsd4_fattr_args *args)
|
||||
{
|
||||
return nfsd4_encode_posixacl(xdr, args->rqstp, args->pacl);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_NFSD_V4_POSIX_ACLS */
|
||||
|
||||
static const nfsd4_enc_attr nfsd4_enc_fattr4_encode_ops[] = {
|
||||
[FATTR4_SUPPORTED_ATTRS] = nfsd4_encode_fattr4_supported_attrs,
|
||||
[FATTR4_TYPE] = nfsd4_encode_fattr4_type,
|
||||
@@ -3573,6 +3833,22 @@ static const nfsd4_enc_attr nfsd4_enc_fattr4_encode_ops[] = {
|
||||
[FATTR4_TIME_DELEG_ACCESS] = nfsd4_encode_fattr4__inval,
|
||||
[FATTR4_TIME_DELEG_MODIFY] = nfsd4_encode_fattr4__inval,
|
||||
[FATTR4_OPEN_ARGUMENTS] = nfsd4_encode_fattr4_open_arguments,
|
||||
|
||||
/* Reserved */
|
||||
[87] = nfsd4_encode_fattr4__inval,
|
||||
[88] = nfsd4_encode_fattr4__inval,
|
||||
|
||||
#ifdef CONFIG_NFSD_V4_POSIX_ACLS
|
||||
[FATTR4_ACL_TRUEFORM] = nfsd4_encode_fattr4_acl_trueform,
|
||||
[FATTR4_ACL_TRUEFORM_SCOPE] = nfsd4_encode_fattr4_acl_trueform_scope,
|
||||
[FATTR4_POSIX_DEFAULT_ACL] = nfsd4_encode_fattr4_posix_default_acl,
|
||||
[FATTR4_POSIX_ACCESS_ACL] = nfsd4_encode_fattr4_posix_access_acl,
|
||||
#else
|
||||
[FATTR4_ACL_TRUEFORM] = nfsd4_encode_fattr4__noop,
|
||||
[FATTR4_ACL_TRUEFORM_SCOPE] = nfsd4_encode_fattr4__noop,
|
||||
[FATTR4_POSIX_DEFAULT_ACL] = nfsd4_encode_fattr4__noop,
|
||||
[FATTR4_POSIX_ACCESS_ACL] = nfsd4_encode_fattr4__noop,
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -3613,6 +3889,10 @@ nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xdr_stream *xdr,
|
||||
#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
|
||||
args.context.context = NULL;
|
||||
#endif
|
||||
#ifdef CONFIG_NFSD_V4_POSIX_ACLS
|
||||
args.dpacl = NULL;
|
||||
args.pacl = NULL;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Make a local copy of the attribute bitmap that can be modified.
|
||||
@@ -3719,6 +3999,55 @@ nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xdr_stream *xdr,
|
||||
}
|
||||
#endif /* CONFIG_NFSD_V4_SECURITY_LABEL */
|
||||
|
||||
#ifdef CONFIG_NFSD_V4_POSIX_ACLS
|
||||
if (attrmask[2] & FATTR4_WORD2_POSIX_DEFAULT_ACL) {
|
||||
struct inode *inode = d_inode(dentry);
|
||||
struct posix_acl *dpacl;
|
||||
|
||||
if (S_ISDIR(inode->i_mode)) {
|
||||
dpacl = get_inode_acl(inode, ACL_TYPE_DEFAULT);
|
||||
if (IS_ERR(dpacl)) {
|
||||
switch (PTR_ERR(dpacl)) {
|
||||
case -EOPNOTSUPP:
|
||||
attrmask[2] &= ~FATTR4_WORD2_POSIX_DEFAULT_ACL;
|
||||
break;
|
||||
case -EINVAL:
|
||||
status = nfserr_attrnotsupp;
|
||||
goto out;
|
||||
default:
|
||||
err = PTR_ERR(dpacl);
|
||||
goto out_nfserr;
|
||||
}
|
||||
} else {
|
||||
args.dpacl = dpacl;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (attrmask[2] & FATTR4_WORD2_POSIX_ACCESS_ACL) {
|
||||
struct inode *inode = d_inode(dentry);
|
||||
struct posix_acl *pacl;
|
||||
|
||||
pacl = get_inode_acl(inode, ACL_TYPE_ACCESS);
|
||||
if (!pacl)
|
||||
pacl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
|
||||
if (IS_ERR(pacl)) {
|
||||
switch (PTR_ERR(pacl)) {
|
||||
case -EOPNOTSUPP:
|
||||
attrmask[2] &= ~FATTR4_WORD2_POSIX_ACCESS_ACL;
|
||||
break;
|
||||
case -EINVAL:
|
||||
status = nfserr_attrnotsupp;
|
||||
goto out;
|
||||
default:
|
||||
err = PTR_ERR(pacl);
|
||||
goto out_nfserr;
|
||||
}
|
||||
} else {
|
||||
args.pacl = pacl;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_NFSD_V4_POSIX_ACLS */
|
||||
|
||||
/* attrmask */
|
||||
status = nfsd4_encode_bitmap4(xdr, attrmask[0], attrmask[1],
|
||||
attrmask[2]);
|
||||
@@ -3742,6 +4071,12 @@ nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xdr_stream *xdr,
|
||||
status = nfs_ok;
|
||||
|
||||
out:
|
||||
#ifdef CONFIG_NFSD_V4_POSIX_ACLS
|
||||
if (args.dpacl)
|
||||
posix_acl_release(args.dpacl);
|
||||
if (args.pacl)
|
||||
posix_acl_release(args.pacl);
|
||||
#endif /* CONFIG_NFSD_V4_POSIX_ACLS */
|
||||
#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
|
||||
if (args.context.context)
|
||||
security_release_secctx(&args.context);
|
||||
@@ -6013,6 +6348,22 @@ nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
|
||||
args->ops = args->iops;
|
||||
args->rqstp = rqstp;
|
||||
|
||||
/*
|
||||
* NFSv4 operation decoders can invoke svc cache lookups
|
||||
* that trigger svc_defer() when RQ_USEDEFERRAL is set,
|
||||
* setting RQ_DROPME. This creates two problems:
|
||||
*
|
||||
* 1. Non-idempotency: Compounds make it too hard to avoid
|
||||
* problems if a request is deferred and replayed.
|
||||
*
|
||||
* 2. Session slot leakage (NFSv4.1+): If RQ_DROPME is set
|
||||
* during decode but SEQUENCE executes successfully, the
|
||||
* session slot will be marked INUSE. The request is then
|
||||
* dropped before encoding, so the slot is never released,
|
||||
* rendering it permanently unusable by the client.
|
||||
*/
|
||||
clear_bit(RQ_USEDEFERRAL, &rqstp->rq_flags);
|
||||
|
||||
return nfsd4_decode_compound(args);
|
||||
}
|
||||
|
||||
|
||||
+332
-19
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Generated by xdrgen. Manual edits will be lost.
|
||||
// XDR specification file: ../../Documentation/sunrpc/xdr/nfs4_1.x
|
||||
// XDR specification modification time: Mon Oct 14 09:10:13 2024
|
||||
// XDR specification modification time: Thu Jan 8 23:12:07 2026
|
||||
|
||||
#include <linux/sunrpc/svc.h>
|
||||
|
||||
@@ -11,13 +11,13 @@ static bool __maybe_unused
|
||||
xdrgen_decode_int64_t(struct xdr_stream *xdr, int64_t *ptr)
|
||||
{
|
||||
return xdrgen_decode_hyper(xdr, ptr);
|
||||
};
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_decode_uint32_t(struct xdr_stream *xdr, uint32_t *ptr)
|
||||
{
|
||||
return xdrgen_decode_unsigned_int(xdr, ptr);
|
||||
};
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_decode_bitmap4(struct xdr_stream *xdr, bitmap4 *ptr)
|
||||
@@ -28,7 +28,31 @@ xdrgen_decode_bitmap4(struct xdr_stream *xdr, bitmap4 *ptr)
|
||||
if (!xdrgen_decode_uint32_t(xdr, &ptr->element[i]))
|
||||
return false;
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_decode_utf8string(struct xdr_stream *xdr, utf8string *ptr)
|
||||
{
|
||||
return xdrgen_decode_opaque(xdr, ptr, 0);
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_decode_utf8str_cis(struct xdr_stream *xdr, utf8str_cis *ptr)
|
||||
{
|
||||
return xdrgen_decode_utf8string(xdr, ptr);
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_decode_utf8str_cs(struct xdr_stream *xdr, utf8str_cs *ptr)
|
||||
{
|
||||
return xdrgen_decode_utf8string(xdr, ptr);
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_decode_utf8str_mixed(struct xdr_stream *xdr, utf8str_mixed *ptr)
|
||||
{
|
||||
return xdrgen_decode_utf8string(xdr, ptr);
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_decode_nfstime4(struct xdr_stream *xdr, struct nfstime4 *ptr)
|
||||
@@ -38,13 +62,13 @@ xdrgen_decode_nfstime4(struct xdr_stream *xdr, struct nfstime4 *ptr)
|
||||
if (!xdrgen_decode_uint32_t(xdr, &ptr->nseconds))
|
||||
return false;
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_decode_fattr4_offline(struct xdr_stream *xdr, fattr4_offline *ptr)
|
||||
{
|
||||
return xdrgen_decode_bool(xdr, ptr);
|
||||
};
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_decode_open_arguments4(struct xdr_stream *xdr, struct open_arguments4 *ptr)
|
||||
@@ -60,7 +84,7 @@ xdrgen_decode_open_arguments4(struct xdr_stream *xdr, struct open_arguments4 *pt
|
||||
if (!xdrgen_decode_bitmap4(xdr, &ptr->oa_create_mode))
|
||||
return false;
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_decode_open_args_share_access4(struct xdr_stream *xdr, open_args_share_access4 *ptr)
|
||||
@@ -69,6 +93,15 @@ xdrgen_decode_open_args_share_access4(struct xdr_stream *xdr, open_args_share_ac
|
||||
|
||||
if (xdr_stream_decode_u32(xdr, &val) < 0)
|
||||
return false;
|
||||
/* Compiler may optimize to a range check for dense enums */
|
||||
switch (val) {
|
||||
case OPEN_ARGS_SHARE_ACCESS_READ:
|
||||
case OPEN_ARGS_SHARE_ACCESS_WRITE:
|
||||
case OPEN_ARGS_SHARE_ACCESS_BOTH:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
*ptr = val;
|
||||
return true;
|
||||
}
|
||||
@@ -80,6 +113,16 @@ xdrgen_decode_open_args_share_deny4(struct xdr_stream *xdr, open_args_share_deny
|
||||
|
||||
if (xdr_stream_decode_u32(xdr, &val) < 0)
|
||||
return false;
|
||||
/* Compiler may optimize to a range check for dense enums */
|
||||
switch (val) {
|
||||
case OPEN_ARGS_SHARE_DENY_NONE:
|
||||
case OPEN_ARGS_SHARE_DENY_READ:
|
||||
case OPEN_ARGS_SHARE_DENY_WRITE:
|
||||
case OPEN_ARGS_SHARE_DENY_BOTH:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
*ptr = val;
|
||||
return true;
|
||||
}
|
||||
@@ -91,6 +134,19 @@ xdrgen_decode_open_args_share_access_want4(struct xdr_stream *xdr, open_args_sha
|
||||
|
||||
if (xdr_stream_decode_u32(xdr, &val) < 0)
|
||||
return false;
|
||||
/* Compiler may optimize to a range check for dense enums */
|
||||
switch (val) {
|
||||
case OPEN_ARGS_SHARE_ACCESS_WANT_ANY_DELEG:
|
||||
case OPEN_ARGS_SHARE_ACCESS_WANT_NO_DELEG:
|
||||
case OPEN_ARGS_SHARE_ACCESS_WANT_CANCEL:
|
||||
case OPEN_ARGS_SHARE_ACCESS_WANT_SIGNAL_DELEG_WHEN_RESRC_AVAIL:
|
||||
case OPEN_ARGS_SHARE_ACCESS_WANT_PUSH_DELEG_WHEN_UNCONTENDED:
|
||||
case OPEN_ARGS_SHARE_ACCESS_WANT_DELEG_TIMESTAMPS:
|
||||
case OPEN_ARGS_SHARE_ACCESS_WANT_OPEN_XOR_DELEGATION:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
*ptr = val;
|
||||
return true;
|
||||
}
|
||||
@@ -102,6 +158,19 @@ xdrgen_decode_open_args_open_claim4(struct xdr_stream *xdr, open_args_open_claim
|
||||
|
||||
if (xdr_stream_decode_u32(xdr, &val) < 0)
|
||||
return false;
|
||||
/* Compiler may optimize to a range check for dense enums */
|
||||
switch (val) {
|
||||
case OPEN_ARGS_OPEN_CLAIM_NULL:
|
||||
case OPEN_ARGS_OPEN_CLAIM_PREVIOUS:
|
||||
case OPEN_ARGS_OPEN_CLAIM_DELEGATE_CUR:
|
||||
case OPEN_ARGS_OPEN_CLAIM_DELEGATE_PREV:
|
||||
case OPEN_ARGS_OPEN_CLAIM_FH:
|
||||
case OPEN_ARGS_OPEN_CLAIM_DELEG_CUR_FH:
|
||||
case OPEN_ARGS_OPEN_CLAIM_DELEG_PREV_FH:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
*ptr = val;
|
||||
return true;
|
||||
}
|
||||
@@ -113,6 +182,16 @@ xdrgen_decode_open_args_createmode4(struct xdr_stream *xdr, open_args_createmode
|
||||
|
||||
if (xdr_stream_decode_u32(xdr, &val) < 0)
|
||||
return false;
|
||||
/* Compiler may optimize to a range check for dense enums */
|
||||
switch (val) {
|
||||
case OPEN_ARGS_CREATEMODE_UNCHECKED4:
|
||||
case OPEN_ARGS_CREATE_MODE_GUARDED:
|
||||
case OPEN_ARGS_CREATEMODE_EXCLUSIVE4:
|
||||
case OPEN_ARGS_CREATE_MODE_EXCLUSIVE4_1:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
*ptr = val;
|
||||
return true;
|
||||
}
|
||||
@@ -121,19 +200,28 @@ bool
|
||||
xdrgen_decode_fattr4_open_arguments(struct xdr_stream *xdr, fattr4_open_arguments *ptr)
|
||||
{
|
||||
return xdrgen_decode_open_arguments4(xdr, ptr);
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine what OPEN supports.
|
||||
*/
|
||||
|
||||
bool
|
||||
xdrgen_decode_fattr4_time_deleg_access(struct xdr_stream *xdr, fattr4_time_deleg_access *ptr)
|
||||
{
|
||||
return xdrgen_decode_nfstime4(xdr, ptr);
|
||||
};
|
||||
}
|
||||
|
||||
bool
|
||||
xdrgen_decode_fattr4_time_deleg_modify(struct xdr_stream *xdr, fattr4_time_deleg_modify *ptr)
|
||||
{
|
||||
return xdrgen_decode_nfstime4(xdr, ptr);
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
* New RECOMMENDED Attribute for
|
||||
* delegation caching of times
|
||||
*/
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_decode_open_delegation_type4(struct xdr_stream *xdr, open_delegation_type4 *ptr)
|
||||
@@ -142,21 +230,152 @@ xdrgen_decode_open_delegation_type4(struct xdr_stream *xdr, open_delegation_type
|
||||
|
||||
if (xdr_stream_decode_u32(xdr, &val) < 0)
|
||||
return false;
|
||||
/* Compiler may optimize to a range check for dense enums */
|
||||
switch (val) {
|
||||
case OPEN_DELEGATE_NONE:
|
||||
case OPEN_DELEGATE_READ:
|
||||
case OPEN_DELEGATE_WRITE:
|
||||
case OPEN_DELEGATE_NONE_EXT:
|
||||
case OPEN_DELEGATE_READ_ATTRS_DELEG:
|
||||
case OPEN_DELEGATE_WRITE_ATTRS_DELEG:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
*ptr = val;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
xdrgen_decode_aclmodel4(struct xdr_stream *xdr, aclmodel4 *ptr)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
if (xdr_stream_decode_u32(xdr, &val) < 0)
|
||||
return false;
|
||||
/* Compiler may optimize to a range check for dense enums */
|
||||
switch (val) {
|
||||
case ACL_MODEL_NFS4:
|
||||
case ACL_MODEL_POSIX_DRAFT:
|
||||
case ACL_MODEL_NONE:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
*ptr = val;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
xdrgen_decode_aclscope4(struct xdr_stream *xdr, aclscope4 *ptr)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
if (xdr_stream_decode_u32(xdr, &val) < 0)
|
||||
return false;
|
||||
/* Compiler may optimize to a range check for dense enums */
|
||||
switch (val) {
|
||||
case ACL_SCOPE_FILE_OBJECT:
|
||||
case ACL_SCOPE_FILE_SYSTEM:
|
||||
case ACL_SCOPE_SERVER:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
*ptr = val;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
xdrgen_decode_posixacetag4(struct xdr_stream *xdr, posixacetag4 *ptr)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
if (xdr_stream_decode_u32(xdr, &val) < 0)
|
||||
return false;
|
||||
/* Compiler may optimize to a range check for dense enums */
|
||||
switch (val) {
|
||||
case POSIXACE4_TAG_USER_OBJ:
|
||||
case POSIXACE4_TAG_USER:
|
||||
case POSIXACE4_TAG_GROUP_OBJ:
|
||||
case POSIXACE4_TAG_GROUP:
|
||||
case POSIXACE4_TAG_MASK:
|
||||
case POSIXACE4_TAG_OTHER:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
*ptr = val;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
xdrgen_decode_posixaceperm4(struct xdr_stream *xdr, posixaceperm4 *ptr)
|
||||
{
|
||||
return xdrgen_decode_uint32_t(xdr, ptr);
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_decode_posixace4(struct xdr_stream *xdr, struct posixace4 *ptr)
|
||||
{
|
||||
if (!xdrgen_decode_posixacetag4(xdr, &ptr->tag))
|
||||
return false;
|
||||
if (!xdrgen_decode_posixaceperm4(xdr, &ptr->perm))
|
||||
return false;
|
||||
if (!xdrgen_decode_utf8str_mixed(xdr, &ptr->who))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_decode_fattr4_acl_trueform(struct xdr_stream *xdr, fattr4_acl_trueform *ptr)
|
||||
{
|
||||
return xdrgen_decode_aclmodel4(xdr, ptr);
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_decode_fattr4_acl_trueform_scope(struct xdr_stream *xdr, fattr4_acl_trueform_scope *ptr)
|
||||
{
|
||||
return xdrgen_decode_aclscope4(xdr, ptr);
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_decode_fattr4_posix_default_acl(struct xdr_stream *xdr, fattr4_posix_default_acl *ptr)
|
||||
{
|
||||
if (xdr_stream_decode_u32(xdr, &ptr->count) < 0)
|
||||
return false;
|
||||
for (u32 i = 0; i < ptr->count; i++)
|
||||
if (!xdrgen_decode_posixace4(xdr, &ptr->element[i]))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_decode_fattr4_posix_access_acl(struct xdr_stream *xdr, fattr4_posix_access_acl *ptr)
|
||||
{
|
||||
if (xdr_stream_decode_u32(xdr, &ptr->count) < 0)
|
||||
return false;
|
||||
for (u32 i = 0; i < ptr->count; i++)
|
||||
if (!xdrgen_decode_posixace4(xdr, &ptr->element[i]))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* New for POSIX ACL extension
|
||||
*/
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_encode_int64_t(struct xdr_stream *xdr, const int64_t value)
|
||||
{
|
||||
return xdrgen_encode_hyper(xdr, value);
|
||||
};
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_encode_uint32_t(struct xdr_stream *xdr, const uint32_t value)
|
||||
{
|
||||
return xdrgen_encode_unsigned_int(xdr, value);
|
||||
};
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_encode_bitmap4(struct xdr_stream *xdr, const bitmap4 value)
|
||||
@@ -167,7 +386,31 @@ xdrgen_encode_bitmap4(struct xdr_stream *xdr, const bitmap4 value)
|
||||
if (!xdrgen_encode_uint32_t(xdr, value.element[i]))
|
||||
return false;
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_encode_utf8string(struct xdr_stream *xdr, const utf8string value)
|
||||
{
|
||||
return xdr_stream_encode_opaque(xdr, value.data, value.len) >= 0;
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_encode_utf8str_cis(struct xdr_stream *xdr, const utf8str_cis value)
|
||||
{
|
||||
return xdrgen_encode_utf8string(xdr, value);
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_encode_utf8str_cs(struct xdr_stream *xdr, const utf8str_cs value)
|
||||
{
|
||||
return xdrgen_encode_utf8string(xdr, value);
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_encode_utf8str_mixed(struct xdr_stream *xdr, const utf8str_mixed value)
|
||||
{
|
||||
return xdrgen_encode_utf8string(xdr, value);
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_encode_nfstime4(struct xdr_stream *xdr, const struct nfstime4 *value)
|
||||
@@ -177,13 +420,13 @@ xdrgen_encode_nfstime4(struct xdr_stream *xdr, const struct nfstime4 *value)
|
||||
if (!xdrgen_encode_uint32_t(xdr, value->nseconds))
|
||||
return false;
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_encode_fattr4_offline(struct xdr_stream *xdr, const fattr4_offline value)
|
||||
{
|
||||
return xdrgen_encode_bool(xdr, value);
|
||||
};
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_encode_open_arguments4(struct xdr_stream *xdr, const struct open_arguments4 *value)
|
||||
@@ -199,7 +442,7 @@ xdrgen_encode_open_arguments4(struct xdr_stream *xdr, const struct open_argument
|
||||
if (!xdrgen_encode_bitmap4(xdr, value->oa_create_mode))
|
||||
return false;
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_encode_open_args_share_access4(struct xdr_stream *xdr, open_args_share_access4 value)
|
||||
@@ -235,22 +478,92 @@ bool
|
||||
xdrgen_encode_fattr4_open_arguments(struct xdr_stream *xdr, const fattr4_open_arguments *value)
|
||||
{
|
||||
return xdrgen_encode_open_arguments4(xdr, value);
|
||||
};
|
||||
}
|
||||
|
||||
bool
|
||||
xdrgen_encode_fattr4_time_deleg_access(struct xdr_stream *xdr, const fattr4_time_deleg_access *value)
|
||||
{
|
||||
return xdrgen_encode_nfstime4(xdr, value);
|
||||
};
|
||||
}
|
||||
|
||||
bool
|
||||
xdrgen_encode_fattr4_time_deleg_modify(struct xdr_stream *xdr, const fattr4_time_deleg_modify *value)
|
||||
{
|
||||
return xdrgen_encode_nfstime4(xdr, value);
|
||||
};
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_encode_open_delegation_type4(struct xdr_stream *xdr, open_delegation_type4 value)
|
||||
{
|
||||
return xdr_stream_encode_u32(xdr, value) == XDR_UNIT;
|
||||
}
|
||||
|
||||
bool
|
||||
xdrgen_encode_aclmodel4(struct xdr_stream *xdr, aclmodel4 value)
|
||||
{
|
||||
return xdr_stream_encode_u32(xdr, value) == XDR_UNIT;
|
||||
}
|
||||
|
||||
bool
|
||||
xdrgen_encode_aclscope4(struct xdr_stream *xdr, aclscope4 value)
|
||||
{
|
||||
return xdr_stream_encode_u32(xdr, value) == XDR_UNIT;
|
||||
}
|
||||
|
||||
bool
|
||||
xdrgen_encode_posixacetag4(struct xdr_stream *xdr, posixacetag4 value)
|
||||
{
|
||||
return xdr_stream_encode_u32(xdr, value) == XDR_UNIT;
|
||||
}
|
||||
|
||||
bool
|
||||
xdrgen_encode_posixaceperm4(struct xdr_stream *xdr, const posixaceperm4 value)
|
||||
{
|
||||
return xdrgen_encode_uint32_t(xdr, value);
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_encode_posixace4(struct xdr_stream *xdr, const struct posixace4 *value)
|
||||
{
|
||||
if (!xdrgen_encode_posixacetag4(xdr, value->tag))
|
||||
return false;
|
||||
if (!xdrgen_encode_posixaceperm4(xdr, value->perm))
|
||||
return false;
|
||||
if (!xdrgen_encode_utf8str_mixed(xdr, value->who))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_encode_fattr4_acl_trueform(struct xdr_stream *xdr, const fattr4_acl_trueform value)
|
||||
{
|
||||
return xdrgen_encode_aclmodel4(xdr, value);
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_encode_fattr4_acl_trueform_scope(struct xdr_stream *xdr, const fattr4_acl_trueform_scope value)
|
||||
{
|
||||
return xdrgen_encode_aclscope4(xdr, value);
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_encode_fattr4_posix_default_acl(struct xdr_stream *xdr, const fattr4_posix_default_acl value)
|
||||
{
|
||||
if (xdr_stream_encode_u32(xdr, value.count) != XDR_UNIT)
|
||||
return false;
|
||||
for (u32 i = 0; i < value.count; i++)
|
||||
if (!xdrgen_encode_posixace4(xdr, &value.element[i]))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_encode_fattr4_posix_access_acl(struct xdr_stream *xdr, const fattr4_posix_access_acl value)
|
||||
{
|
||||
if (xdr_stream_encode_u32(xdr, value.count) != XDR_UNIT)
|
||||
return false;
|
||||
for (u32 i = 0; i < value.count; i++)
|
||||
if (!xdrgen_encode_posixace4(xdr, &value.element[i]))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
+11
-1
@@ -1,7 +1,7 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Generated by xdrgen. Manual edits will be lost. */
|
||||
/* XDR specification file: ../../Documentation/sunrpc/xdr/nfs4_1.x */
|
||||
/* XDR specification modification time: Mon Oct 14 09:10:13 2024 */
|
||||
/* XDR specification modification time: Thu Jan 8 23:12:07 2026 */
|
||||
|
||||
#ifndef _LINUX_XDRGEN_NFS4_1_DECL_H
|
||||
#define _LINUX_XDRGEN_NFS4_1_DECL_H
|
||||
@@ -21,5 +21,15 @@ bool xdrgen_encode_fattr4_time_deleg_access(struct xdr_stream *xdr, const fattr4
|
||||
|
||||
bool xdrgen_decode_fattr4_time_deleg_modify(struct xdr_stream *xdr, fattr4_time_deleg_modify *ptr);
|
||||
bool xdrgen_encode_fattr4_time_deleg_modify(struct xdr_stream *xdr, const fattr4_time_deleg_modify *value);
|
||||
bool xdrgen_decode_aclmodel4(struct xdr_stream *xdr, aclmodel4 *ptr);
|
||||
bool xdrgen_encode_aclmodel4(struct xdr_stream *xdr, aclmodel4 value);
|
||||
bool xdrgen_decode_aclscope4(struct xdr_stream *xdr, aclscope4 *ptr);
|
||||
bool xdrgen_encode_aclscope4(struct xdr_stream *xdr, aclscope4 value);
|
||||
bool xdrgen_decode_posixacetag4(struct xdr_stream *xdr, posixacetag4 *ptr);
|
||||
bool xdrgen_encode_posixacetag4(struct xdr_stream *xdr, posixacetag4 value);
|
||||
|
||||
bool xdrgen_decode_posixaceperm4(struct xdr_stream *xdr, posixaceperm4 *ptr);
|
||||
bool xdrgen_encode_posixaceperm4(struct xdr_stream *xdr, const posixaceperm4 value);
|
||||
|
||||
|
||||
#endif /* _LINUX_XDRGEN_NFS4_1_DECL_H */
|
||||
|
||||
@@ -285,6 +285,7 @@ static ssize_t write_unlock_fs(struct file *file, char *buf, size_t size)
|
||||
* 2. Is that directory a mount point, or
|
||||
* 3. Is that directory the root of an exported file system?
|
||||
*/
|
||||
nfsd4_cancel_copy_by_sb(netns(file), path.dentry->d_sb);
|
||||
error = nlmsvc_unlock_all_by_sb(path.dentry->d_sb);
|
||||
mutex_lock(&nfsd_mutex);
|
||||
nn = net_generic(netns(file), nfsd_net_id);
|
||||
@@ -1642,6 +1643,10 @@ int nfsd_nl_threads_set_doit(struct sk_buff *skb, struct genl_info *info)
|
||||
scope = nla_data(attr);
|
||||
}
|
||||
|
||||
attr = info->attrs[NFSD_A_SERVER_MIN_THREADS];
|
||||
if (attr)
|
||||
nn->min_threads = nla_get_u32(attr);
|
||||
|
||||
ret = nfsd_svc(nrpools, nthreads, net, get_current_cred(), scope);
|
||||
if (ret > 0)
|
||||
ret = 0;
|
||||
@@ -1681,6 +1686,8 @@ int nfsd_nl_threads_get_doit(struct sk_buff *skb, struct genl_info *info)
|
||||
nn->nfsd4_grace) ||
|
||||
nla_put_u32(skb, NFSD_A_SERVER_LEASETIME,
|
||||
nn->nfsd4_lease) ||
|
||||
nla_put_u32(skb, NFSD_A_SERVER_MIN_THREADS,
|
||||
nn->min_threads) ||
|
||||
nla_put_string(skb, NFSD_A_SERVER_SCOPE,
|
||||
nn->nfsd_name);
|
||||
if (err)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user