diff options
Diffstat (limited to 'fs/afs/callback.c')
-rw-r--r-- | fs/afs/callback.c | 84 |
1 files changed, 61 insertions, 23 deletions
diff --git a/fs/afs/callback.c b/fs/afs/callback.c index abd9a84f4e88..571437dcb252 100644 --- a/fs/afs/callback.c +++ b/fs/afs/callback.c | |||
@@ -23,36 +23,55 @@ | |||
23 | /* | 23 | /* |
24 | * Set up an interest-in-callbacks record for a volume on a server and | 24 | * Set up an interest-in-callbacks record for a volume on a server and |
25 | * register it with the server. | 25 | * register it with the server. |
26 | * - Called with volume->server_sem held. | 26 | * - Called with vnode->io_lock held. |
27 | */ | 27 | */ |
28 | int afs_register_server_cb_interest(struct afs_vnode *vnode, | 28 | int afs_register_server_cb_interest(struct afs_vnode *vnode, |
29 | struct afs_server_entry *entry) | 29 | struct afs_server_list *slist, |
30 | unsigned int index) | ||
30 | { | 31 | { |
31 | struct afs_cb_interest *cbi = entry->cb_interest, *vcbi, *new, *x; | 32 | struct afs_server_entry *entry = &slist->servers[index]; |
33 | struct afs_cb_interest *cbi, *vcbi, *new, *old; | ||
32 | struct afs_server *server = entry->server; | 34 | struct afs_server *server = entry->server; |
33 | 35 | ||
34 | again: | 36 | again: |
37 | if (vnode->cb_interest && | ||
38 | likely(vnode->cb_interest == entry->cb_interest)) | ||
39 | return 0; | ||
40 | |||
41 | read_lock(&slist->lock); | ||
42 | cbi = afs_get_cb_interest(entry->cb_interest); | ||
43 | read_unlock(&slist->lock); | ||
44 | |||
35 | vcbi = vnode->cb_interest; | 45 | vcbi = vnode->cb_interest; |
36 | if (vcbi) { | 46 | if (vcbi) { |
37 | if (vcbi == cbi) | 47 | if (vcbi == cbi) { |
48 | afs_put_cb_interest(afs_v2net(vnode), cbi); | ||
38 | return 0; | 49 | return 0; |
50 | } | ||
39 | 51 | ||
52 | /* Use a new interest in the server list for the same server | ||
53 | * rather than an old one that's still attached to a vnode. | ||
54 | */ | ||
40 | if (cbi && vcbi->server == cbi->server) { | 55 | if (cbi && vcbi->server == cbi->server) { |
41 | write_seqlock(&vnode->cb_lock); | 56 | write_seqlock(&vnode->cb_lock); |
42 | vnode->cb_interest = afs_get_cb_interest(cbi); | 57 | old = vnode->cb_interest; |
58 | vnode->cb_interest = cbi; | ||
43 | write_sequnlock(&vnode->cb_lock); | 59 | write_sequnlock(&vnode->cb_lock); |
44 | afs_put_cb_interest(afs_v2net(vnode), cbi); | 60 | afs_put_cb_interest(afs_v2net(vnode), old); |
45 | return 0; | 61 | return 0; |
46 | } | 62 | } |
47 | 63 | ||
64 | /* Re-use the one attached to the vnode. */ | ||
48 | if (!cbi && vcbi->server == server) { | 65 | if (!cbi && vcbi->server == server) { |
49 | afs_get_cb_interest(vcbi); | 66 | write_lock(&slist->lock); |
50 | x = cmpxchg(&entry->cb_interest, cbi, vcbi); | 67 | if (entry->cb_interest) { |
51 | if (x != cbi) { | 68 | write_unlock(&slist->lock); |
52 | cbi = x; | 69 | afs_put_cb_interest(afs_v2net(vnode), cbi); |
53 | afs_put_cb_interest(afs_v2net(vnode), vcbi); | ||
54 | goto again; | 70 | goto again; |
55 | } | 71 | } |
72 | |||
73 | entry->cb_interest = cbi; | ||
74 | write_unlock(&slist->lock); | ||
56 | return 0; | 75 | return 0; |
57 | } | 76 | } |
58 | } | 77 | } |
@@ -72,13 +91,16 @@ again: | |||
72 | list_add_tail(&new->cb_link, &server->cb_interests); | 91 | list_add_tail(&new->cb_link, &server->cb_interests); |
73 | write_unlock(&server->cb_break_lock); | 92 | write_unlock(&server->cb_break_lock); |
74 | 93 | ||
75 | x = cmpxchg(&entry->cb_interest, cbi, new); | 94 | write_lock(&slist->lock); |
76 | if (x == cbi) { | 95 | if (!entry->cb_interest) { |
96 | entry->cb_interest = afs_get_cb_interest(new); | ||
77 | cbi = new; | 97 | cbi = new; |
98 | new = NULL; | ||
78 | } else { | 99 | } else { |
79 | cbi = x; | 100 | cbi = afs_get_cb_interest(entry->cb_interest); |
80 | afs_put_cb_interest(afs_v2net(vnode), new); | ||
81 | } | 101 | } |
102 | write_unlock(&slist->lock); | ||
103 | afs_put_cb_interest(afs_v2net(vnode), new); | ||
82 | } | 104 | } |
83 | 105 | ||
84 | ASSERT(cbi); | 106 | ASSERT(cbi); |
@@ -88,11 +110,14 @@ again: | |||
88 | */ | 110 | */ |
89 | write_seqlock(&vnode->cb_lock); | 111 | write_seqlock(&vnode->cb_lock); |
90 | 112 | ||
91 | vnode->cb_interest = afs_get_cb_interest(cbi); | 113 | old = vnode->cb_interest; |
114 | vnode->cb_interest = cbi; | ||
92 | vnode->cb_s_break = cbi->server->cb_s_break; | 115 | vnode->cb_s_break = cbi->server->cb_s_break; |
116 | vnode->cb_v_break = vnode->volume->cb_v_break; | ||
93 | clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags); | 117 | clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags); |
94 | 118 | ||
95 | write_sequnlock(&vnode->cb_lock); | 119 | write_sequnlock(&vnode->cb_lock); |
120 | afs_put_cb_interest(afs_v2net(vnode), old); | ||
96 | return 0; | 121 | return 0; |
97 | } | 122 | } |
98 | 123 | ||
@@ -171,13 +196,24 @@ static void afs_break_one_callback(struct afs_server *server, | |||
171 | if (cbi->vid != fid->vid) | 196 | if (cbi->vid != fid->vid) |
172 | continue; | 197 | continue; |
173 | 198 | ||
174 | data.volume = NULL; | 199 | if (fid->vnode == 0 && fid->unique == 0) { |
175 | data.fid = *fid; | 200 | /* The callback break applies to an entire volume. */ |
176 | inode = ilookup5_nowait(cbi->sb, fid->vnode, afs_iget5_test, &data); | 201 | struct afs_super_info *as = AFS_FS_S(cbi->sb); |
177 | if (inode) { | 202 | struct afs_volume *volume = as->volume; |
178 | vnode = AFS_FS_I(inode); | 203 | |
179 | afs_break_callback(vnode); | 204 | write_lock(&volume->cb_break_lock); |
180 | iput(inode); | 205 | volume->cb_v_break++; |
206 | write_unlock(&volume->cb_break_lock); | ||
207 | } else { | ||
208 | data.volume = NULL; | ||
209 | data.fid = *fid; | ||
210 | inode = ilookup5_nowait(cbi->sb, fid->vnode, | ||
211 | afs_iget5_test, &data); | ||
212 | if (inode) { | ||
213 | vnode = AFS_FS_I(inode); | ||
214 | afs_break_callback(vnode); | ||
215 | iput(inode); | ||
216 | } | ||
181 | } | 217 | } |
182 | } | 218 | } |
183 | 219 | ||
@@ -195,6 +231,8 @@ void afs_break_callbacks(struct afs_server *server, size_t count, | |||
195 | ASSERT(server != NULL); | 231 | ASSERT(server != NULL); |
196 | ASSERTCMP(count, <=, AFSCBMAX); | 232 | ASSERTCMP(count, <=, AFSCBMAX); |
197 | 233 | ||
234 | /* TODO: Sort the callback break list by volume ID */ | ||
235 | |||
198 | for (; count > 0; callbacks++, count--) { | 236 | for (; count > 0; callbacks++, count--) { |
199 | _debug("- Fid { vl=%08x n=%u u=%u } CB { v=%u x=%u t=%u }", | 237 | _debug("- Fid { vl=%08x n=%u u=%u } CB { v=%u x=%u t=%u }", |
200 | callbacks->fid.vid, | 238 | callbacks->fid.vid, |