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); 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 if (vnode->cb_interest && 98 likely(vnode->cb_interest == entry->cb_interest)) 99 return 0; 100 101 read_lock(&slist->lock); 102 cbi = afs_get_cb_interest(entry->cb_interest); 103 read_unlock(&slist->lock); 104 105 vcbi = vnode->cb_interest; 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 = vnode->cb_interest; 118 vnode->cb_interest = cbi; 119 write_sequnlock(&vnode->cb_lock); 120 afs_put_cb_interest(afs_v2net(vnode), old); 121 return 0; 122 } 123 124 /* Re-use the one attached to the vnode. */ 125 if (!cbi && vcbi->server == server) { 126 write_lock(&slist->lock); 127 if (entry->cb_interest) { 128 write_unlock(&slist->lock); 129 afs_put_cb_interest(afs_v2net(vnode), cbi); 130 goto again; 131 } 132 133 entry->cb_interest = cbi; 134 write_unlock(&slist->lock); 135 return 0; 136 } 137 } 138 139 if (!cbi) { 140 new = afs_create_interest(server, vnode); 141 if (!new) 142 return -ENOMEM; 143 144 write_lock(&slist->lock); 145 if (!entry->cb_interest) { 146 entry->cb_interest = afs_get_cb_interest(new); 147 cbi = new; 148 new = NULL; 149 } else { 150 cbi = afs_get_cb_interest(entry->cb_interest); 151 } 152 write_unlock(&slist->lock); 153 afs_put_cb_interest(afs_v2net(vnode), new); 154 } 155 156 ASSERT(cbi); 157 158 /* Change the server the vnode is using. This entails scrubbing any 159 * interest the vnode had in the previous server it was using. 160 */ 161 write_seqlock(&vnode->cb_lock); 162 163 old = vnode->cb_interest; 164 vnode->cb_interest = cbi; 165 vnode->cb_s_break = cbi->server->cb_s_break; 166 vnode->cb_v_break = vnode->volume->cb_v_break; 167 clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags); 168 169 write_sequnlock(&vnode->cb_lock); 170 afs_put_cb_interest(afs_v2net(vnode), old); 171 return 0; 172 } 173 174 /* 175 * Remove an interest on a server. 176 */ 177 void afs_put_cb_interest(struct afs_net *net, struct afs_cb_interest *cbi) 178 { 179 struct afs_vol_interest *vi; 180 181 if (cbi && refcount_dec_and_test(&cbi->usage)) { 182 if (!hlist_unhashed(&cbi->cb_vlink)) { 183 write_lock(&cbi->server->cb_break_lock); 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 193 write_unlock(&cbi->server->cb_break_lock); 194 kfree(vi); 195 afs_put_server(net, cbi->server); 196 } 197 kfree(cbi); 198 } 199 } 200 201 /* 202 * allow the fileserver to request callback state (re-)initialisation 203 */ 204 void afs_init_callback_state(struct afs_server *server) 205 { 206 if (!test_and_clear_bit(AFS_SERVER_FL_NEW, &server->flags)) 207 server->cb_s_break++; 208 } 209 210 /* 211 * actually break a callback 212 */ 213 void afs_break_callback(struct afs_vnode *vnode) 214 { 215 _enter(""); 216 217 write_seqlock(&vnode->cb_lock); 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 spin_lock(&vnode->lock); 225 226 _debug("break callback"); 227 228 if (list_empty(&vnode->granted_locks) && 229 !list_empty(&vnode->pending_locks)) 230 afs_lock_may_be_available(vnode); 231 spin_unlock(&vnode->lock); 232 } 233 234 write_sequnlock(&vnode->cb_lock); 235 } 236 237 /* 238 * allow the fileserver to explicitly break one callback 239 * - happens when 240 * - the backing file is changed 241 * - a lock is released 242 */ 243 static void afs_break_one_callback(struct afs_server *server, 244 struct afs_fid *fid) 245 { 246 struct afs_vol_interest *vi; 247 struct afs_cb_interest *cbi; 248 struct afs_iget_data data; 249 struct afs_vnode *vnode; 250 struct inode *inode; 251 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; 269 270 /* Step through all interested superblocks. There may be more than one 271 * because of cell aliasing. 272 */ 273 hlist_for_each_entry(cbi, &vi->cb_interests, cb_vlink) { 274 if (fid->vnode == 0 && fid->unique == 0) { 275 /* The callback break applies to an entire volume. */ 276 struct afs_super_info *as = AFS_FS_S(cbi->sb); 277 struct afs_volume *volume = as->volume; 278 279 write_lock(&volume->cb_break_lock); 280 volume->cb_v_break++; 281 write_unlock(&volume->cb_break_lock); 282 } else { 283 data.volume = NULL; 284 data.fid = *fid; 285 inode = ilookup5_nowait(cbi->sb, fid->vnode, 286 afs_iget5_test, &data); 287 if (inode) { 288 vnode = AFS_FS_I(inode); 289 afs_break_callback(vnode); 290 iput(inode); 291 } 292 } 293 } 294 295 out: 296 read_unlock(&server->cb_break_lock); 297 } 298 299 /* 300 * allow the fileserver to break callback promises 301 */ 302 void afs_break_callbacks(struct afs_server *server, size_t count, 303 struct afs_callback_break *callbacks) 304 { 305 _enter("%p,%zu,", server, count); 306 307 ASSERT(server != NULL); 308 ASSERTCMP(count, <=, AFSCBMAX); 309 310 /* TODO: Sort the callback break list by volume ID */ 311 312 for (; count > 0; callbacks++, count--) { 313 _debug("- Fid { vl=%08x n=%u u=%u } CB { v=%u x=%u t=%u }", 314 callbacks->fid.vid, 315 callbacks->fid.vnode, 316 callbacks->fid.unique, 317 callbacks->cb.version, 318 callbacks->cb.expiry, 319 callbacks->cb.type 320 ); 321 afs_break_one_callback(server, &callbacks->fid); 322 } 323 324 _leave(""); 325 return; 326 } 327 328 /* 329 * Clear the callback interests in a server list. 330 */ 331 void afs_clear_callback_interests(struct afs_net *net, struct afs_server_list *slist) 332 { 333 int i; 334 335 for (i = 0; i < slist->nr_servers; i++) { 336 afs_put_cb_interest(net, slist->servers[i].cb_interest); 337 slist->servers[i].cb_interest = NULL; 338 } 339 } 340