mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-18 02:04:05 +08:00
AFS development
Tested-by: Marc Dionne <marc.dionne@auristor.com> -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEqG5UsNXhtOCrfGQP+7dXa6fLC2sFAl1+owMACgkQ+7dXa6fL C2v6+RAAoelLwYFRYYwQRJ1JnPapUGgHQSlDR7nlOXAc69yNWuKp4BIh/29G4ZgP Z6f/puXIogc8zwhQ958omDP7ZkFLydP9JkXUsYJuDzjG2pFLCSqgXm4fp6+Srb0Y L2JHm9geMfM0B2I+uuPCQSl33NcZrBh6lKONFyXP+tZ+ihSxqegGVCoNwFBpyKFl 7pVXSzVUW7OxLRsNAYqONcW5Kv89wqnB13lBIl8gpfyahHu2y6oNVMoEyr6ZwcSW X+VEC9BJeFYkO7kc4h0+EavovKON4N26Eo0+7dtZf/ytURxD5FtTc+nfRKbb4gHq qAfJwEWJsTCO0ej042j1cXizLcOoAC6DMHRnVbLA3RukiWvVsjHtIv1bxCxEULw9 Ye4ktmdfoQk9LB/b2sGN/9NShMi/pmuHeOmtegDfN/h2aF0cI5fMusdf7XPuAPv7 qYfBDSZ+tHkwp2R72Bmv3a0kqqTZnRXQLx1C4smQlE6yH74l8/iSl+J6e5lEJ247 KjI5x0WNurCOYCjVaihC7fV8X/fyUsyuxw7Ui9z7a9BxHM838ZiFPzPd09kmoL6T WqrllWJ35R4Bv8e5s6hGzZz52n5cW0LUnVwepPghe2adZ3LY49ej8ZSY1oTmjmOP sZZKsdmzCbd0p5aw37X424tk8yT8kexLM6Yw48GyYeUv659VLkA= =Nueu -----END PGP SIGNATURE----- Merge tag 'afs-next-20190915' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs Pull AFS updates from David Howells: "Here's a set of patches for AFS. The first three are trivial, deleting unused symbols and rolling out a wrapper function. The fourth and fifth patches make use of the previously added RCU-safe request_key facility to allow afs_permission() and afs_d_revalidate() to attempt to operate without dropping out of RCU-mode pathwalk. Under certain conditions, such as conflict with another client, we still have to drop out anyway, take a lock and consult the server" * tag 'afs-next-20190915' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs: afs: Support RCU pathwalk afs: Provide an RCU-capable key lookup afs: Use afs_extract_discard() rather than iov_iter_discard() afs: remove unused variable 'afs_zero_fid' afs: remove unused variable 'afs_voltypes'
This commit is contained in:
commit
0bb73e42f0
54
fs/afs/dir.c
54
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));
|
||||
|
@ -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);
|
||||
@ -394,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 */
|
||||
|
||||
@ -1872,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 */
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
@ -274,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
|
||||
@ -340,14 +403,21 @@ 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);
|
||||
|
||||
if (mask & MAY_NOT_BLOCK) {
|
||||
key = afs_request_key_rcu(vnode->volume->cell);
|
||||
if (IS_ERR(key))
|
||||
return -ECHILD;
|
||||
|
||||
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));
|
||||
@ -362,11 +432,13 @@ int afs_permission(struct inode *inode, int mask)
|
||||
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))
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user