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 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); 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) 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 } 228 229 void afs_break_callback(struct afs_vnode *vnode) 230 { 231 write_seqlock(&vnode->cb_lock); 232 __afs_break_callback(vnode); 233 write_sequnlock(&vnode->cb_lock); 234 } 235 236 /* 237 * allow the fileserver to explicitly break one callback 238 * - happens when 239 * - the backing file is changed 240 * - a lock is released 241 */ 242 static void afs_break_one_callback(struct afs_server *server, 243 struct afs_fid *fid) 244 { 245 struct afs_vol_interest *vi; 246 struct afs_cb_interest *cbi; 247 struct afs_iget_data data; 248 struct afs_vnode *vnode; 249 struct inode *inode; 250 251 read_lock(&server->cb_break_lock); 252 hlist_for_each_entry(vi, &server->cb_volumes, srv_link) { 253 if (vi->vid < fid->vid) 254 continue; 255 if (vi->vid > fid->vid) { 256 vi = NULL; 257 break; 258 } 259 //atomic_inc(&vi->usage); 260 break; 261 } 262 263 /* TODO: Find all matching volumes if we couldn't match the server and 264 * break them anyway. 265 */ 266 if (!vi) 267 goto out; 268 269 /* Step through all interested superblocks. There may be more than one 270 * because of cell aliasing. 271 */ 272 hlist_for_each_entry(cbi, &vi->cb_interests, cb_vlink) { 273 if (fid->vnode == 0 && fid->unique == 0) { 274 /* The callback break applies to an entire volume. */ 275 struct afs_super_info *as = AFS_FS_S(cbi->sb); 276 struct afs_volume *volume = as->volume; 277 278 write_lock(&volume->cb_break_lock); 279 volume->cb_v_break++; 280 write_unlock(&volume->cb_break_lock); 281 } else { 282 data.volume = NULL; 283 data.fid = *fid; 284 inode = ilookup5_nowait(cbi->sb, fid->vnode, 285 afs_iget5_test, &data); 286 if (inode) { 287 vnode = AFS_FS_I(inode); 288 afs_break_callback(vnode); 289 iput(inode); 290 } 291 } 292 } 293 294 out: 295 read_unlock(&server->cb_break_lock); 296 } 297 298 /* 299 * allow the fileserver to break callback promises 300 */ 301 void afs_break_callbacks(struct afs_server *server, size_t count, 302 struct afs_callback_break *callbacks) 303 { 304 _enter("%p,%zu,", server, count); 305 306 ASSERT(server != NULL); 307 ASSERTCMP(count, <=, AFSCBMAX); 308 309 /* TODO: Sort the callback break list by volume ID */ 310 311 for (; count > 0; callbacks++, count--) { 312 _debug("- Fid { vl=%08llx n=%llu u=%u }", 313 callbacks->fid.vid, 314 callbacks->fid.vnode, 315 callbacks->fid.unique); 316 afs_break_one_callback(server, &callbacks->fid); 317 } 318 319 _leave(""); 320 return; 321 } 322 323 /* 324 * Clear the callback interests in a server list. 325 */ 326 void afs_clear_callback_interests(struct afs_net *net, struct afs_server_list *slist) 327 { 328 int i; 329 330 for (i = 0; i < slist->nr_servers; i++) { 331 afs_put_cb_interest(net, slist->servers[i].cb_interest); 332 slist->servers[i].cb_interest = NULL; 333 } 334 } 335