diff options
author | David Howells <dhowells@redhat.com> | 2017-11-02 18:27:50 +0300 |
---|---|---|
committer | David Howells <dhowells@redhat.com> | 2017-11-13 18:38:18 +0300 |
commit | 989782dcdc91a5e6d5999c7a52a84a60a0811e56 (patch) | |
tree | 138ed46554536280e0d4d1834a16c28740e8cdae /fs/afs/internal.h | |
parent | be080a6f43c40976afc950ee55e9b7f8e2b53525 (diff) | |
download | linux-989782dcdc91a5e6d5999c7a52a84a60a0811e56.tar.xz |
afs: Overhaul cell database management
Overhaul the way that the in-kernel AFS client keeps track of cells in the
following manner:
(1) Cells are now held in an rbtree to make walking them quicker and RCU
managed (though this is probably overkill).
(2) Cells now have a manager work item that:
(A) Looks after fetching and refreshing the VL server list.
(B) Manages cell record lifetime, including initialising and
destruction.
(B) Manages cell record caching whereby threads are kept around for a
certain time after last use and then destroyed.
(C) Manages the FS-Cache index cookie for a cell. It is not permitted
for a cookie to be in use twice, so we have to be careful to not
allow a new cell record to exist at the same time as an old record
of the same name.
(3) Each AFS network namespace is given a manager work item that manages
the cells within it, maintaining a single timer to prod cells into
updating their DNS records.
This uses the reduce_timer() facility to make the timer expire at the
soonest timed event that needs happening.
(4) When a module is being unloaded, cells and cell managers are now
counted out using dec_after_work() to make sure the module text is
pinned until after the data structures have been cleaned up.
(5) Each cell's VL server list is now protected by a seqlock rather than a
semaphore.
Signed-off-by: David Howells <dhowells@redhat.com>
Diffstat (limited to 'fs/afs/internal.h')
-rw-r--r-- | fs/afs/internal.h | 60 |
1 files changed, 45 insertions, 15 deletions
diff --git a/fs/afs/internal.h b/fs/afs/internal.h index 7c318666e436..51e3825b5ffb 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -207,13 +207,14 @@ struct afs_net { atomic_t nr_superblocks; /* Cell database */ - struct list_head cells; + struct rb_root cells; struct afs_cell *ws_cell; - rwlock_t cells_lock; - struct rw_semaphore cells_sem; - wait_queue_head_t cells_freeable_wq; + struct work_struct cells_manager; + struct timer_list cells_timer; + atomic_t cells_outstanding; + seqlock_t cells_lock; - struct rw_semaphore proc_cells_sem; + spinlock_t proc_cells_lock; struct list_head proc_cells; /* Volume location database */ @@ -242,14 +243,26 @@ struct afs_net { extern struct afs_net __afs_net;// Dummy AFS network namespace; TODO: replace with real netns +enum afs_cell_state { + AFS_CELL_UNSET, + AFS_CELL_ACTIVATING, + AFS_CELL_ACTIVE, + AFS_CELL_DEACTIVATING, + AFS_CELL_INACTIVE, + AFS_CELL_FAILED, +}; + /* * AFS cell record */ struct afs_cell { - atomic_t usage; - struct list_head link; /* main cell list link */ - struct afs_net *net; /* The network namespace */ + union { + struct rcu_head rcu; + struct rb_node net_node; /* Node in net->cells */ + }; + struct afs_net *net; struct key *anonymous_key; /* anonymous user key for this cell */ + struct work_struct manager; /* Manager for init/deinit/dns */ struct list_head proc_link; /* /proc cell list link */ #ifdef CONFIG_AFS_FSCACHE struct fscache_cookie *cache; /* caching cookie */ @@ -262,12 +275,26 @@ struct afs_cell { /* volume location record management */ struct rw_semaphore vl_sem; /* volume management serialisation semaphore */ struct list_head vl_list; /* cell's active VL record list */ + time64_t dns_expiry; /* Time AFSDB/SRV record expires */ + time64_t last_inactive; /* Time of last drop of usage count */ + atomic_t usage; + unsigned long flags; +#define AFS_CELL_FL_NOT_READY 0 /* The cell record is not ready for use */ +#define AFS_CELL_FL_NO_GC 1 /* The cell was added manually, don't auto-gc */ +#define AFS_CELL_FL_NOT_FOUND 2 /* Permanent DNS error */ +#define AFS_CELL_FL_DNS_FAIL 3 /* Failed to access DNS */ + enum afs_cell_state state; + short error; + spinlock_t vl_lock; /* vl_list lock */ + + /* VLDB server list. */ + seqlock_t vl_addrs_lock; unsigned short vl_naddrs; /* number of VL servers in addr list */ unsigned short vl_curr_svix; /* current server index */ struct sockaddr_rxrpc vl_addrs[AFS_CELL_MAX_ADDRS]; /* cell VL server addresses */ - - char name[0]; /* cell name - must go last */ + u8 name_len; /* Length of name */ + char name[64 + 1]; /* Cell name, case-flattened and NUL-padded */ }; /* @@ -494,17 +521,20 @@ static inline struct afs_cb_interest *afs_get_cb_interest(struct afs_cb_interest /* * cell.c */ -static inline struct afs_cell *afs_get_cell(struct afs_cell *cell) + static inline struct afs_cell *afs_get_cell(struct afs_cell *cell) { if (cell) atomic_inc(&cell->usage); return cell; } -extern int afs_cell_init(struct afs_net *, char *); -extern struct afs_cell *afs_cell_create(struct afs_net *, const char *, unsigned, char *, bool); -extern struct afs_cell *afs_cell_lookup(struct afs_net *, const char *, unsigned, bool); -extern struct afs_cell *afs_grab_cell(struct afs_cell *); + +extern int afs_cell_init(struct afs_net *, const char *); +extern struct afs_cell *afs_lookup_cell_rcu(struct afs_net *, const char *, unsigned); +extern struct afs_cell *afs_lookup_cell(struct afs_net *, const char *, unsigned, + const char *, bool); extern void afs_put_cell(struct afs_net *, struct afs_cell *); +extern void afs_manage_cells(struct work_struct *); +extern void afs_cells_timer(struct timer_list *); extern void __net_exit afs_cell_purge(struct afs_net *); /* |