summaryrefslogtreecommitdiff
path: root/fs/afs/internal.h
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2017-11-02 18:27:50 +0300
committerDavid Howells <dhowells@redhat.com>2017-11-13 18:38:18 +0300
commit989782dcdc91a5e6d5999c7a52a84a60a0811e56 (patch)
tree138ed46554536280e0d4d1834a16c28740e8cdae /fs/afs/internal.h
parentbe080a6f43c40976afc950ee55e9b7f8e2b53525 (diff)
downloadlinux-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.h60
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 *);
/*