1 /* 2 * Copyright (c) 2002, 2007 Red Hat, Inc. All rights reserved. 3 * 4 * This software may be freely redistributed under the terms of the 5 * GNU General Public License. 6 * 7 * You should have received a copy of the GNU General Public License 8 * along with this program; if not, write to the Free Software 9 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 10 * 11 * Authors: David Woodhouse <dwmw2@infradead.org> 12 * David Howells <dhowells@redhat.com> 13 * 14 */ 15 16 #include <linux/kernel.h> 17 #include <linux/module.h> 18 #include <linux/init.h> 19 #include <linux/circ_buf.h> 20 #include <linux/sched.h> 21 #include "internal.h" 22 23 /* 24 * Create volume and callback interests on a server. 25 */ 26 static 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, afs_server_trace_get_new_cbi); 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; 73 found_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 /* 84 * Set up an interest-in-callbacks record for a volume on a server and 85 * register it with the server. 86 * - Called with vnode->io_lock held. 87 */ 88 int afs_register_server_cb_interest(struct afs_vnode *vnode, 89 struct afs_server_list *slist, 90 unsigned int index) 91 { 92 struct afs_server_entry *entry = &slist->servers[index]; 93 struct afs_cb_interest *cbi, *vcbi, *new, *old; 94 struct afs_server *server = entry->server; 95 96 again: 97 vcbi = rcu_dereference_protected(vnode->cb_interest, 98 lockdep_is_held(&vnode->io_lock)); 99 if (vcbi && likely(vcbi == entry->cb_interest)) 100 return 0; 101 102 read_lock(&slist->lock); 103 cbi = afs_get_cb_interest(entry->cb_interest); 104 read_unlock(&slist->lock); 105 106 if (vcbi) { 107 if (vcbi == cbi) { 108 afs_put_cb_interest(afs_v2net(vnode), cbi); 109 return 0; 110 } 111 112 /* Use a new interest in the server list for the same server 113 * rather than an old one that's still attached to a vnode. 114 */ 115 if (cbi && vcbi->server == cbi->server) { 116 write_seqlock(&vnode->cb_lock); 117 old = rcu_dereference_protected(vnode->cb_interest, 118 lockdep_is_held(&vnode->cb_lock.lock)); 119 rcu_assign_pointer(vnode->cb_interest, cbi); 120 write_sequnlock(&vnode->cb_lock); 121 afs_put_cb_interest(afs_v2net(vnode), old); 122 return 0; 123 } 124 125 /* Re-use the one attached to the vnode. */ 126 if (!cbi && vcbi->server == server) { 127 write_lock(&slist->lock); 128 if (entry->cb_interest) { 129 write_unlock(&slist->lock); 130 afs_put_cb_interest(afs_v2net(vnode), cbi); 131 goto again; 132 } 133 134 entry->cb_interest = cbi; 135 write_unlock(&slist->lock); 136 return 0; 137 } 138 } 139 140 if (!cbi) { 141 new = afs_create_interest(server, vnode); 142 if (!new) 143 return -ENOMEM; 144 145 write_lock(&slist->lock); 146 if (!entry->cb_interest) { 147 entry->cb_interest = afs_get_cb_interest(new); 148 cbi = new; 149 new = NULL; 150 } else { 151 cbi = afs_get_cb_interest(entry->cb_interest); 152 } 153 write_unlock(&slist->lock); 154 afs_put_cb_interest(afs_v2net(vnode), new); 155 } 156 157 ASSERT(cbi); 158 159 /* Change the server the vnode is using. This entails scrubbing any 160 * interest the vnode had in the previous server it was using. 161 */ 162 write_seqlock(&vnode->cb_lock); 163 164 old = rcu_dereference_protected(vnode->cb_interest, 165 lockdep_is_held(&vnode->cb_lock.lock)); 166 rcu_assign_pointer(vnode->cb_interest, cbi); 167 vnode->cb_s_break = cbi->server->cb_s_break; 168 vnode->cb_v_break = vnode->volume->cb_v_break; 169 clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags); 170 171 write_sequnlock(&vnode->cb_lock); 172 afs_put_cb_interest(afs_v2net(vnode), old); 173 return 0; 174 } 175 176 /* 177 * Remove an interest on a server. 178 */ 179 void afs_put_cb_interest(struct afs_net *net, struct afs_cb_interest *cbi) 180 { 181 struct afs_vol_interest *vi; 182 183 if (cbi && refcount_dec_and_test(&cbi->usage)) { 184 if (!hlist_unhashed(&cbi->cb_vlink)) { 185 write_lock(&cbi->server->cb_break_lock); 186 187 hlist_del_init(&cbi->cb_vlink); 188 vi = cbi->vol_interest; 189 cbi->vol_interest = NULL; 190 if (--vi->usage == 0) 191 hlist_del(&vi->srv_link); 192 else 193 vi = NULL; 194 195 write_unlock(&cbi->server->cb_break_lock); 196 if (vi) 197 kfree_rcu(vi, rcu); 198 afs_put_server(net, cbi->server, afs_server_trace_put_cbi); 199 } 200 kfree_rcu(cbi, rcu); 201 } 202 } 203 204 /* 205 * allow the fileserver to request callback state (re-)initialisation 206 */ 207 void afs_init_callback_state(struct afs_server *server) 208 { 209 server->cb_s_break++; 210 } 211 212 /* 213 * actually break a callback 214 */ 215 void __afs_break_callback(struct afs_vnode *vnode, enum afs_cb_break_reason reason) 216 { 217 _enter(""); 218 219 clear_bit(AFS_VNODE_NEW_CONTENT, &vnode->flags); 220 if (test_and_clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) { 221 vnode->cb_break++; 222 afs_clear_permits(vnode); 223 224 if (vnode->lock_state == AFS_VNODE_LOCK_WAITING_FOR_CB) 225 afs_lock_may_be_available(vnode); 226 227 trace_afs_cb_break(&vnode->fid, vnode->cb_break, reason, true); 228 } else { 229 trace_afs_cb_break(&vnode->fid, vnode->cb_break, reason, false); 230 } 231 } 232 233 void afs_break_callback(struct afs_vnode *vnode, enum afs_cb_break_reason reason) 234 { 235 write_seqlock(&vnode->cb_lock); 236 __afs_break_callback(vnode, reason); 237 write_sequnlock(&vnode->cb_lock); 238 } 239 240 /* 241 * allow the fileserver to explicitly break one callback 242 * - happens when 243 * - the backing file is changed 244 * - a lock is released 245 */ 246 static void afs_break_one_callback(struct afs_server *server, 247 struct afs_fid *fid) 248 { 249 struct afs_vol_interest *vi; 250 struct afs_cb_interest *cbi; 251 struct afs_iget_data data; 252 struct afs_vnode *vnode; 253 struct inode *inode; 254 255 read_lock(&server->cb_break_lock); 256 hlist_for_each_entry(vi, &server->cb_volumes, srv_link) { 257 if (vi->vid < fid->vid) 258 continue; 259 if (vi->vid > fid->vid) { 260 vi = NULL; 261 break; 262 } 263 //atomic_inc(&vi->usage); 264 break; 265 } 266 267 /* TODO: Find all matching volumes if we couldn't match the server and 268 * break them anyway. 269 */ 270 if (!vi) 271 goto out; 272 273 /* Step through all interested superblocks. There may be more than one 274 * because of cell aliasing. 275 */ 276 hlist_for_each_entry(cbi, &vi->cb_interests, cb_vlink) { 277 if (fid->vnode == 0 && fid->unique == 0) { 278 /* The callback break applies to an entire volume. */ 279 struct afs_super_info *as = AFS_FS_S(cbi->sb); 280 struct afs_volume *volume = as->volume; 281 282 write_lock(&volume->cb_v_break_lock); 283 volume->cb_v_break++; 284 trace_afs_cb_break(fid, volume->cb_v_break, 285 afs_cb_break_for_volume_callback, false); 286 write_unlock(&volume->cb_v_break_lock); 287 } else { 288 data.volume = NULL; 289 data.fid = *fid; 290 inode = ilookup5_nowait(cbi->sb, fid->vnode, 291 afs_iget5_test, &data); 292 if (inode) { 293 vnode = AFS_FS_I(inode); 294 afs_break_callback(vnode, afs_cb_break_for_callback); 295 iput(inode); 296 } else { 297 trace_afs_cb_miss(fid, afs_cb_break_for_callback); 298 } 299 } 300 } 301 302 out: 303 read_unlock(&server->cb_break_lock); 304 } 305 306 /* 307 * allow the fileserver to break callback promises 308 */ 309 void afs_break_callbacks(struct afs_server *server, size_t count, 310 struct afs_callback_break *callbacks) 311 { 312 _enter("%p,%zu,", server, count); 313 314 ASSERT(server != NULL); 315 316 /* TODO: Sort the callback break list by volume ID */ 317 318 for (; count > 0; callbacks++, count--) { 319 _debug("- Fid { vl=%08llx n=%llu u=%u }", 320 callbacks->fid.vid, 321 callbacks->fid.vnode, 322 callbacks->fid.unique); 323 afs_break_one_callback(server, &callbacks->fid); 324 } 325 326 _leave(""); 327 return; 328 } 329 330 /* 331 * Clear the callback interests in a server list. 332 */ 333 void afs_clear_callback_interests(struct afs_net *net, struct afs_server_list *slist) 334 { 335 int i; 336 337 for (i = 0; i < slist->nr_servers; i++) { 338 afs_put_cb_interest(net, slist->servers[i].cb_interest); 339 slist->servers[i].cb_interest = NULL; 340 } 341 } 342