diff options
author | David Howells <dhowells@redhat.com> | 2020-04-30 02:03:49 +0200 |
---|---|---|
committer | David Howells <dhowells@redhat.com> | 2020-06-04 16:37:57 +0200 |
commit | 20325960f8750165964a6891a733e4cc15d19076 (patch) | |
tree | d372bb21037626d2fac40b9a1e6e6bea21786b8e /fs/afs/dir.c | |
parent | afs: Add a tracepoint to track the lifetime of the afs_volume struct (diff) | |
download | linux-20325960f8750165964a6891a733e4cc15d19076.tar.xz linux-20325960f8750165964a6891a733e4cc15d19076.zip |
afs: Reorganise volume and server trees to be rooted on the cell
Reorganise afs_volume objects such that they're in a tree keyed on volume
ID, rooted at on an afs_cell object rather than being in multiple trees,
each of which is rooted on an afs_server object.
afs_server structs become per-cell and acquire a pointer to the cell.
The process of breaking a callback then starts with finding the server by
its network address, following that to the cell and then looking up each
volume ID in the volume tree.
This is simpler than the afs_vol_interest/afs_cb_interest N:M mapping web
and allows those structs and the code for maintaining them to be simplified
or removed.
It does make a couple of things a bit more tricky, though:
(1) Operations now start with a volume, not a server, so there can be more
than one answer as to whether or not the server we'll end up using
supports the FS.InlineBulkStatus RPC.
(2) CB RPC operations that specify the server UUID. There's still a tree
of servers by UUID on the afs_net struct, but the UUIDs in it aren't
guaranteed unique.
Signed-off-by: David Howells <dhowells@redhat.com>
Diffstat (limited to 'fs/afs/dir.c')
-rw-r--r-- | fs/afs/dir.c | 45 |
1 files changed, 33 insertions, 12 deletions
diff --git a/fs/afs/dir.c b/fs/afs/dir.c index 0d3cf3af0352..25cbe0aeeec5 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c @@ -703,6 +703,37 @@ static const struct afs_operation_ops afs_fetch_status_operation = { }; /* + * See if we know that the server we expect to use doesn't support + * FS.InlineBulkStatus. + */ +static bool afs_server_supports_ibulk(struct afs_vnode *dvnode) +{ + struct afs_server_list *slist; + struct afs_volume *volume = dvnode->volume; + struct afs_server *server; + bool ret = true; + int i; + + if (!test_bit(AFS_VOLUME_MAYBE_NO_IBULK, &volume->flags)) + return true; + + rcu_read_lock(); + slist = rcu_dereference(volume->servers); + + for (i = 0; i < slist->nr_servers; i++) { + server = slist->servers[i].server; + if (server == dvnode->cb_server) { + if (test_bit(AFS_SERVER_FL_NO_IBULK, &server->flags)) + ret = false; + break; + } + } + + rcu_read_unlock(); + return ret; +} + +/* * Do a lookup in a directory. We make use of bulk lookup to query a slew of * files in one go and create inodes for them. The inode of the file we were * asked for is returned. @@ -711,10 +742,8 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry, struct key *key) { struct afs_lookup_cookie *cookie; - struct afs_cb_interest *dcbi; struct afs_vnode_param *vp; struct afs_operation *op; - struct afs_server *server; struct afs_vnode *dvnode = AFS_FS_I(dir), *vnode; struct inode *inode = NULL, *ti; afs_dataversion_t data_version = READ_ONCE(dvnode->status.data_version); @@ -734,16 +763,8 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry, cookie->nr_fids = 2; /* slot 0 is saved for the fid we actually want * and slot 1 for the directory */ - read_seqlock_excl(&dvnode->cb_lock); - dcbi = rcu_dereference_protected(dvnode->cb_interest, - lockdep_is_held(&dvnode->cb_lock.lock)); - if (dcbi) { - server = dcbi->server; - if (server && - test_bit(AFS_SERVER_FL_NO_IBULK, &server->flags)) - cookie->one_only = true; - } - read_sequnlock_excl(&dvnode->cb_lock); + if (!afs_server_supports_ibulk(dvnode)) + cookie->one_only = true; /* search the directory */ ret = afs_dir_iterate(dir, &cookie->ctx, key, &data_version); |