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 clear_bit(AFS_VNODE_NEW_CONTENT, &vnode->flags); 218 if (test_and_clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) { 219 vnode->cb_break++; 220 afs_clear_permits(vnode); 221 222 spin_lock(&vnode->lock); 223 224 _debug("break callback"); 225 226 if (list_empty(&vnode->granted_locks) && 227 !list_empty(&vnode->pending_locks)) 228 afs_lock_may_be_available(vnode); 229 spin_unlock(&vnode->lock); 230 } 231 } 232 233 void afs_break_callback(struct afs_vnode *vnode) 234 { 235 write_seqlock(&vnode->cb_lock); 236 __afs_break_callback(vnode); 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_break_lock); 283 volume->cb_v_break++; 284 write_unlock(&volume->cb_break_lock); 285 } else { 286 data.volume = NULL; 287 data.fid = *fid; 288 inode = ilookup5_nowait(cbi->sb, fid->vnode, 289 afs_iget5_test, &data); 290 if (inode) { 291 vnode = AFS_FS_I(inode); 292 afs_break_callback(vnode); 293 iput(inode); 294 } 295 } 296 } 297 298 out: 299 read_unlock(&server->cb_break_lock); 300 } 301 302 /* 303 * allow the fileserver to break callback promises 304 */ 305 void afs_break_callbacks(struct afs_server *server, size_t count, 306 struct afs_callback_break *callbacks) 307 { 308 _enter("%p,%zu,", server, count); 309 310 ASSERT(server != NULL); 311 ASSERTCMP(count, <=, AFSCBMAX); 312 313 /* TODO: Sort the callback break list by volume ID */ 314 315 for (; count > 0; callbacks++, count--) { 316 _debug("- Fid { vl=%08llx n=%llu u=%u }", 317 callbacks->fid.vid, 318 callbacks->fid.vnode, 319 callbacks->fid.unique); 320 afs_break_one_callback(server, &callbacks->fid); 321 } 322 323 _leave(""); 324 return; 325 } 326 327 /* 328 * Clear the callback interests in a server list. 329 */ 330 void afs_clear_callback_interests(struct afs_net *net, struct afs_server_list *slist) 331 { 332 int i; 333 334 for (i = 0; i < slist->nr_servers; i++) { 335 afs_put_cb_interest(net, slist->servers[i].cb_interest); 336 slist->servers[i].cb_interest = NULL; 337 } 338 } 339