aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/afs/callback.c110
-rw-r--r--fs/afs/internal.h15
-rw-r--r--fs/afs/server.c2
3 files changed, 107 insertions, 20 deletions
diff --git a/fs/afs/callback.c b/fs/afs/callback.c
index 571437dcb252..5f261fbf2182 100644
--- a/fs/afs/callback.c
+++ b/fs/afs/callback.c
@@ -21,6 +21,66 @@
21#include "internal.h" 21#include "internal.h"
22 22
23/* 23/*
24 * Create volume and callback interests on a server.
25 */
26static struct afs_cb_interest *afs_create_interest(struct afs_server *server,
27 struct afs_vnode *vnode)
28{
29 struct afs_vol_interest *new_vi, *vi;
30 struct afs_cb_interest *new;
31 struct hlist_node **pp;
32
33 new_vi = kzalloc(sizeof(struct afs_vol_interest), GFP_KERNEL);
34 if (!new_vi)
35 return NULL;
36
37 new = kzalloc(sizeof(struct afs_cb_interest), GFP_KERNEL);
38 if (!new) {
39 kfree(new_vi);
40 return NULL;
41 }
42
43 new_vi->usage = 1;
44 new_vi->vid = vnode->volume->vid;
45 INIT_HLIST_NODE(&new_vi->srv_link);
46 INIT_HLIST_HEAD(&new_vi->cb_interests);
47
48 refcount_set(&new->usage, 1);
49 new->sb = vnode->vfs_inode.i_sb;
50 new->vid = vnode->volume->vid;
51 new->server = afs_get_server(server);
52 INIT_HLIST_NODE(&new->cb_vlink);
53
54 write_lock(&server->cb_break_lock);
55
56 for (pp = &server->cb_volumes.first; *pp; pp = &(*pp)->next) {
57 vi = hlist_entry(*pp, struct afs_vol_interest, srv_link);
58 if (vi->vid < new_vi->vid)
59 continue;
60 if (vi->vid > new_vi->vid)
61 break;
62 vi->usage++;
63 goto found_vi;
64 }
65
66 new_vi->srv_link.pprev = pp;
67 new_vi->srv_link.next = *pp;
68 if (*pp)
69 (*pp)->pprev = &new_vi->srv_link.next;
70 *pp = &new_vi->srv_link;
71 vi = new_vi;
72 new_vi = NULL;
73found_vi:
74
75 new->vol_interest = vi;
76 hlist_add_head(&new->cb_vlink, &vi->cb_interests);
77
78 write_unlock(&server->cb_break_lock);
79 kfree(new_vi);
80 return new;
81}
82
83/*
24 * Set up an interest-in-callbacks record for a volume on a server and 84 * Set up an interest-in-callbacks record for a volume on a server and
25 * register it with the server. 85 * register it with the server.
26 * - Called with vnode->io_lock held. 86 * - Called with vnode->io_lock held.
@@ -77,20 +137,10 @@ again:
77 } 137 }
78 138
79 if (!cbi) { 139 if (!cbi) {
80 new = kzalloc(sizeof(struct afs_cb_interest), GFP_KERNEL); 140 new = afs_create_interest(server, vnode);
81 if (!new) 141 if (!new)
82 return -ENOMEM; 142 return -ENOMEM;
83 143
84 refcount_set(&new->usage, 1);
85 new->sb = vnode->vfs_inode.i_sb;
86 new->vid = vnode->volume->vid;
87 new->server = afs_get_server(server);
88 INIT_LIST_HEAD(&new->cb_link);
89
90 write_lock(&server->cb_break_lock);
91 list_add_tail(&new->cb_link, &server->cb_interests);
92 write_unlock(&server->cb_break_lock);
93
94 write_lock(&slist->lock); 144 write_lock(&slist->lock);
95 if (!entry->cb_interest) { 145 if (!entry->cb_interest) {
96 entry->cb_interest = afs_get_cb_interest(new); 146 entry->cb_interest = afs_get_cb_interest(new);
@@ -126,11 +176,22 @@ again:
126 */ 176 */
127void afs_put_cb_interest(struct afs_net *net, struct afs_cb_interest *cbi) 177void afs_put_cb_interest(struct afs_net *net, struct afs_cb_interest *cbi)
128{ 178{
179 struct afs_vol_interest *vi;
180
129 if (cbi && refcount_dec_and_test(&cbi->usage)) { 181 if (cbi && refcount_dec_and_test(&cbi->usage)) {
130 if (!list_empty(&cbi->cb_link)) { 182 if (!hlist_unhashed(&cbi->cb_vlink)) {
131 write_lock(&cbi->server->cb_break_lock); 183 write_lock(&cbi->server->cb_break_lock);
132 list_del_init(&cbi->cb_link); 184
185 hlist_del_init(&cbi->cb_vlink);
186 vi = cbi->vol_interest;
187 cbi->vol_interest = NULL;
188 if (--vi->usage == 0)
189 hlist_del(&vi->srv_link);
190 else
191 vi = NULL;
192
133 write_unlock(&cbi->server->cb_break_lock); 193 write_unlock(&cbi->server->cb_break_lock);
194 kfree(vi);
134 afs_put_server(net, cbi->server); 195 afs_put_server(net, cbi->server);
135 } 196 }
136 kfree(cbi); 197 kfree(cbi);
@@ -182,20 +243,34 @@ void afs_break_callback(struct afs_vnode *vnode)
182static void afs_break_one_callback(struct afs_server *server, 243static void afs_break_one_callback(struct afs_server *server,
183 struct afs_fid *fid) 244 struct afs_fid *fid)
184{ 245{
246 struct afs_vol_interest *vi;
185 struct afs_cb_interest *cbi; 247 struct afs_cb_interest *cbi;
186 struct afs_iget_data data; 248 struct afs_iget_data data;
187 struct afs_vnode *vnode; 249 struct afs_vnode *vnode;
188 struct inode *inode; 250 struct inode *inode;
189 251
190 read_lock(&server->cb_break_lock); 252 read_lock(&server->cb_break_lock);
253 hlist_for_each_entry(vi, &server->cb_volumes, srv_link) {
254 if (vi->vid < fid->vid)
255 continue;
256 if (vi->vid > fid->vid) {
257 vi = NULL;
258 break;
259 }
260 //atomic_inc(&vi->usage);
261 break;
262 }
263
264 /* TODO: Find all matching volumes if we couldn't match the server and
265 * break them anyway.
266 */
267 if (!vi)
268 goto out;
191 269
192 /* Step through all interested superblocks. There may be more than one 270 /* Step through all interested superblocks. There may be more than one
193 * because of cell aliasing. 271 * because of cell aliasing.
194 */ 272 */
195 list_for_each_entry(cbi, &server->cb_interests, cb_link) { 273 hlist_for_each_entry(cbi, &vi->cb_interests, cb_vlink) {
196 if (cbi->vid != fid->vid)
197 continue;
198
199 if (fid->vnode == 0 && fid->unique == 0) { 274 if (fid->vnode == 0 && fid->unique == 0) {
200 /* The callback break applies to an entire volume. */ 275 /* The callback break applies to an entire volume. */
201 struct afs_super_info *as = AFS_FS_S(cbi->sb); 276 struct afs_super_info *as = AFS_FS_S(cbi->sb);
@@ -217,6 +292,7 @@ static void afs_break_one_callback(struct afs_server *server,
217 } 292 }
218 } 293 }
219 294
295out:
220 read_unlock(&server->cb_break_lock); 296 read_unlock(&server->cb_break_lock);
221} 297}
222 298
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index 5d8260b4c2b3..9778df135717 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -407,16 +407,27 @@ struct afs_server {
407 rwlock_t fs_lock; /* access lock */ 407 rwlock_t fs_lock; /* access lock */
408 408
409 /* callback promise management */ 409 /* callback promise management */
410 struct list_head cb_interests; /* List of superblocks using this server */ 410 struct hlist_head cb_volumes; /* List of volume interests on this server */
411 unsigned cb_s_break; /* Break-everything counter. */ 411 unsigned cb_s_break; /* Break-everything counter. */
412 rwlock_t cb_break_lock; /* Volume finding lock */ 412 rwlock_t cb_break_lock; /* Volume finding lock */
413}; 413};
414 414
415/* 415/*
416 * Volume collation in the server's callback interest list.
417 */
418struct afs_vol_interest {
419 struct hlist_node srv_link; /* Link in server->cb_volumes */
420 struct hlist_head cb_interests; /* List of callback interests on the server */
421 afs_volid_t vid; /* Volume ID to match */
422 unsigned int usage;
423};
424
425/*
416 * Interest by a superblock on a server. 426 * Interest by a superblock on a server.
417 */ 427 */
418struct afs_cb_interest { 428struct afs_cb_interest {
419 struct list_head cb_link; /* Link in server->cb_interests */ 429 struct hlist_node cb_vlink; /* Link in vol_interest->cb_interests */
430 struct afs_vol_interest *vol_interest;
420 struct afs_server *server; /* Server on which this interest resides */ 431 struct afs_server *server; /* Server on which this interest resides */
421 struct super_block *sb; /* Superblock on which inodes reside */ 432 struct super_block *sb; /* Superblock on which inodes reside */
422 afs_volid_t vid; /* Volume ID to match */ 433 afs_volid_t vid; /* Volume ID to match */
diff --git a/fs/afs/server.c b/fs/afs/server.c
index 3af4625e2f8c..1d329e6981d5 100644
--- a/fs/afs/server.c
+++ b/fs/afs/server.c
@@ -228,7 +228,7 @@ static struct afs_server *afs_alloc_server(struct afs_net *net,
228 server->flags = (1UL << AFS_SERVER_FL_NEW); 228 server->flags = (1UL << AFS_SERVER_FL_NEW);
229 server->update_at = ktime_get_real_seconds() + afs_server_update_delay; 229 server->update_at = ktime_get_real_seconds() + afs_server_update_delay;
230 rwlock_init(&server->fs_lock); 230 rwlock_init(&server->fs_lock);
231 INIT_LIST_HEAD(&server->cb_interests); 231 INIT_HLIST_HEAD(&server->cb_volumes);
232 rwlock_init(&server->cb_break_lock); 232 rwlock_init(&server->cb_break_lock);
233 233
234 afs_inc_servers_outstanding(net); 234 afs_inc_servers_outstanding(net);