From cacf2d7dcf966a57e30f66c0598c88e2b64865a3 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Fri, 9 Aug 2019 16:40:37 +0800 Subject: afs: remove unused variable 'afs_voltypes' fs/afs/volume.c:15:26: warning: afs_voltypes defined but not used [-Wunused-const-variable=] It is not used since commit d2ddc776a458 ("afs: Overhaul volume and server record caching and fileserver rotation") Reported-by: Hulk Robot Signed-off-by: YueHaibing Signed-off-by: David Howells --- fs/afs/volume.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/fs/afs/volume.c b/fs/afs/volume.c index 1a414300b654..92ca5e27573b 100644 --- a/fs/afs/volume.c +++ b/fs/afs/volume.c @@ -12,8 +12,6 @@ unsigned __read_mostly afs_volume_gc_delay = 10; unsigned __read_mostly afs_volume_record_life = 60 * 60; -static const char *const afs_voltypes[] = { "R/W", "R/O", "BAK" }; - /* * Allocate a volume record and load it up from a vldb record. */ -- cgit v1.2.3-59-g8ed1b From 52c9c130780095fdf72fbf6920a6a1c936fb5e6f Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Fri, 9 Aug 2019 16:42:31 +0800 Subject: afs: remove unused variable 'afs_zero_fid' fs/afs/fsclient.c:18:29: warning: afs_zero_fid defined but not used [-Wunused-const-variable=] It is never used since commit 025db80c9e42 ("afs: Trace the initiation and completion of client calls") Reported-by: Hulk Robot Signed-off-by: YueHaibing Signed-off-by: David Howells --- fs/afs/fsclient.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c index 114f281f3687..67af0682342e 100644 --- a/fs/afs/fsclient.c +++ b/fs/afs/fsclient.c @@ -15,8 +15,6 @@ #include "xdr_fs.h" #include "protocol_yfs.h" -static const struct afs_fid afs_zero_fid; - static inline void afs_use_fs_server(struct afs_call *call, struct afs_cb_interest *cbi) { call->cbi = afs_get_cb_interest(cbi); -- cgit v1.2.3-59-g8ed1b From 23a289137ab82daeea826eeb9556c6f89b1fcd67 Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 20 Aug 2019 09:22:38 +0100 Subject: afs: Use afs_extract_discard() rather than iov_iter_discard() Use afs_extract_discard() rather than iov_iter_discard() as the former is a wrapper for the latter, providing a place to put tracepoints. Signed-off-by: David Howells --- fs/afs/fsclient.c | 4 ++-- fs/afs/yfsclient.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c index 67af0682342e..6f84231f11a5 100644 --- a/fs/afs/fsclient.c +++ b/fs/afs/fsclient.c @@ -392,7 +392,7 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call) goto no_more_data; /* Discard any excess data the server gave us */ - iov_iter_discard(&call->iter, READ, req->actual_len - req->len); + afs_extract_discard(call, req->actual_len - req->len); call->unmarshall = 3; /* Fall through */ @@ -1870,7 +1870,7 @@ static int afs_deliver_fs_get_capabilities(struct afs_call *call) call->count = count; call->count2 = count; - iov_iter_discard(&call->iter, READ, count * sizeof(__be32)); + afs_extract_discard(call, count * sizeof(__be32)); call->unmarshall++; /* Fall through */ diff --git a/fs/afs/yfsclient.c b/fs/afs/yfsclient.c index ca2452806ebf..3ee7abf4b2d0 100644 --- a/fs/afs/yfsclient.c +++ b/fs/afs/yfsclient.c @@ -505,7 +505,7 @@ static int yfs_deliver_fs_fetch_data64(struct afs_call *call) goto no_more_data; /* Discard any excess data the server gave us */ - iov_iter_discard(&call->iter, READ, req->actual_len - req->len); + afs_extract_discard(call, req->actual_len - req->len); call->unmarshall = 3; /* Fall through */ @@ -2007,7 +2007,7 @@ static int yfs_deliver_fs_fetch_opaque_acl(struct afs_call *call) acl->size = call->count2; afs_extract_begin(call, acl->data, size); } else { - iov_iter_discard(&call->iter, READ, size); + afs_extract_discard(call, size); } call->unmarshall++; /* Fall through */ @@ -2039,7 +2039,7 @@ static int yfs_deliver_fs_fetch_opaque_acl(struct afs_call *call) acl->size = call->count2; afs_extract_begin(call, acl->data, size); } else { - iov_iter_discard(&call->iter, READ, size); + afs_extract_discard(call, size); } call->unmarshall++; /* Fall through */ -- cgit v1.2.3-59-g8ed1b From 8b6a666a97544bf307190a05947742b8357aa962 Mon Sep 17 00:00:00 2001 From: David Howells Date: Mon, 20 May 2019 08:48:46 +0100 Subject: afs: Provide an RCU-capable key lookup Provide an RCU-capable key lookup function. We don't want to call afs_request_key() in RCU-mode pathwalk as request_key() might sleep, even if we don't ask it to construct anything as it might find a key that is currently undergoing construction. Signed-off-by: David Howells --- fs/afs/internal.h | 1 + fs/afs/security.c | 33 +++++++++++++++++++++++++++++++-- include/linux/key.h | 14 +++++++++++++- 3 files changed, 45 insertions(+), 3 deletions(-) diff --git a/fs/afs/internal.h b/fs/afs/internal.h index f66a3be12fd6..9cdfabaeaa0b 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -1217,6 +1217,7 @@ extern void afs_cache_permit(struct afs_vnode *, struct key *, unsigned int, struct afs_status_cb *); extern void afs_zap_permits(struct rcu_head *); extern struct key *afs_request_key(struct afs_cell *); +extern struct key *afs_request_key_rcu(struct afs_cell *); extern int afs_check_permit(struct afs_vnode *, struct key *, afs_access_t *); extern int afs_permission(struct inode *, int); extern void __exit afs_clean_up_permit_cache(void); diff --git a/fs/afs/security.c b/fs/afs/security.c index 71e71c07568f..ef2fd34ba282 100644 --- a/fs/afs/security.c +++ b/fs/afs/security.c @@ -27,8 +27,37 @@ struct key *afs_request_key(struct afs_cell *cell) _enter("{%x}", key_serial(cell->anonymous_key)); _debug("key %s", cell->anonymous_key->description); - key = request_key(&key_type_rxrpc, cell->anonymous_key->description, - NULL); + key = request_key_net(&key_type_rxrpc, cell->anonymous_key->description, + cell->net->net, NULL); + if (IS_ERR(key)) { + if (PTR_ERR(key) != -ENOKEY) { + _leave(" = %ld", PTR_ERR(key)); + return key; + } + + /* act as anonymous user */ + _leave(" = {%x} [anon]", key_serial(cell->anonymous_key)); + return key_get(cell->anonymous_key); + } else { + /* act as authorised user */ + _leave(" = {%x} [auth]", key_serial(key)); + return key; + } +} + +/* + * Get a key when pathwalk is in rcuwalk mode. + */ +struct key *afs_request_key_rcu(struct afs_cell *cell) +{ + struct key *key; + + _enter("{%x}", key_serial(cell->anonymous_key)); + + _debug("key %s", cell->anonymous_key->description); + key = request_key_net_rcu(&key_type_rxrpc, + cell->anonymous_key->description, + cell->net->net); if (IS_ERR(key)) { if (PTR_ERR(key) != -ENOKEY) { _leave(" = %ld", PTR_ERR(key)); diff --git a/include/linux/key.h b/include/linux/key.h index 50028338a4cc..6cf8e71cf8b7 100644 --- a/include/linux/key.h +++ b/include/linux/key.h @@ -324,7 +324,7 @@ static inline struct key *request_key(struct key_type *type, } #ifdef CONFIG_NET -/* +/** * request_key_net - Request a key for a net namespace and wait for construction * @type: Type of key. * @description: The searchable description of the key. @@ -341,6 +341,18 @@ static inline struct key *request_key(struct key_type *type, */ #define request_key_net(type, description, net, callout_info) \ request_key_tag(type, description, net->key_domain, callout_info); + +/** + * request_key_net_rcu - Request a key for a net namespace under RCU conditions + * @type: Type of key. + * @description: The searchable description of the key. + * @net: The network namespace that is the key's domain of operation. + * + * As for request_key_rcu() except that only keys that operate the specified + * network namespace are used. + */ +#define request_key_net_rcu(type, description, net) \ + request_key_rcu(type, description, net->key_domain); #endif /* CONFIG_NET */ extern int wait_for_key_construction(struct key *key, bool intr); -- cgit v1.2.3-59-g8ed1b From a0753c29004f4983e303abce019f29e183b1ee48 Mon Sep 17 00:00:00 2001 From: David Howells Date: Mon, 20 May 2019 08:48:46 +0100 Subject: afs: Support RCU pathwalk Make afs_permission() and afs_d_revalidate() do initial checks in RCU-mode pathwalk to reduce latency in pathwalk elements that get done multiple times. We don't need to query the server unless we've received a notification from it that something has changed or the callback has expired. This requires that we can request a key and check permits under RCU conditions if we need to. Signed-off-by: David Howells --- fs/afs/dir.c | 54 ++++++++++++++++++++++++++++++++++++++- fs/afs/security.c | 75 +++++++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 112 insertions(+), 17 deletions(-) diff --git a/fs/afs/dir.c b/fs/afs/dir.c index 139b4e3cc946..cc12772d0a4d 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c @@ -965,6 +965,58 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry, return d; } +/* + * Check the validity of a dentry under RCU conditions. + */ +static int afs_d_revalidate_rcu(struct dentry *dentry) +{ + struct afs_vnode *dvnode, *vnode; + struct dentry *parent; + struct inode *dir, *inode; + long dir_version, de_version; + + _enter("%p", dentry); + + /* Check the parent directory is still valid first. */ + parent = READ_ONCE(dentry->d_parent); + dir = d_inode_rcu(parent); + if (!dir) + return -ECHILD; + dvnode = AFS_FS_I(dir); + if (test_bit(AFS_VNODE_DELETED, &dvnode->flags)) + return -ECHILD; + + if (!afs_check_validity(dvnode)) + return -ECHILD; + + /* We only need to invalidate a dentry if the server's copy changed + * behind our back. If we made the change, it's no problem. Note that + * on a 32-bit system, we only have 32 bits in the dentry to store the + * version. + */ + dir_version = (long)READ_ONCE(dvnode->status.data_version); + de_version = (long)READ_ONCE(dentry->d_fsdata); + if (de_version != dir_version) { + dir_version = (long)READ_ONCE(dvnode->invalid_before); + if (de_version - dir_version < 0) + return -ECHILD; + } + + /* Check to see if the vnode referred to by the dentry still + * has a callback. + */ + if (d_really_is_positive(dentry)) { + inode = d_inode_rcu(dentry); + if (inode) { + vnode = AFS_FS_I(inode); + if (!afs_check_validity(vnode)) + return -ECHILD; + } + } + + return 1; /* Still valid */ +} + /* * check that a dentry lookup hit has found a valid entry * - NOTE! the hit can be a negative hit too, so we can't assume we have an @@ -982,7 +1034,7 @@ static int afs_d_revalidate(struct dentry *dentry, unsigned int flags) int ret; if (flags & LOOKUP_RCU) - return -ECHILD; + return afs_d_revalidate_rcu(dentry); if (d_really_is_positive(dentry)) { vnode = AFS_FS_I(d_inode(dentry)); diff --git a/fs/afs/security.c b/fs/afs/security.c index ef2fd34ba282..ce9de1e6742b 100644 --- a/fs/afs/security.c +++ b/fs/afs/security.c @@ -303,6 +303,40 @@ someone_else_changed_it: return; } +static bool afs_check_permit_rcu(struct afs_vnode *vnode, struct key *key, + afs_access_t *_access) +{ + const struct afs_permits *permits; + int i; + + _enter("{%llx:%llu},%x", + vnode->fid.vid, vnode->fid.vnode, key_serial(key)); + + /* check the permits to see if we've got one yet */ + if (key == vnode->volume->cell->anonymous_key) { + *_access = vnode->status.anon_access; + _leave(" = t [anon %x]", *_access); + return true; + } + + permits = rcu_dereference(vnode->permit_cache); + if (permits) { + for (i = 0; i < permits->nr_permits; i++) { + if (permits->permits[i].key < key) + continue; + if (permits->permits[i].key > key) + break; + + *_access = permits->permits[i].access; + _leave(" = %u [perm %x]", !permits->invalidated, *_access); + return !permits->invalidated; + } + } + + _leave(" = f"); + return false; +} + /* * check with the fileserver to see if the directory or parent directory is * permitted to be accessed with this authorisation, and if so, what access it @@ -369,33 +403,42 @@ int afs_permission(struct inode *inode, int mask) struct afs_vnode *vnode = AFS_FS_I(inode); afs_access_t uninitialized_var(access); struct key *key; - int ret; - - if (mask & MAY_NOT_BLOCK) - return -ECHILD; + int ret = 0; _enter("{{%llx:%llu},%lx},%x,", vnode->fid.vid, vnode->fid.vnode, vnode->flags, mask); - key = afs_request_key(vnode->volume->cell); - if (IS_ERR(key)) { - _leave(" = %ld [key]", PTR_ERR(key)); - return PTR_ERR(key); - } + if (mask & MAY_NOT_BLOCK) { + key = afs_request_key_rcu(vnode->volume->cell); + if (IS_ERR(key)) + return -ECHILD; - ret = afs_validate(vnode, key); - if (ret < 0) - goto error; + ret = -ECHILD; + if (!afs_check_validity(vnode) || + !afs_check_permit_rcu(vnode, key, &access)) + goto error; + } else { + key = afs_request_key(vnode->volume->cell); + if (IS_ERR(key)) { + _leave(" = %ld [key]", PTR_ERR(key)); + return PTR_ERR(key); + } - /* check the permits to see if we've got one yet */ - ret = afs_check_permit(vnode, key, &access); - if (ret < 0) - goto error; + ret = afs_validate(vnode, key); + if (ret < 0) + goto error; + + /* check the permits to see if we've got one yet */ + ret = afs_check_permit(vnode, key, &access); + if (ret < 0) + goto error; + } /* interpret the access mask */ _debug("REQ %x ACC %x on %s", mask, access, S_ISDIR(inode->i_mode) ? "dir" : "file"); + ret = 0; if (S_ISDIR(inode->i_mode)) { if (mask & (MAY_EXEC | MAY_READ | MAY_CHDIR)) { if (!(access & AFS_ACE_LOOKUP)) -- cgit v1.2.3-59-g8ed1b