mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
Merge branch 'nfsd-next' of https://git.kernel.org/pub/scm/linux/kernel/git/cel/linux
This commit is contained in:
@@ -45,19 +45,162 @@ pragma header nfs4;
|
||||
/*
|
||||
* Basic typedefs for RFC 1832 data type definitions
|
||||
*/
|
||||
typedef hyper int64_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef int int32_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef hyper int64_t;
|
||||
typedef unsigned hyper uint64_t;
|
||||
|
||||
const NFS4_VERIFIER_SIZE = 8;
|
||||
const NFS4_FHSIZE = 128;
|
||||
|
||||
enum nfsstat4 {
|
||||
NFS4_OK = 0, /* everything is okay */
|
||||
NFS4ERR_PERM = 1, /* caller not privileged */
|
||||
NFS4ERR_NOENT = 2, /* no such file/directory */
|
||||
NFS4ERR_IO = 5, /* hard I/O error */
|
||||
NFS4ERR_NXIO = 6, /* no such device */
|
||||
NFS4ERR_ACCESS = 13, /* access denied */
|
||||
NFS4ERR_EXIST = 17, /* file already exists */
|
||||
NFS4ERR_XDEV = 18, /* different filesystems */
|
||||
|
||||
/*
|
||||
* Please do not allocate value 19; it was used in NFSv3
|
||||
* and we do not want a value in NFSv3 to have a different
|
||||
* meaning in NFSv4.x.
|
||||
*/
|
||||
|
||||
NFS4ERR_NOTDIR = 20, /* should be a directory */
|
||||
NFS4ERR_ISDIR = 21, /* should not be directory */
|
||||
NFS4ERR_INVAL = 22, /* invalid argument */
|
||||
NFS4ERR_FBIG = 27, /* file exceeds server max */
|
||||
NFS4ERR_NOSPC = 28, /* no space on filesystem */
|
||||
NFS4ERR_ROFS = 30, /* read-only filesystem */
|
||||
NFS4ERR_MLINK = 31, /* too many hard links */
|
||||
NFS4ERR_NAMETOOLONG = 63, /* name exceeds server max */
|
||||
NFS4ERR_NOTEMPTY = 66, /* directory not empty */
|
||||
NFS4ERR_DQUOT = 69, /* hard quota limit reached*/
|
||||
NFS4ERR_STALE = 70, /* file no longer exists */
|
||||
NFS4ERR_BADHANDLE = 10001,/* Illegal filehandle */
|
||||
NFS4ERR_BAD_COOKIE = 10003,/* READDIR cookie is stale */
|
||||
NFS4ERR_NOTSUPP = 10004,/* operation not supported */
|
||||
NFS4ERR_TOOSMALL = 10005,/* response limit exceeded */
|
||||
NFS4ERR_SERVERFAULT = 10006,/* undefined server error */
|
||||
NFS4ERR_BADTYPE = 10007,/* type invalid for CREATE */
|
||||
NFS4ERR_DELAY = 10008,/* file "busy" - retry */
|
||||
NFS4ERR_SAME = 10009,/* nverify says attrs same */
|
||||
NFS4ERR_DENIED = 10010,/* lock unavailable */
|
||||
NFS4ERR_EXPIRED = 10011,/* lock lease expired */
|
||||
NFS4ERR_LOCKED = 10012,/* I/O failed due to lock */
|
||||
NFS4ERR_GRACE = 10013,/* in grace period */
|
||||
NFS4ERR_FHEXPIRED = 10014,/* filehandle expired */
|
||||
NFS4ERR_SHARE_DENIED = 10015,/* share reserve denied */
|
||||
NFS4ERR_WRONGSEC = 10016,/* wrong security flavor */
|
||||
NFS4ERR_CLID_INUSE = 10017,/* clientid in use */
|
||||
|
||||
/* NFS4ERR_RESOURCE is not a valid error in NFSv4.1 */
|
||||
NFS4ERR_RESOURCE = 10018,/* resource exhaustion */
|
||||
|
||||
NFS4ERR_MOVED = 10019,/* filesystem relocated */
|
||||
NFS4ERR_NOFILEHANDLE = 10020,/* current FH is not set */
|
||||
NFS4ERR_MINOR_VERS_MISMATCH= 10021,/* minor vers not supp */
|
||||
NFS4ERR_STALE_CLIENTID = 10022,/* server has rebooted */
|
||||
NFS4ERR_STALE_STATEID = 10023,/* server has rebooted */
|
||||
NFS4ERR_OLD_STATEID = 10024,/* state is out of sync */
|
||||
NFS4ERR_BAD_STATEID = 10025,/* incorrect stateid */
|
||||
NFS4ERR_BAD_SEQID = 10026,/* request is out of seq. */
|
||||
NFS4ERR_NOT_SAME = 10027,/* verify - attrs not same */
|
||||
NFS4ERR_LOCK_RANGE = 10028,/* overlapping lock range */
|
||||
NFS4ERR_SYMLINK = 10029,/* should be file/directory*/
|
||||
NFS4ERR_RESTOREFH = 10030,/* no saved filehandle */
|
||||
NFS4ERR_LEASE_MOVED = 10031,/* some filesystem moved */
|
||||
NFS4ERR_ATTRNOTSUPP = 10032,/* recommended attr not sup*/
|
||||
NFS4ERR_NO_GRACE = 10033,/* reclaim outside of grace*/
|
||||
NFS4ERR_RECLAIM_BAD = 10034,/* reclaim error at server */
|
||||
NFS4ERR_RECLAIM_CONFLICT= 10035,/* conflict on reclaim */
|
||||
NFS4ERR_BADXDR = 10036,/* XDR decode failed */
|
||||
NFS4ERR_LOCKS_HELD = 10037,/* file locks held at CLOSE*/
|
||||
NFS4ERR_OPENMODE = 10038,/* conflict in OPEN and I/O*/
|
||||
NFS4ERR_BADOWNER = 10039,/* owner translation bad */
|
||||
NFS4ERR_BADCHAR = 10040,/* utf-8 char not supported*/
|
||||
NFS4ERR_BADNAME = 10041,/* name not supported */
|
||||
NFS4ERR_BAD_RANGE = 10042,/* lock range not supported*/
|
||||
NFS4ERR_LOCK_NOTSUPP = 10043,/* no atomic up/downgrade */
|
||||
NFS4ERR_OP_ILLEGAL = 10044,/* undefined operation */
|
||||
NFS4ERR_DEADLOCK = 10045,/* file locking deadlock */
|
||||
NFS4ERR_FILE_OPEN = 10046,/* open file blocks op. */
|
||||
NFS4ERR_ADMIN_REVOKED = 10047,/* lockowner state revoked */
|
||||
NFS4ERR_CB_PATH_DOWN = 10048,/* callback path down */
|
||||
|
||||
/* NFSv4.1 errors start here. */
|
||||
|
||||
NFS4ERR_BADIOMODE = 10049,
|
||||
NFS4ERR_BADLAYOUT = 10050,
|
||||
NFS4ERR_BAD_SESSION_DIGEST = 10051,
|
||||
NFS4ERR_BADSESSION = 10052,
|
||||
NFS4ERR_BADSLOT = 10053,
|
||||
NFS4ERR_COMPLETE_ALREADY = 10054,
|
||||
NFS4ERR_CONN_NOT_BOUND_TO_SESSION = 10055,
|
||||
NFS4ERR_DELEG_ALREADY_WANTED = 10056,
|
||||
NFS4ERR_BACK_CHAN_BUSY = 10057,/*backchan reqs outstanding*/
|
||||
NFS4ERR_LAYOUTTRYLATER = 10058,
|
||||
NFS4ERR_LAYOUTUNAVAILABLE = 10059,
|
||||
NFS4ERR_NOMATCHING_LAYOUT = 10060,
|
||||
NFS4ERR_RECALLCONFLICT = 10061,
|
||||
NFS4ERR_UNKNOWN_LAYOUTTYPE = 10062,
|
||||
NFS4ERR_SEQ_MISORDERED = 10063,/* unexpected seq.ID in req*/
|
||||
NFS4ERR_SEQUENCE_POS = 10064,/* [CB_]SEQ. op not 1st op */
|
||||
NFS4ERR_REQ_TOO_BIG = 10065,/* request too big */
|
||||
NFS4ERR_REP_TOO_BIG = 10066,/* reply too big */
|
||||
NFS4ERR_REP_TOO_BIG_TO_CACHE =10067,/* rep. not all cached*/
|
||||
NFS4ERR_RETRY_UNCACHED_REP =10068,/* retry & rep. uncached*/
|
||||
NFS4ERR_UNSAFE_COMPOUND =10069,/* retry/recovery too hard */
|
||||
NFS4ERR_TOO_MANY_OPS = 10070,/*too many ops in [CB_]COMP*/
|
||||
NFS4ERR_OP_NOT_IN_SESSION =10071,/* op needs [CB_]SEQ. op */
|
||||
NFS4ERR_HASH_ALG_UNSUPP = 10072, /* hash alg. not supp. */
|
||||
/* Error 10073 is unused. */
|
||||
NFS4ERR_CLIENTID_BUSY = 10074,/* clientid has state */
|
||||
NFS4ERR_PNFS_IO_HOLE = 10075,/* IO to _SPARSE file hole */
|
||||
NFS4ERR_SEQ_FALSE_RETRY= 10076,/* Retry != original req. */
|
||||
NFS4ERR_BAD_HIGH_SLOT = 10077,/* req has bad highest_slot*/
|
||||
NFS4ERR_DEADSESSION = 10078,/*new req sent to dead sess*/
|
||||
NFS4ERR_ENCR_ALG_UNSUPP= 10079,/* encr alg. not supp. */
|
||||
NFS4ERR_PNFS_NO_LAYOUT = 10080,/* I/O without a layout */
|
||||
NFS4ERR_NOT_ONLY_OP = 10081,/* addl ops not allowed */
|
||||
NFS4ERR_WRONG_CRED = 10082,/* op done by wrong cred */
|
||||
NFS4ERR_WRONG_TYPE = 10083,/* op on wrong type object */
|
||||
NFS4ERR_DIRDELEG_UNAVAIL=10084,/* delegation not avail. */
|
||||
NFS4ERR_REJECT_DELEG = 10085,/* cb rejected delegation */
|
||||
NFS4ERR_RETURNCONFLICT = 10086,/* layout get before return*/
|
||||
NFS4ERR_DELEG_REVOKED = 10087, /* deleg./layout revoked */
|
||||
NFS4ERR_PARTNER_NOTSUPP = 10088,
|
||||
NFS4ERR_PARTNER_NO_AUTH = 10089,
|
||||
NFS4ERR_UNION_NOTSUPP = 10090,
|
||||
NFS4ERR_OFFLOAD_DENIED = 10091,
|
||||
NFS4ERR_WRONG_LFS = 10092,
|
||||
NFS4ERR_BADLABEL = 10093,
|
||||
NFS4ERR_OFFLOAD_NO_REQS = 10094,
|
||||
NFS4ERR_NOXATTR = 10095,
|
||||
NFS4ERR_XATTR2BIG = 10096
|
||||
};
|
||||
|
||||
/*
|
||||
* Basic data types
|
||||
*/
|
||||
typedef opaque attrlist4<>;
|
||||
typedef uint32_t bitmap4<>;
|
||||
typedef opaque verifier4[NFS4_VERIFIER_SIZE];
|
||||
typedef uint64_t nfs_cookie4;
|
||||
typedef opaque nfs_fh4<NFS4_FHSIZE>;
|
||||
|
||||
typedef opaque utf8string<>;
|
||||
typedef utf8string utf8str_cis;
|
||||
typedef utf8string utf8str_cs;
|
||||
typedef utf8string utf8str_mixed;
|
||||
|
||||
typedef utf8str_cs component4;
|
||||
typedef utf8str_cs linktext4;
|
||||
typedef component4 pathname4<>;
|
||||
|
||||
/*
|
||||
* Timeval
|
||||
*/
|
||||
@@ -66,6 +209,21 @@ struct nfstime4 {
|
||||
uint32_t nseconds;
|
||||
};
|
||||
|
||||
/*
|
||||
* File attribute container
|
||||
*/
|
||||
struct fattr4 {
|
||||
bitmap4 attrmask;
|
||||
attrlist4 attr_vals;
|
||||
};
|
||||
|
||||
/*
|
||||
* Stateid
|
||||
*/
|
||||
struct stateid4 {
|
||||
uint32_t seqid;
|
||||
opaque other[12];
|
||||
};
|
||||
|
||||
/*
|
||||
* The following content was extracted from draft-ietf-nfsv4-delstid
|
||||
@@ -245,3 +403,99 @@ const FATTR4_ACL_TRUEFORM = 89;
|
||||
const FATTR4_ACL_TRUEFORM_SCOPE = 90;
|
||||
const FATTR4_POSIX_DEFAULT_ACL = 91;
|
||||
const FATTR4_POSIX_ACCESS_ACL = 92;
|
||||
|
||||
/*
|
||||
* Directory notification types.
|
||||
*/
|
||||
enum notify_type4 {
|
||||
NOTIFY4_CHANGE_CHILD_ATTRS = 0,
|
||||
NOTIFY4_CHANGE_DIR_ATTRS = 1,
|
||||
NOTIFY4_REMOVE_ENTRY = 2,
|
||||
NOTIFY4_ADD_ENTRY = 3,
|
||||
NOTIFY4_RENAME_ENTRY = 4,
|
||||
NOTIFY4_CHANGE_COOKIE_VERIFIER = 5,
|
||||
/* Proposed in RFC8881bis */
|
||||
NOTIFY4_GFLAG_EXTEND = 6,
|
||||
NOTIFY4_AUFLAG_VALID = 7,
|
||||
NOTIFY4_AUFLAG_USER = 8,
|
||||
NOTIFY4_AUFLAG_GROUP = 9,
|
||||
NOTIFY4_AUFLAG_OTHER = 10,
|
||||
NOTIFY4_CHANGE_AUTH = 11,
|
||||
NOTIFY4_CFLAG_ORDER = 12,
|
||||
NOTIFY4_AUFLAG_GANOW = 13,
|
||||
NOTIFY4_AUFLAG_GALATER = 14,
|
||||
NOTIFY4_CHANGE_GA = 15,
|
||||
NOTIFY4_CHANGE_AMASK = 16
|
||||
};
|
||||
|
||||
/* Changed entry information. */
|
||||
struct notify_entry4 {
|
||||
component4 ne_file;
|
||||
fattr4 ne_attrs;
|
||||
};
|
||||
|
||||
/* Previous entry information */
|
||||
struct prev_entry4 {
|
||||
notify_entry4 pe_prev_entry;
|
||||
/* what READDIR returned for this entry */
|
||||
nfs_cookie4 pe_prev_entry_cookie;
|
||||
};
|
||||
|
||||
struct notify_remove4 {
|
||||
notify_entry4 nrm_old_entry;
|
||||
nfs_cookie4 nrm_old_entry_cookie;
|
||||
};
|
||||
pragma public notify_remove4;
|
||||
|
||||
struct notify_add4 {
|
||||
/*
|
||||
* Information on object
|
||||
* possibly renamed over.
|
||||
*/
|
||||
notify_remove4 nad_old_entry<1>;
|
||||
notify_entry4 nad_new_entry;
|
||||
/* what READDIR would have returned for this entry */
|
||||
nfs_cookie4 nad_new_entry_cookie<1>;
|
||||
prev_entry4 nad_prev_entry<1>;
|
||||
bool nad_last_entry;
|
||||
};
|
||||
pragma public notify_add4;
|
||||
|
||||
struct notify_attr4 {
|
||||
notify_entry4 na_changed_entry;
|
||||
};
|
||||
pragma public notify_attr4;
|
||||
|
||||
struct notify_rename4 {
|
||||
notify_remove4 nrn_old_entry;
|
||||
notify_add4 nrn_new_entry;
|
||||
};
|
||||
pragma public notify_rename4;
|
||||
|
||||
struct notify_verifier4 {
|
||||
verifier4 nv_old_cookieverf;
|
||||
verifier4 nv_new_cookieverf;
|
||||
};
|
||||
|
||||
/*
|
||||
* Objects of type notify_<>4 and
|
||||
* notify_device_<>4 are encoded in this.
|
||||
*/
|
||||
typedef opaque notifylist4<>;
|
||||
|
||||
struct notify4 {
|
||||
/* composed from notify_type4 or notify_deviceid_type4 */
|
||||
bitmap4 notify_mask;
|
||||
notifylist4 notify_vals;
|
||||
};
|
||||
|
||||
struct CB_NOTIFY4args {
|
||||
stateid4 cna_stateid;
|
||||
nfs_fh4 cna_fh;
|
||||
notify4 cna_changes<>;
|
||||
};
|
||||
pragma public CB_NOTIFY4args;
|
||||
|
||||
struct CB_NOTIFY4res {
|
||||
nfsstat4 cnr_status;
|
||||
};
|
||||
|
||||
+1
-1
@@ -314,7 +314,7 @@ void nsm_release(struct nsm_handle *nsm);
|
||||
* This is used in garbage collection and resource reclaim
|
||||
* A return value != 0 means destroy the lock/block/share
|
||||
*/
|
||||
typedef int (*nlm_host_match_fn_t)(void *cur, struct nlm_host *ref);
|
||||
typedef int (*nlm_host_match_fn_t)(void *owner, struct nlm_host *ref);
|
||||
|
||||
/*
|
||||
* Server-side lock handling
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Generated by xdrgen. Manual edits will be lost.
|
||||
// XDR specification file: ../../Documentation/sunrpc/xdr/nlm3.x
|
||||
// XDR specification modification time: Thu Apr 23 10:56:34 2026
|
||||
// XDR specification modification time: Mon Jun 29 20:39:34 2026
|
||||
|
||||
#include <linux/sunrpc/svc.h>
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Generated by xdrgen. Manual edits will be lost. */
|
||||
/* XDR specification file: ../../Documentation/sunrpc/xdr/nlm3.x */
|
||||
/* XDR specification modification time: Thu Apr 23 10:56:34 2026 */
|
||||
/* XDR specification modification time: Mon Jun 29 20:39:34 2026 */
|
||||
|
||||
#ifndef _LINUX_XDRGEN_NLM3_DECL_H
|
||||
#define _LINUX_XDRGEN_NLM3_DECL_H
|
||||
|
||||
+45
-2
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Generated by xdrgen. Manual edits will be lost.
|
||||
// XDR specification file: ../../Documentation/sunrpc/xdr/nlm4.x
|
||||
// XDR specification modification time: Thu Dec 25 13:10:19 2025
|
||||
// XDR specification modification time: Mon Jun 29 20:39:36 2026
|
||||
|
||||
#include <linux/sunrpc/svc.h>
|
||||
|
||||
@@ -20,6 +20,16 @@ xdrgen_decode_fsh4_mode(struct xdr_stream *xdr, fsh4_mode *ptr)
|
||||
|
||||
if (xdr_stream_decode_u32(xdr, &val) < 0)
|
||||
return false;
|
||||
/* Compiler may optimize to a range check for dense enums */
|
||||
switch (val) {
|
||||
case fsm_DN:
|
||||
case fsm_DR:
|
||||
case fsm_DW:
|
||||
case fsm_DRW:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
*ptr = val;
|
||||
return true;
|
||||
}
|
||||
@@ -31,6 +41,16 @@ xdrgen_decode_fsh4_access(struct xdr_stream *xdr, fsh4_access *ptr)
|
||||
|
||||
if (xdr_stream_decode_u32(xdr, &val) < 0)
|
||||
return false;
|
||||
/* Compiler may optimize to a range check for dense enums */
|
||||
switch (val) {
|
||||
case fsa_NONE:
|
||||
case fsa_R:
|
||||
case fsa_W:
|
||||
case fsa_RW:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
*ptr = val;
|
||||
return true;
|
||||
}
|
||||
@@ -62,7 +82,30 @@ xdrgen_decode_int32(struct xdr_stream *xdr, int32 *ptr)
|
||||
static bool __maybe_unused
|
||||
xdrgen_decode_nlm4_stats(struct xdr_stream *xdr, nlm4_stats *ptr)
|
||||
{
|
||||
return xdr_stream_decode_be32(xdr, ptr) == 0;
|
||||
__be32 raw;
|
||||
u32 val;
|
||||
|
||||
if (xdr_stream_decode_be32(xdr, &raw) < 0)
|
||||
return false;
|
||||
val = be32_to_cpu(raw);
|
||||
/* Compiler may optimize to a range check for dense enums */
|
||||
switch (val) {
|
||||
case NLM4_GRANTED:
|
||||
case NLM4_DENIED:
|
||||
case NLM4_DENIED_NOLOCKS:
|
||||
case NLM4_BLOCKED:
|
||||
case NLM4_DENIED_GRACE_PERIOD:
|
||||
case NLM4_DEADLCK:
|
||||
case NLM4_ROFS:
|
||||
case NLM4_STALE_FH:
|
||||
case NLM4_FBIG:
|
||||
case NLM4_FAILED:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
*ptr = raw;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Generated by xdrgen. Manual edits will be lost. */
|
||||
/* XDR specification file: ../../Documentation/sunrpc/xdr/nlm4.x */
|
||||
/* XDR specification modification time: Thu Dec 25 13:10:19 2025 */
|
||||
/* XDR specification modification time: Mon Jun 29 20:39:36 2026 */
|
||||
|
||||
#ifndef _LINUX_XDRGEN_NLM4_DECL_H
|
||||
#define _LINUX_XDRGEN_NLM4_DECL_H
|
||||
|
||||
+7
-1
@@ -8,9 +8,14 @@
|
||||
#ifndef _LOCKD_SHARE_H
|
||||
#define _LOCKD_SHARE_H
|
||||
|
||||
#include <linux/bits.h>
|
||||
|
||||
/* Synthetic svid for lockowner lookup during share operations */
|
||||
#define LOCKD_SHARE_SVID (~(u32)0)
|
||||
|
||||
/* One bit per (access, deny) pair; index = (access << 2) | deny */
|
||||
#define LOCKD_FSH_BIT(a, d) BIT(((a) << 2) | (d))
|
||||
|
||||
/*
|
||||
* DOS share for a specific file
|
||||
*/
|
||||
@@ -21,12 +26,13 @@ struct lockd_share {
|
||||
struct xdr_netobj s_owner; /* owner handle */
|
||||
u32 s_access; /* access mode */
|
||||
u32 s_mode; /* deny mode */
|
||||
u16 s_access_deny_bmap; /* held (access, deny) pairs */
|
||||
};
|
||||
|
||||
__be32 nlmsvc_share_file(struct nlm_host *host, struct nlm_file *file,
|
||||
struct xdr_netobj *oh, u32 access, u32 mode);
|
||||
__be32 nlmsvc_unshare_file(struct nlm_host *host, struct nlm_file *file,
|
||||
struct xdr_netobj *oh);
|
||||
struct xdr_netobj *oh, u32 access, u32 mode);
|
||||
void nlmsvc_traverse_shares(struct nlm_host *, struct nlm_file *,
|
||||
nlm_host_match_fn_t);
|
||||
|
||||
|
||||
+2
-2
@@ -47,7 +47,7 @@
|
||||
|
||||
static struct svc_program nlmsvc_program;
|
||||
|
||||
const struct nlmsvc_binding *nlmsvc_ops;
|
||||
const struct nlmsvc_binding __rcu *nlmsvc_ops;
|
||||
EXPORT_SYMBOL_GPL(nlmsvc_ops);
|
||||
|
||||
static DEFINE_MUTEX(nlmsvc_mutex);
|
||||
@@ -142,7 +142,7 @@ lockd(void *vrqstp)
|
||||
nlmsvc_retry_blocked(rqstp);
|
||||
svc_recv(rqstp, 0);
|
||||
}
|
||||
if (nlmsvc_ops)
|
||||
if (rcu_access_pointer(nlmsvc_ops))
|
||||
nlmsvc_invalidate_all();
|
||||
nlm_shutdown_hosts();
|
||||
cancel_delayed_work_sync(&ln->grace_period_end);
|
||||
|
||||
+7
-4
@@ -128,7 +128,7 @@ nlm4svc_lookup_host(struct svc_rqst *rqstp, string caller, bool monitored)
|
||||
{
|
||||
struct nlm_host *host;
|
||||
|
||||
if (!nlmsvc_ops)
|
||||
if (!rcu_access_pointer(nlmsvc_ops))
|
||||
return NULL;
|
||||
host = nlmsvc_lookup_host(rqstp, caller.data, caller.len);
|
||||
if (!host)
|
||||
@@ -872,7 +872,8 @@ static __be32 nlm4svc_proc_granted_msg(struct svc_rqst *rqstp)
|
||||
struct nlm4_testargs_wrapper *argp = rqstp->rq_argp;
|
||||
struct nlm_host *host;
|
||||
|
||||
host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false);
|
||||
host = nlmsvc_lookup_host(rqstp, argp->xdrgen.alock.caller_name.data,
|
||||
argp->xdrgen.alock.caller_name.len);
|
||||
if (!host)
|
||||
return rpc_system_err;
|
||||
|
||||
@@ -894,7 +895,7 @@ static __be32 nlm4svc_proc_granted_res(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nlm4_res_wrapper *argp = rqstp->rq_argp;
|
||||
|
||||
if (!nlmsvc_ops)
|
||||
if (!rcu_access_pointer(nlmsvc_ops))
|
||||
return rpc_success;
|
||||
|
||||
if (nlm4_netobj_to_cookie(&argp->cookie, &argp->xdrgen.cookie))
|
||||
@@ -1078,7 +1079,9 @@ static __be32 nlm4svc_proc_unshare(struct svc_rqst *rqstp)
|
||||
if (resp->xdrgen.stat)
|
||||
goto out;
|
||||
|
||||
resp->xdrgen.stat = nlmsvc_unshare_file(host, file, &lock->oh);
|
||||
resp->xdrgen.stat = nlmsvc_unshare_file(host, file, &lock->oh,
|
||||
argp->xdrgen.share.access,
|
||||
argp->xdrgen.share.mode);
|
||||
|
||||
nlmsvc_release_lockowner(lock);
|
||||
|
||||
|
||||
+5
-37
@@ -47,40 +47,6 @@ static const struct rpc_call_ops nlmsvc_grant_ops;
|
||||
static LIST_HEAD(nlm_blocked);
|
||||
static DEFINE_SPINLOCK(nlm_blocked_lock);
|
||||
|
||||
#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
|
||||
static const char *nlmdbg_cookie2a(const struct lockd_cookie *cookie)
|
||||
{
|
||||
/*
|
||||
* We can get away with a static buffer because this is only called
|
||||
* from lockd, which is single-threaded.
|
||||
*/
|
||||
static char buf[2*NLM_MAXCOOKIELEN+1];
|
||||
unsigned int i, len = sizeof(buf);
|
||||
char *p = buf;
|
||||
|
||||
len--; /* allow for trailing \0 */
|
||||
if (len < 3)
|
||||
return "???";
|
||||
for (i = 0 ; i < cookie->len ; i++) {
|
||||
if (len < 2) {
|
||||
strcpy(p-3, "...");
|
||||
break;
|
||||
}
|
||||
sprintf(p, "%02x", cookie->data[i]);
|
||||
p += 2;
|
||||
len -= 2;
|
||||
}
|
||||
*p = '\0';
|
||||
|
||||
return buf;
|
||||
}
|
||||
#else
|
||||
static inline const char *nlmdbg_cookie2a(const struct lockd_cookie *cookie)
|
||||
{
|
||||
return "???";
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Insert a blocked lock into the global list
|
||||
*/
|
||||
@@ -155,11 +121,12 @@ nlmsvc_lookup_block(struct nlm_file *file, struct lockd_lock *lock)
|
||||
spin_lock(&nlm_blocked_lock);
|
||||
list_for_each_entry(block, &nlm_blocked, b_list) {
|
||||
fl = &block->b_call->a_args.lock.fl;
|
||||
dprintk("lockd: check f=%p pd=%d %Ld-%Ld ty=%d cookie=%s\n",
|
||||
dprintk("lockd: check f=%p pd=%d %Ld-%Ld ty=%d cookie=%*phN\n",
|
||||
block->b_file, fl->c.flc_pid,
|
||||
(long long)fl->fl_start,
|
||||
(long long)fl->fl_end, fl->c.flc_type,
|
||||
nlmdbg_cookie2a(&block->b_call->a_args.cookie));
|
||||
block->b_call->a_args.cookie.len,
|
||||
block->b_call->a_args.cookie.data);
|
||||
if (block->b_file == file && nlm_compare_locks(fl, &lock->fl)) {
|
||||
kref_get(&block->b_count);
|
||||
spin_unlock(&nlm_blocked_lock);
|
||||
@@ -198,7 +165,8 @@ nlmsvc_find_block(struct lockd_cookie *cookie)
|
||||
return NULL;
|
||||
|
||||
found:
|
||||
dprintk("nlmsvc_find_block(%s): block=%p\n", nlmdbg_cookie2a(cookie), block);
|
||||
dprintk("nlmsvc_find_block(%*phN): block=%p\n",
|
||||
cookie->len, cookie->data, block);
|
||||
kref_get(&block->b_count);
|
||||
spin_unlock(&nlm_blocked_lock);
|
||||
return block;
|
||||
|
||||
+5
-3
@@ -133,7 +133,7 @@ nlm3svc_lookup_host(struct svc_rqst *rqstp, string caller, bool monitored)
|
||||
{
|
||||
struct nlm_host *host;
|
||||
|
||||
if (!nlmsvc_ops)
|
||||
if (!rcu_access_pointer(nlmsvc_ops))
|
||||
return NULL;
|
||||
host = nlmsvc_lookup_host(rqstp, caller.data, caller.len);
|
||||
if (!host)
|
||||
@@ -924,7 +924,7 @@ static __be32 nlmsvc_proc_granted_res(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nlm_res_wrapper *argp = rqstp->rq_argp;
|
||||
|
||||
if (!nlmsvc_ops)
|
||||
if (!rcu_access_pointer(nlmsvc_ops))
|
||||
return rpc_success;
|
||||
|
||||
if (nlm_netobj_to_cookie(&argp->cookie, &argp->xdrgen.cookie))
|
||||
@@ -1098,7 +1098,9 @@ static __be32 nlmsvc_proc_unshare(struct svc_rqst *rqstp)
|
||||
if (resp->xdrgen.stat)
|
||||
goto out;
|
||||
|
||||
resp->xdrgen.stat = nlmsvc_unshare_file(host, file, &lock->oh);
|
||||
resp->xdrgen.stat = nlmsvc_unshare_file(host, file, &lock->oh,
|
||||
argp->xdrgen.share.access,
|
||||
argp->xdrgen.share.mode);
|
||||
|
||||
nlmsvc_release_lockowner(lock);
|
||||
|
||||
|
||||
+31
-5
@@ -25,6 +25,25 @@ nlm_cmp_owner(struct lockd_share *share, struct xdr_netobj *oh)
|
||||
&& !memcmp(share->s_owner.data, oh->data, oh->len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Recompute s_access / s_mode as the union of every (access, deny) pair
|
||||
* whose bit is currently set in s_access_deny_bmap.
|
||||
*/
|
||||
static void nlm_recompute_share(struct lockd_share *share)
|
||||
{
|
||||
u32 new_access = 0, new_mode = 0;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
if (share->s_access_deny_bmap & BIT(i)) {
|
||||
new_access |= i >> 2;
|
||||
new_mode |= i & 3;
|
||||
}
|
||||
}
|
||||
share->s_access = new_access;
|
||||
share->s_mode = new_mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* nlmsvc_share_file - create a share
|
||||
* @host: Network client peer
|
||||
@@ -64,12 +83,13 @@ nlmsvc_share_file(struct nlm_host *host, struct nlm_file *file,
|
||||
share->s_host = host;
|
||||
share->s_owner.data = ohdata;
|
||||
share->s_owner.len = oh->len;
|
||||
share->s_access_deny_bmap = 0;
|
||||
share->s_next = file->f_shares;
|
||||
file->f_shares = share;
|
||||
|
||||
update:
|
||||
share->s_access = access;
|
||||
share->s_mode = mode;
|
||||
share->s_access_deny_bmap |= LOCKD_FSH_BIT(access, mode);
|
||||
nlm_recompute_share(share);
|
||||
return nlm_granted;
|
||||
}
|
||||
|
||||
@@ -78,12 +98,14 @@ update:
|
||||
* @host: Network client peer
|
||||
* @file: File to be unshared
|
||||
* @oh: Share owner handle
|
||||
* @access: Access mode of the SHARE being released
|
||||
* @mode: Deny mode of the SHARE being released
|
||||
*
|
||||
* Returns an NLM status code.
|
||||
*/
|
||||
__be32
|
||||
nlmsvc_unshare_file(struct nlm_host *host, struct nlm_file *file,
|
||||
struct xdr_netobj *oh)
|
||||
struct xdr_netobj *oh, u32 access, u32 mode)
|
||||
{
|
||||
struct lockd_share *share, **shpp;
|
||||
|
||||
@@ -93,8 +115,12 @@ nlmsvc_unshare_file(struct nlm_host *host, struct nlm_file *file,
|
||||
for (shpp = &file->f_shares; (share = *shpp) != NULL;
|
||||
shpp = &share->s_next) {
|
||||
if (share->s_host == host && nlm_cmp_owner(share, oh)) {
|
||||
*shpp = share->s_next;
|
||||
kfree(share);
|
||||
share->s_access_deny_bmap &= ~LOCKD_FSH_BIT(access, mode);
|
||||
nlm_recompute_share(share);
|
||||
if (!share->s_access_deny_bmap) {
|
||||
*shpp = share->s_next;
|
||||
kfree(share);
|
||||
}
|
||||
return nlm_granted;
|
||||
}
|
||||
}
|
||||
|
||||
+76
-31
@@ -90,22 +90,35 @@ int lock_to_openmode(struct file_lock *lock)
|
||||
static __be32 nlm_do_fopen(struct svc_rqst *rqstp,
|
||||
struct nlm_file *file, int mode)
|
||||
{
|
||||
const struct nlmsvc_binding *ops;
|
||||
__be32 nlmerr = nlm__int__failed;
|
||||
__be32 deferred = 0;
|
||||
int error;
|
||||
int m;
|
||||
|
||||
rcu_read_lock();
|
||||
ops = rcu_dereference(nlmsvc_ops);
|
||||
if (!ops || !try_module_get(ops->owner)) {
|
||||
rcu_read_unlock();
|
||||
return nlm__int__failed;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
for (m = O_RDONLY; m <= O_WRONLY; m++) {
|
||||
struct file **fp = &file->f_file[m];
|
||||
|
||||
if (mode != O_RDWR && mode != m)
|
||||
continue;
|
||||
if (*fp)
|
||||
if (*fp) {
|
||||
module_put(ops->owner);
|
||||
return nlm_granted;
|
||||
}
|
||||
|
||||
error = nlmsvc_ops->fopen(rqstp, &file->f_handle, fp, m);
|
||||
if (!error)
|
||||
error = ops->fopen(rqstp, &file->f_handle, fp, m);
|
||||
if (!error) {
|
||||
module_put(ops->owner);
|
||||
return nlm_granted;
|
||||
}
|
||||
|
||||
dprintk("lockd: open failed (errno %d)\n", error);
|
||||
switch (error) {
|
||||
@@ -122,6 +135,7 @@ static __be32 nlm_do_fopen(struct svc_rqst *rqstp,
|
||||
}
|
||||
}
|
||||
|
||||
module_put(ops->owner);
|
||||
return deferred ? deferred : nlmerr;
|
||||
}
|
||||
|
||||
@@ -185,6 +199,33 @@ out_free:
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
/*
|
||||
* Release the struct file references held by a nlm_file.
|
||||
*/
|
||||
static void nlm_release_files(struct nlm_file *file)
|
||||
{
|
||||
const struct nlmsvc_binding *ops;
|
||||
bool have_ops;
|
||||
|
||||
rcu_read_lock();
|
||||
ops = rcu_dereference(nlmsvc_ops);
|
||||
have_ops = ops && try_module_get(ops->owner);
|
||||
rcu_read_unlock();
|
||||
|
||||
if (have_ops) {
|
||||
if (file->f_file[O_RDONLY])
|
||||
ops->fclose(file->f_file[O_RDONLY]);
|
||||
if (file->f_file[O_WRONLY])
|
||||
ops->fclose(file->f_file[O_WRONLY]);
|
||||
module_put(ops->owner);
|
||||
} else {
|
||||
if (file->f_file[O_RDONLY])
|
||||
fput(file->f_file[O_RDONLY]);
|
||||
if (file->f_file[O_WRONLY])
|
||||
fput(file->f_file[O_WRONLY]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete a file after having released all locks, blocks and shares
|
||||
*/
|
||||
@@ -194,10 +235,7 @@ nlm_delete_file(struct nlm_file *file)
|
||||
nlm_debug_print_file("closing file", file);
|
||||
if (!hlist_unhashed(&file->f_list)) {
|
||||
hlist_del(&file->f_list);
|
||||
if (file->f_file[O_RDONLY])
|
||||
nlmsvc_ops->fclose(file->f_file[O_RDONLY]);
|
||||
if (file->f_file[O_WRONLY])
|
||||
nlmsvc_ops->fclose(file->f_file[O_WRONLY]);
|
||||
nlm_release_files(file);
|
||||
kfree(file);
|
||||
} else {
|
||||
printk(KERN_WARNING "lockd: attempt to release unknown file!\n");
|
||||
@@ -312,12 +350,10 @@ nlm_file_inuse(struct nlm_file *file)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void nlm_close_files(struct nlm_file *file)
|
||||
static void nlm_file_release(struct nlm_file *file)
|
||||
{
|
||||
if (file->f_file[O_RDONLY])
|
||||
nlmsvc_ops->fclose(file->f_file[O_RDONLY]);
|
||||
if (file->f_file[O_WRONLY])
|
||||
nlmsvc_ops->fclose(file->f_file[O_WRONLY]);
|
||||
if (!nlm_file_inuse(file))
|
||||
nlm_delete_file(file);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -327,32 +363,41 @@ static int
|
||||
nlm_traverse_files(void *data, nlm_host_match_fn_t match,
|
||||
int (*is_failover_file)(void *data, struct nlm_file *file))
|
||||
{
|
||||
struct hlist_node *next;
|
||||
struct nlm_file *file;
|
||||
struct nlm_file *file, *next;
|
||||
int i, ret = 0;
|
||||
|
||||
mutex_lock(&nlm_file_mutex);
|
||||
for (i = 0; i < FILE_NRHASH; i++) {
|
||||
hlist_for_each_entry_safe(file, next, &nlm_files[i], f_list) {
|
||||
if (is_failover_file && !is_failover_file(data, file))
|
||||
continue;
|
||||
file = hlist_entry_safe(nlm_files[i].first,
|
||||
struct nlm_file, f_list);
|
||||
if (file)
|
||||
file->f_count++;
|
||||
mutex_unlock(&nlm_file_mutex);
|
||||
while (file) {
|
||||
/*
|
||||
* Pin the next neighbour before we drop the mutex
|
||||
* for nlm_inspect_file(); a concurrent
|
||||
* nlm_release_file() under the same mutex would
|
||||
* otherwise be free to unlink and kfree it during
|
||||
* the unlock window, leaving us to dereference a
|
||||
* freed slab when we walked to next afterwards.
|
||||
*/
|
||||
next = hlist_entry_safe(file->f_list.next,
|
||||
struct nlm_file, f_list);
|
||||
if (next)
|
||||
next->f_count++;
|
||||
|
||||
/* Traverse locks, blocks and shares of this file
|
||||
* and update file->f_locks count */
|
||||
if (nlm_inspect_file(data, file, match))
|
||||
ret = 1;
|
||||
if (!is_failover_file || is_failover_file(data, file)) {
|
||||
mutex_unlock(&nlm_file_mutex);
|
||||
|
||||
mutex_lock(&nlm_file_mutex);
|
||||
file->f_count--;
|
||||
/* No more references to this file. Let go of it. */
|
||||
if (list_empty(&file->f_blocks) && !file->f_locks
|
||||
&& !file->f_shares && !file->f_count) {
|
||||
hlist_del(&file->f_list);
|
||||
nlm_close_files(file);
|
||||
kfree(file);
|
||||
if (nlm_inspect_file(data, file, match))
|
||||
ret = 1;
|
||||
|
||||
mutex_lock(&nlm_file_mutex);
|
||||
}
|
||||
|
||||
file->f_count--;
|
||||
nlm_file_release(file);
|
||||
file = next;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&nlm_file_mutex);
|
||||
@@ -512,7 +557,7 @@ EXPORT_SYMBOL_GPL(nlmsvc_unlock_all_by_sb);
|
||||
static int
|
||||
nlmsvc_match_ip(void *datap, struct nlm_host *host)
|
||||
{
|
||||
return rpc_cmp_addr(nlm_srcaddr(host), datap);
|
||||
return rpc_cmp_addr(nlm_srcaddr(datap), (struct sockaddr *)host);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+3
-1
@@ -231,8 +231,9 @@ int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt)
|
||||
cb_info->users++;
|
||||
err_net:
|
||||
if (!cb_info->users) {
|
||||
xprt_svc_shutdown_bc(xprt);
|
||||
svc_set_num_threads(cb_info->serv, 0, 0);
|
||||
svc_destroy(&cb_info->serv);
|
||||
xprt_svc_destroy_nullify_bc(xprt, &cb_info->serv);
|
||||
}
|
||||
err_create:
|
||||
mutex_unlock(&nfs_callback_mutex);
|
||||
@@ -254,6 +255,7 @@ void nfs_callback_down(int minorversion, struct net *net, struct rpc_xprt *xprt)
|
||||
|
||||
mutex_lock(&nfs_callback_mutex);
|
||||
serv = cb_info->serv;
|
||||
xprt_svc_shutdown_bc(xprt);
|
||||
nfs_callback_down_net(minorversion, serv, net);
|
||||
cb_info->users--;
|
||||
if (cb_info->users == 0) {
|
||||
|
||||
@@ -292,8 +292,22 @@ struct nfsd_file *nfs_open_local_fh(nfs_uuid_t *uuid,
|
||||
localio = nfs_to->nfsd_open_local_fh(net, uuid->dom, rpc_clnt, cred,
|
||||
nfs_fh, pnf, fmode);
|
||||
if (!IS_ERR(localio) && nfs_uuid_add_file(uuid, nfl) < 0) {
|
||||
/* Delete the cached file when racing with nfs_uuid_put() */
|
||||
/*
|
||||
* Delete the cached file when racing with nfs_uuid_put().
|
||||
* Since nfl->nfs_uuid was never published via
|
||||
* rcu_assign_pointer(), nfs_close_local_fh() will early-return
|
||||
* and cannot clean up after us. Drop the slot's file ref and
|
||||
* its paired net ref, then drop the caller-owned nfsd_file ref
|
||||
* (+1) and the entry-time nfsd_net ref carried via nf->nf_net,
|
||||
* and return -ENXIO so the caller never dereferences the
|
||||
* now-cleared localio.
|
||||
*/
|
||||
struct nfsd_file __rcu *tmp =
|
||||
(struct nfsd_file __force __rcu *)localio;
|
||||
|
||||
nfs_to_nfsd_file_put_local(pnf);
|
||||
nfs_to_nfsd_file_put_local(&tmp);
|
||||
localio = ERR_PTR(-ENXIO);
|
||||
}
|
||||
nfs_to_nfsd_net_put(net);
|
||||
|
||||
|
||||
+177
-88
@@ -55,6 +55,17 @@
|
||||
/* We only care about NFSD_MAY_READ/WRITE for this cache */
|
||||
#define NFSD_FILE_MAY_MASK (NFSD_MAY_READ|NFSD_MAY_WRITE|NFSD_MAY_LOCALIO)
|
||||
|
||||
/* If the shrinker runs between calls to list_lru_walk_node() in
|
||||
* nfsd_file_gc(), the "remaining" count will be wrong. This could
|
||||
* result in premature freeing of some files. This may not matter much
|
||||
* but is easy to fix with this spinlock which temporarily disables
|
||||
* the shrinker.
|
||||
*
|
||||
* It also serializes callers of nfsd_file_dispose_list_delayed()
|
||||
* against per-net shutdown.
|
||||
*/
|
||||
static DEFINE_SPINLOCK(nfsd_gc_lock);
|
||||
|
||||
static DEFINE_PER_CPU(unsigned long, nfsd_file_cache_hits);
|
||||
static DEFINE_PER_CPU(unsigned long, nfsd_file_acquisitions);
|
||||
static DEFINE_PER_CPU(unsigned long, nfsd_file_allocations);
|
||||
@@ -62,16 +73,12 @@ static DEFINE_PER_CPU(unsigned long, nfsd_file_releases);
|
||||
static DEFINE_PER_CPU(unsigned long, nfsd_file_total_age);
|
||||
static DEFINE_PER_CPU(unsigned long, nfsd_file_evictions);
|
||||
|
||||
struct nfsd_fcache_disposal {
|
||||
spinlock_t lock;
|
||||
struct list_head freeme;
|
||||
};
|
||||
|
||||
static struct kmem_cache *nfsd_file_slab;
|
||||
static struct kmem_cache *nfsd_file_mark_slab;
|
||||
static struct list_lru nfsd_file_lru;
|
||||
static unsigned long nfsd_file_flags;
|
||||
static struct fsnotify_group *nfsd_file_fsnotify_group;
|
||||
static struct fsnotify_group *nfsd_dir_fsnotify_group;
|
||||
static struct delayed_work nfsd_filecache_laundrette;
|
||||
static struct rhltable nfsd_file_rhltable
|
||||
____cacheline_aligned_in_smp;
|
||||
@@ -147,7 +154,7 @@ static void
|
||||
nfsd_file_mark_put(struct nfsd_file_mark *nfm)
|
||||
{
|
||||
if (refcount_dec_and_test(&nfm->nfm_ref)) {
|
||||
fsnotify_destroy_mark(&nfm->nfm_mark, nfsd_file_fsnotify_group);
|
||||
fsnotify_destroy_mark(&nfm->nfm_mark, nfm->nfm_mark.group);
|
||||
fsnotify_put_mark(&nfm->nfm_mark);
|
||||
}
|
||||
}
|
||||
@@ -155,37 +162,40 @@ nfsd_file_mark_put(struct nfsd_file_mark *nfm)
|
||||
static struct nfsd_file_mark *
|
||||
nfsd_file_mark_find_or_create(struct inode *inode)
|
||||
{
|
||||
int err;
|
||||
struct fsnotify_mark *mark;
|
||||
struct nfsd_file_mark *nfm = NULL, *new;
|
||||
struct fsnotify_group *group;
|
||||
struct fsnotify_mark *mark;
|
||||
int err;
|
||||
|
||||
group = S_ISDIR(inode->i_mode) ? nfsd_dir_fsnotify_group : nfsd_file_fsnotify_group;
|
||||
|
||||
do {
|
||||
fsnotify_group_lock(nfsd_file_fsnotify_group);
|
||||
mark = fsnotify_find_inode_mark(inode,
|
||||
nfsd_file_fsnotify_group);
|
||||
fsnotify_group_lock(group);
|
||||
mark = fsnotify_find_inode_mark(inode, group);
|
||||
if (mark) {
|
||||
nfm = nfsd_file_mark_get(container_of(mark,
|
||||
struct nfsd_file_mark,
|
||||
nfm_mark));
|
||||
fsnotify_group_unlock(nfsd_file_fsnotify_group);
|
||||
fsnotify_group_unlock(group);
|
||||
if (nfm) {
|
||||
fsnotify_put_mark(mark);
|
||||
break;
|
||||
}
|
||||
/* Avoid soft lockup race with nfsd_file_mark_put() */
|
||||
fsnotify_destroy_mark(mark, nfsd_file_fsnotify_group);
|
||||
fsnotify_destroy_mark(mark, group);
|
||||
fsnotify_put_mark(mark);
|
||||
} else {
|
||||
fsnotify_group_unlock(nfsd_file_fsnotify_group);
|
||||
fsnotify_group_unlock(group);
|
||||
}
|
||||
|
||||
/* allocate a new nfm */
|
||||
new = kmem_cache_alloc(nfsd_file_mark_slab, GFP_KERNEL);
|
||||
if (!new)
|
||||
return NULL;
|
||||
fsnotify_init_mark(&new->nfm_mark, nfsd_file_fsnotify_group);
|
||||
fsnotify_init_mark(&new->nfm_mark, group);
|
||||
new->nfm_mark.mask = FS_ATTRIB|FS_DELETE_SELF;
|
||||
refcount_set(&new->nfm_ref, 1);
|
||||
mutex_init(&new->nfm_recalc_mutex);
|
||||
|
||||
err = fsnotify_add_inode_mark(&new->nfm_mark, inode, 0);
|
||||
|
||||
@@ -327,8 +337,11 @@ static void nfsd_file_lru_add(struct nfsd_file *nf)
|
||||
refcount_inc(&nf->nf_ref);
|
||||
if (list_lru_add_obj(&nfsd_file_lru, &nf->nf_lru))
|
||||
trace_nfsd_file_lru_add(nf);
|
||||
else
|
||||
WARN_ON(1);
|
||||
else {
|
||||
refcount_dec(&nf->nf_ref);
|
||||
WARN_ON_ONCE(1);
|
||||
return;
|
||||
}
|
||||
nfsd_file_schedule_laundrette();
|
||||
}
|
||||
|
||||
@@ -419,25 +432,31 @@ nfsd_file_dispose_list(struct list_head *dispose)
|
||||
}
|
||||
|
||||
/**
|
||||
* nfsd_file_dispose_list_delayed - move list of dead files to net's freeme list
|
||||
* nfsd_file_dispose_list_delayed - queue dead files for nfsd thread disposal
|
||||
* @dispose: list of nfsd_files to be disposed
|
||||
*
|
||||
* Transfers each file to the "freeme" list for its nfsd_net, to eventually
|
||||
* be disposed of by the per-net garbage collector.
|
||||
* Transfers each file to the dispose list in its nfsd_net and wakes an nfsd
|
||||
* thread to do the actual close. This keeps the cost of fput() in the nfsd
|
||||
* threads rather than in the shrinker or GC worker.
|
||||
*
|
||||
* All callers must hold nfsd_gc_lock, so that nfsd_file_cache_shutdown_net()
|
||||
* can synchronize against them before draining the per-net dispose list.
|
||||
* This guarantees nf_net is still live when we call net_generic().
|
||||
*/
|
||||
static void
|
||||
nfsd_file_dispose_list_delayed(struct list_head *dispose)
|
||||
{
|
||||
while(!list_empty(dispose)) {
|
||||
lockdep_assert_held(&nfsd_gc_lock);
|
||||
|
||||
while (!list_empty(dispose)) {
|
||||
struct nfsd_file *nf = list_first_entry(dispose,
|
||||
struct nfsd_file, nf_gc);
|
||||
struct nfsd_net *nn = net_generic(nf->nf_net, nfsd_net_id);
|
||||
struct nfsd_fcache_disposal *l = nn->fcache_disposal;
|
||||
struct svc_serv *serv;
|
||||
|
||||
spin_lock(&l->lock);
|
||||
list_move_tail(&nf->nf_gc, &l->freeme);
|
||||
spin_unlock(&l->lock);
|
||||
spin_lock(&nn->fcache_dispose_lock);
|
||||
list_move_tail(&nf->nf_gc, &nn->fcache_dispose_list);
|
||||
spin_unlock(&nn->fcache_dispose_lock);
|
||||
|
||||
/*
|
||||
* The filecache laundrette is shut down after the
|
||||
@@ -461,21 +480,28 @@ nfsd_file_dispose_list_delayed(struct list_head *dispose)
|
||||
*/
|
||||
void nfsd_file_net_dispose(struct nfsd_net *nn)
|
||||
{
|
||||
struct nfsd_fcache_disposal *l = nn->fcache_disposal;
|
||||
|
||||
if (!list_empty(&l->freeme)) {
|
||||
if (!list_empty(&nn->fcache_dispose_list)) {
|
||||
LIST_HEAD(dispose);
|
||||
int i;
|
||||
|
||||
spin_lock(&l->lock);
|
||||
for (i = 0; i < 8 && !list_empty(&l->freeme); i++)
|
||||
list_move(l->freeme.next, &dispose);
|
||||
spin_unlock(&l->lock);
|
||||
if (!list_empty(&l->freeme))
|
||||
/* Wake up another thread to share the work
|
||||
spin_lock(&nn->fcache_dispose_lock);
|
||||
for (i = 0; i < 8 && !list_empty(&nn->fcache_dispose_list); i++)
|
||||
list_move(nn->fcache_dispose_list.next, &dispose);
|
||||
spin_unlock(&nn->fcache_dispose_lock);
|
||||
if (!list_empty(&nn->fcache_dispose_list)) {
|
||||
/*
|
||||
* Wake up another thread to share the work
|
||||
* *before* doing any actual disposing.
|
||||
*
|
||||
* The filecache laundrette is shut down after
|
||||
* the nn->nfsd_serv pointer is cleared, but
|
||||
* before the svc_serv is freed.
|
||||
*/
|
||||
svc_wake_up(nn->nfsd_serv);
|
||||
struct svc_serv *serv = nn->nfsd_serv;
|
||||
|
||||
if (serv)
|
||||
svc_wake_up(serv);
|
||||
}
|
||||
nfsd_file_dispose_list(&dispose);
|
||||
}
|
||||
}
|
||||
@@ -552,13 +578,6 @@ nfsd_file_gc_cb(struct list_head *item, struct list_lru_one *lru,
|
||||
return nfsd_file_lru_cb(item, lru, arg);
|
||||
}
|
||||
|
||||
/* If the shrinker runs between calls to list_lru_walk_node() in
|
||||
* nfsd_file_gc(), the "remaining" count will be wrong. This could
|
||||
* result in premature freeing of some files. This may not matter much
|
||||
* but is easy to fix with this spinlock which temporarily disables
|
||||
* the shrinker.
|
||||
*/
|
||||
static DEFINE_SPINLOCK(nfsd_gc_lock);
|
||||
static void
|
||||
nfsd_file_gc(void)
|
||||
{
|
||||
@@ -581,9 +600,9 @@ nfsd_file_gc(void)
|
||||
remaining = 0;
|
||||
}
|
||||
}
|
||||
nfsd_file_dispose_list_delayed(&dispose);
|
||||
spin_unlock(&nfsd_gc_lock);
|
||||
trace_nfsd_file_gc_removed(ret, list_lru_count(&nfsd_file_lru));
|
||||
nfsd_file_dispose_list_delayed(&dispose);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -611,9 +630,9 @@ nfsd_file_lru_scan(struct shrinker *s, struct shrink_control *sc)
|
||||
|
||||
ret = list_lru_shrink_walk(&nfsd_file_lru, sc,
|
||||
nfsd_file_lru_cb, &dispose);
|
||||
nfsd_file_dispose_list_delayed(&dispose);
|
||||
spin_unlock(&nfsd_gc_lock);
|
||||
trace_nfsd_file_shrinker_removed(ret, list_lru_count(&nfsd_file_lru));
|
||||
nfsd_file_dispose_list_delayed(&dispose);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -686,11 +705,11 @@ nfsd_file_queue_for_close(struct inode *inode, struct list_head *dispose)
|
||||
}
|
||||
|
||||
/**
|
||||
* nfsd_file_close_inode - attempt a delayed close of a nfsd_file
|
||||
* nfsd_file_close_inode - attempt a deferred close of a nfsd_file
|
||||
* @inode: inode of the file to attempt to remove
|
||||
*
|
||||
* Close out any open nfsd_files that can be reaped for @inode. The
|
||||
* actual freeing is deferred to the dispose_list_delayed infrastructure.
|
||||
* actual freeing is deferred to the nfsd service threads.
|
||||
*
|
||||
* This is used by the fsnotify callbacks and setlease notifier.
|
||||
*/
|
||||
@@ -699,8 +718,10 @@ nfsd_file_close_inode(struct inode *inode)
|
||||
{
|
||||
LIST_HEAD(dispose);
|
||||
|
||||
spin_lock(&nfsd_gc_lock);
|
||||
nfsd_file_queue_for_close(inode, &dispose);
|
||||
nfsd_file_dispose_list_delayed(&dispose);
|
||||
spin_unlock(&nfsd_gc_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -812,12 +833,36 @@ nfsd_file_fsnotify_handle_event(struct fsnotify_mark *mark, u32 mask,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NFSD_V4
|
||||
static int
|
||||
nfsd_dir_fsnotify_handle_event(struct fsnotify_group *group, u32 mask,
|
||||
const void *data, int data_type, struct inode *dir,
|
||||
const struct qstr *name, u32 cookie,
|
||||
struct fsnotify_iter_info *iter_info)
|
||||
{
|
||||
return nfsd_handle_dir_event(mask, dir, data, data_type, name);
|
||||
}
|
||||
#else
|
||||
static int
|
||||
nfsd_dir_fsnotify_handle_event(struct fsnotify_group *group, u32 mask,
|
||||
const void *data, int data_type, struct inode *dir,
|
||||
const struct qstr *name, u32 cookie,
|
||||
struct fsnotify_iter_info *iter_info)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct fsnotify_ops nfsd_file_fsnotify_ops = {
|
||||
.handle_inode_event = nfsd_file_fsnotify_handle_event,
|
||||
.free_mark = nfsd_file_mark_free,
|
||||
};
|
||||
|
||||
static const struct fsnotify_ops nfsd_dir_fsnotify_ops = {
|
||||
.handle_event = nfsd_dir_fsnotify_handle_event,
|
||||
.free_mark = nfsd_file_mark_free,
|
||||
};
|
||||
|
||||
int
|
||||
nfsd_file_cache_init(void)
|
||||
{
|
||||
@@ -869,8 +914,7 @@ nfsd_file_cache_init(void)
|
||||
goto out_shrinker;
|
||||
}
|
||||
|
||||
nfsd_file_fsnotify_group = fsnotify_alloc_group(&nfsd_file_fsnotify_ops,
|
||||
0);
|
||||
nfsd_file_fsnotify_group = fsnotify_alloc_group(&nfsd_file_fsnotify_ops, 0);
|
||||
if (IS_ERR(nfsd_file_fsnotify_group)) {
|
||||
pr_err("nfsd: unable to create fsnotify group: %ld\n",
|
||||
PTR_ERR(nfsd_file_fsnotify_group));
|
||||
@@ -879,11 +923,23 @@ nfsd_file_cache_init(void)
|
||||
goto out_notifier;
|
||||
}
|
||||
|
||||
nfsd_dir_fsnotify_group = fsnotify_alloc_group(&nfsd_dir_fsnotify_ops, 0);
|
||||
if (IS_ERR(nfsd_dir_fsnotify_group)) {
|
||||
pr_err("nfsd: unable to create fsnotify group: %ld\n",
|
||||
PTR_ERR(nfsd_dir_fsnotify_group));
|
||||
ret = PTR_ERR(nfsd_dir_fsnotify_group);
|
||||
nfsd_dir_fsnotify_group = NULL;
|
||||
goto out_notify_group;
|
||||
}
|
||||
|
||||
INIT_DELAYED_WORK(&nfsd_filecache_laundrette, nfsd_file_gc_worker);
|
||||
out:
|
||||
if (ret)
|
||||
clear_bit(NFSD_FILE_CACHE_UP, &nfsd_file_flags);
|
||||
return ret;
|
||||
out_notify_group:
|
||||
fsnotify_put_group(nfsd_file_fsnotify_group);
|
||||
nfsd_file_fsnotify_group = NULL;
|
||||
out_notifier:
|
||||
lease_unregister_notifier(&nfsd_file_lease_notifier);
|
||||
out_shrinker:
|
||||
@@ -940,42 +996,14 @@ __nfsd_file_cache_purge(struct net *net)
|
||||
nfsd_file_dispose_list(&dispose);
|
||||
}
|
||||
|
||||
static struct nfsd_fcache_disposal *
|
||||
nfsd_alloc_fcache_disposal(void)
|
||||
{
|
||||
struct nfsd_fcache_disposal *l;
|
||||
|
||||
l = kmalloc_obj(*l);
|
||||
if (!l)
|
||||
return NULL;
|
||||
spin_lock_init(&l->lock);
|
||||
INIT_LIST_HEAD(&l->freeme);
|
||||
return l;
|
||||
}
|
||||
|
||||
static void
|
||||
nfsd_free_fcache_disposal(struct nfsd_fcache_disposal *l)
|
||||
{
|
||||
nfsd_file_dispose_list(&l->freeme);
|
||||
kfree(l);
|
||||
}
|
||||
|
||||
static void
|
||||
nfsd_free_fcache_disposal_net(struct net *net)
|
||||
{
|
||||
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
|
||||
struct nfsd_fcache_disposal *l = nn->fcache_disposal;
|
||||
|
||||
nfsd_free_fcache_disposal(l);
|
||||
}
|
||||
|
||||
int
|
||||
nfsd_file_cache_start_net(struct net *net)
|
||||
{
|
||||
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
|
||||
|
||||
nn->fcache_disposal = nfsd_alloc_fcache_disposal();
|
||||
return nn->fcache_disposal ? 0 : -ENOMEM;
|
||||
spin_lock_init(&nn->fcache_dispose_lock);
|
||||
INIT_LIST_HEAD(&nn->fcache_dispose_list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -994,8 +1022,18 @@ nfsd_file_cache_purge(struct net *net)
|
||||
void
|
||||
nfsd_file_cache_shutdown_net(struct net *net)
|
||||
{
|
||||
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
|
||||
|
||||
nfsd_file_cache_purge(net);
|
||||
nfsd_free_fcache_disposal_net(net);
|
||||
/*
|
||||
* Ensure any in-progress shrinker, GC, or fsnotify/lease callback
|
||||
* (all of which hold nfsd_gc_lock while calling
|
||||
* nfsd_file_dispose_list_delayed()) has fully completed before
|
||||
* draining the per-net dispose list.
|
||||
*/
|
||||
spin_lock(&nfsd_gc_lock);
|
||||
spin_unlock(&nfsd_gc_lock);
|
||||
nfsd_file_dispose_list(&nn->fcache_dispose_list);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1019,6 +1057,8 @@ nfsd_file_cache_shutdown(void)
|
||||
rcu_barrier();
|
||||
fsnotify_put_group(nfsd_file_fsnotify_group);
|
||||
nfsd_file_fsnotify_group = NULL;
|
||||
fsnotify_put_group(nfsd_dir_fsnotify_group);
|
||||
nfsd_dir_fsnotify_group = NULL;
|
||||
kmem_cache_destroy(nfsd_file_slab);
|
||||
nfsd_file_slab = NULL;
|
||||
fsnotify_wait_marks_destroyed();
|
||||
@@ -1223,11 +1263,9 @@ out:
|
||||
open_file:
|
||||
trace_nfsd_file_alloc(nf);
|
||||
|
||||
if (type == S_IFREG)
|
||||
nf->nf_mark = nfsd_file_mark_find_or_create(inode);
|
||||
|
||||
if (type != S_IFREG || nf->nf_mark) {
|
||||
if (file) {
|
||||
nf->nf_mark = nfsd_file_mark_find_or_create(inode);
|
||||
if (nf->nf_mark) {
|
||||
if (file && (file->f_mode & FMODE_OPENED)) {
|
||||
get_file(file);
|
||||
nf->nf_file = file;
|
||||
status = nfs_ok;
|
||||
@@ -1374,12 +1412,12 @@ nfsd_file_acquire_local(struct net *net, struct svc_cred *cred,
|
||||
* @rqstp: the RPC transaction being executed
|
||||
* @fhp: the NFS filehandle of the file just created
|
||||
* @may_flags: NFSD_MAY_ settings for the file
|
||||
* @file: cached, already-open file (may be NULL)
|
||||
* @file: cached, already-open file (may be NULL or not yet opened)
|
||||
* @pnf: OUT: new or found "struct nfsd_file" object
|
||||
*
|
||||
* Acquire a nfsd_file object that is not GC'ed. If one doesn't already exist,
|
||||
* and @file is non-NULL, use it to instantiate a new nfsd_file instead of
|
||||
* opening a new one.
|
||||
* and @file has FMODE_OPENED set, use it to instantiate a new nfsd_file
|
||||
* instead of opening a new one.
|
||||
*
|
||||
* Return values:
|
||||
* %nfs_ok - @pnf points to an nfsd_file with its reference
|
||||
@@ -1474,3 +1512,54 @@ int nfsd_file_cache_stats_show(struct seq_file *m, void *v)
|
||||
seq_printf(m, "mean age (ms): -\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* nfsd_fsnotify_recalc_mask - recalculate the fsnotify mask for a nfsd_file
|
||||
* @nf: nfsd_file to recalculate the mask on
|
||||
*
|
||||
* When a directory nfsd_file has a delegation added or removed, that may
|
||||
* change the events that nfsd requires from the VFS layer. This function
|
||||
* recalculates the fsnotify mask based on the leases present.
|
||||
*/
|
||||
void nfsd_fsnotify_recalc_mask(struct nfsd_file *nf)
|
||||
{
|
||||
struct inode *inode = file_inode(nf->nf_file);
|
||||
u32 lease_mask, set = 0, clear = 0;
|
||||
struct fsnotify_mark *mark;
|
||||
|
||||
/* This is only needed when adding or removing dir delegs */
|
||||
if (!S_ISDIR(inode->i_mode) || !nf->nf_mark)
|
||||
return;
|
||||
|
||||
mark = &nf->nf_mark->nfm_mark;
|
||||
|
||||
/*
|
||||
* The mark is shared by every nfsd_file on this inode, so concurrent
|
||||
* delegation add/remove on the same directory can recalc it in
|
||||
* parallel. Serialize the read of the lease state and the update of
|
||||
* the mark so that a recalc working from a stale snapshot of the
|
||||
* lease list can't clobber a concurrent recalc's update.
|
||||
*/
|
||||
mutex_lock(&nf->nf_mark->nfm_recalc_mutex);
|
||||
|
||||
/* Set up notifications for any ignored delegation events */
|
||||
lease_mask = inode_lease_ignore_mask(inode);
|
||||
|
||||
if (lease_mask & FL_IGN_DIR_CREATE)
|
||||
set |= FS_CREATE | FS_MOVED_TO;
|
||||
else
|
||||
clear |= FS_CREATE | FS_MOVED_TO;
|
||||
|
||||
if (lease_mask & FL_IGN_DIR_DELETE)
|
||||
set |= FS_DELETE | FS_MOVED_FROM;
|
||||
else
|
||||
clear |= FS_DELETE | FS_MOVED_FROM;
|
||||
|
||||
if (lease_mask & FL_IGN_DIR_RENAME)
|
||||
set |= FS_RENAME;
|
||||
else
|
||||
clear |= FS_RENAME;
|
||||
|
||||
fsnotify_modify_mark_mask(mark, set, clear);
|
||||
mutex_unlock(&nf->nf_mark->nfm_recalc_mutex);
|
||||
}
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
struct nfsd_file_mark {
|
||||
struct fsnotify_mark nfm_mark;
|
||||
refcount_t nfm_ref;
|
||||
/* serializes nfsd_fsnotify_recalc_mask() against itself */
|
||||
struct mutex nfm_recalc_mutex;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -86,4 +88,5 @@ __be32 nfsd_file_acquire_local(struct net *net, struct svc_cred *cred,
|
||||
__be32 nfsd_file_acquire_dir(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
||||
struct nfsd_file **pnf);
|
||||
int nfsd_file_cache_stats_show(struct seq_file *m, void *v);
|
||||
void nfsd_fsnotify_recalc_mask(struct nfsd_file *nf);
|
||||
#endif /* _FS_NFSD_FILECACHE_H */
|
||||
|
||||
@@ -30,19 +30,24 @@ nfsd4_ff_encode_layoutget(struct xdr_stream *xdr,
|
||||
struct ff_idmap uid;
|
||||
struct ff_idmap gid;
|
||||
|
||||
fh_len = 4 + fl->fh.size;
|
||||
fh_len = 4 + xdr_align_size(fl->fh.size);
|
||||
|
||||
uid.len = sprintf(uid.buf, "%u", from_kuid(&init_user_ns, fl->uid));
|
||||
gid.len = sprintf(gid.buf, "%u", from_kgid(&init_user_ns, fl->gid));
|
||||
|
||||
/* 8 + len for recording the length, name, and padding */
|
||||
ds_len = 20 + sizeof(stateid_opaque_t) + 4 + fh_len +
|
||||
8 + uid.len + 8 + gid.len;
|
||||
/* data server entry: deviceid + efficiency + stateid + fh list +
|
||||
* user + group + flags + stats_collect_hint
|
||||
*/
|
||||
ds_len = 16 + 4 + 4 + sizeof(stateid_opaque_t) + 4 + fh_len +
|
||||
4 + xdr_align_size(uid.len) +
|
||||
4 + xdr_align_size(gid.len) +
|
||||
4 + 4;
|
||||
|
||||
/* mirror: ds_count + ds */
|
||||
mirror_len = 4 + ds_len;
|
||||
|
||||
/* The layout segment */
|
||||
len = 20 + mirror_len;
|
||||
/* stripe_unit + mirror_count + mirror */
|
||||
len = 12 + mirror_len;
|
||||
|
||||
p = xdr_reserve_space(xdr, sizeof(__be32) + len);
|
||||
if (!p)
|
||||
@@ -94,7 +99,8 @@ nfsd4_ff_encode_getdeviceinfo(struct xdr_stream *xdr,
|
||||
}
|
||||
|
||||
/* len + padding for two strings */
|
||||
addr_len = 16 + da->netaddr.netid_len + da->netaddr.addr_len;
|
||||
addr_len = 8 + xdr_align_size(da->netaddr.netid_len) +
|
||||
xdr_align_size(da->netaddr.addr_len);
|
||||
ver_len = 20;
|
||||
|
||||
len = 4 + ver_len + 4 + addr_len;
|
||||
|
||||
+7
-1
@@ -97,11 +97,15 @@ nfsd_open_local_fh(struct net *net, struct auth_domain *dom,
|
||||
}
|
||||
nfsd_file_get(localio);
|
||||
again:
|
||||
rcu_read_lock();
|
||||
new = unrcu_pointer(cmpxchg(pnf, NULL, RCU_INITIALIZER(localio)));
|
||||
if (new) {
|
||||
/* Some other thread installed an nfsd_file */
|
||||
if (nfsd_file_get(new) == NULL)
|
||||
if (nfsd_file_get(new) == NULL) {
|
||||
rcu_read_unlock();
|
||||
goto again;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
/*
|
||||
* Drop the ref we were going to install (both file and
|
||||
* net) and the one we were going to return (only file).
|
||||
@@ -110,6 +114,8 @@ nfsd_open_local_fh(struct net *net, struct auth_domain *dom,
|
||||
nfsd_net_put(net);
|
||||
nfsd_file_put(localio);
|
||||
localio = new;
|
||||
} else {
|
||||
rcu_read_unlock();
|
||||
}
|
||||
} else
|
||||
nfsd_net_put(net);
|
||||
|
||||
+4
-2
@@ -92,6 +92,7 @@ nlm_fclose(struct file *filp)
|
||||
}
|
||||
|
||||
static const struct nlmsvc_binding nfsd_nlm_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.fopen = nlm_fopen, /* open file for locking */
|
||||
.fclose = nlm_fclose, /* close file */
|
||||
};
|
||||
@@ -100,11 +101,12 @@ void
|
||||
nfsd_lockd_init(void)
|
||||
{
|
||||
dprintk("nfsd: initializing lockd\n");
|
||||
nlmsvc_ops = &nfsd_nlm_ops;
|
||||
rcu_assign_pointer(nlmsvc_ops, &nfsd_nlm_ops);
|
||||
}
|
||||
|
||||
void
|
||||
nfsd_lockd_shutdown(void)
|
||||
{
|
||||
nlmsvc_ops = NULL;
|
||||
RCU_INIT_POINTER(nlmsvc_ops, NULL);
|
||||
synchronize_rcu();
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user