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 * Set up an interest-in-callbacks record for a volume on a server and 25 * register it with the server. 26 * - Called with vnode->io_lock held. 27 */ 28 int afs_register_server_cb_interest(struct afs_vnode *vnode, 29 struct afs_server_list *slist, 30 unsigned int index) 31 { 32 struct afs_server_entry *entry = &slist->servers[index]; 33 struct afs_cb_interest *cbi, *vcbi, *new, *old; 34 struct afs_server *server = entry->server; 35 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 45 vcbi = vnode->cb_interest; 46 if (vcbi) { 47 if (vcbi == cbi) { 48 afs_put_cb_interest(afs_v2net(vnode), cbi); 49 return 0; 50 } 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 */ 55 if (cbi && vcbi->server == cbi->server) { 56 write_seqlock(&vnode->cb_lock); 57 old = vnode->cb_interest; 58 vnode->cb_interest = cbi; 59 write_sequnlock(&vnode->cb_lock); 60 afs_put_cb_interest(afs_v2net(vnode), old); 61 return 0; 62 } 63 64 /* Re-use the one attached to the vnode. */ 65 if (!cbi && vcbi->server == server) { 66 write_lock(&slist->lock); 67 if (entry->cb_interest) { 68 write_unlock(&slist->lock); 69 afs_put_cb_interest(afs_v2net(vnode), cbi); 70 goto again; 71 } 72 73 entry->cb_interest = cbi; 74 write_unlock(&slist->lock); 75 return 0; 76 } 77 } 78 79 if (!cbi) { 80 new = kzalloc(sizeof(struct afs_cb_interest), GFP_KERNEL); 81 if (!new) 82 return -ENOMEM; 83 84 refcount_set(&new->usage, 1); 85 new->sb = vnode->vfs_inode.i_sb; 86 new->vid = vnode->volume->vid; 87 new->server = afs_get_server(server); 88 INIT_LIST_HEAD(&new->cb_link); 89 90 write_lock(&server->cb_break_lock); 91 list_add_tail(&new->cb_link, &server->cb_interests); 92 write_unlock(&server->cb_break_lock); 93 94 write_lock(&slist->lock); 95 if (!entry->cb_interest) { 96 entry->cb_interest = afs_get_cb_interest(new); 97 cbi = new; 98 new = NULL; 99 } else { 100 cbi = afs_get_cb_interest(entry->cb_interest); 101 } 102 write_unlock(&slist->lock); 103 afs_put_cb_interest(afs_v2net(vnode), new); 104 } 105 106 ASSERT(cbi); 107 108 /* Change the server the vnode is using. This entails scrubbing any 109 * interest the vnode had in the previous server it was using. 110 */ 111 write_seqlock(&vnode->cb_lock); 112 113 old = vnode->cb_interest; 114 vnode->cb_interest = cbi; 115 vnode->cb_s_break = cbi->server->cb_s_break; 116 vnode->cb_v_break = vnode->volume->cb_v_break; 117 clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags); 118 119 write_sequnlock(&vnode->cb_lock); 120 afs_put_cb_interest(afs_v2net(vnode), old); 121 return 0; 122 } 123 124 /* 125 * Remove an interest on a server. 126 */ 127 void afs_put_cb_interest(struct afs_net *net, struct afs_cb_interest *cbi) 128 { 129 if (cbi && refcount_dec_and_test(&cbi->usage)) { 130 if (!list_empty(&cbi->cb_link)) { 131 write_lock(&cbi->server->cb_break_lock); 132 list_del_init(&cbi->cb_link); 133 write_unlock(&cbi->server->cb_break_lock); 134 afs_put_server(net, cbi->server); 135 } 136 kfree(cbi); 137 } 138 } 139 140 /* 141 * allow the fileserver to request callback state (re-)initialisation 142 */ 143 void afs_init_callback_state(struct afs_server *server) 144 { 145 if (!test_and_clear_bit(AFS_SERVER_FL_NEW, &server->flags)) 146 server->cb_s_break++; 147 } 148 149 /* 150 * actually break a callback 151 */ 152 void afs_break_callback(struct afs_vnode *vnode) 153 { 154 _enter(""); 155 156 write_seqlock(&vnode->cb_lock); 157 158 clear_bit(AFS_VNODE_NEW_CONTENT, &vnode->flags); 159 if (test_and_clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) { 160 vnode->cb_break++; 161 afs_clear_permits(vnode); 162 163 spin_lock(&vnode->lock); 164 165 _debug("break callback"); 166 167 if (list_empty(&vnode->granted_locks) && 168 !list_empty(&vnode->pending_locks)) 169 afs_lock_may_be_available(vnode); 170 spin_unlock(&vnode->lock); 171 } 172 173 write_sequnlock(&vnode->cb_lock); 174 } 175 176 /* 177 * allow the fileserver to explicitly break one callback 178 * - happens when 179 * - the backing file is changed 180 * - a lock is released 181 */ 182 static void afs_break_one_callback(struct afs_server *server, 183 struct afs_fid *fid) 184 { 185 struct afs_cb_interest *cbi; 186 struct afs_iget_data data; 187 struct afs_vnode *vnode; 188 struct inode *inode; 189 190 read_lock(&server->cb_break_lock); 191 192 /* Step through all interested superblocks. There may be more than one 193 * because of cell aliasing. 194 */ 195 list_for_each_entry(cbi, &server->cb_interests, cb_link) { 196 if (cbi->vid != fid->vid) 197 continue; 198 199 if (fid->vnode == 0 && fid->unique == 0) { 200 /* The callback break applies to an entire volume. */ 201 struct afs_super_info *as = AFS_FS_S(cbi->sb); 202 struct afs_volume *volume = as->volume; 203 204 write_lock(&volume->cb_break_lock); 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 } 217 } 218 } 219 220 read_unlock(&server->cb_break_lock); 221 } 222 223 /* 224 * allow the fileserver to break callback promises 225 */ 226 void afs_break_callbacks(struct afs_server *server, size_t count, 227 struct afs_callback_break *callbacks) 228 { 229 _enter("%p,%zu,", server, count); 230 231 ASSERT(server != NULL); 232 ASSERTCMP(count, <=, AFSCBMAX); 233 234 /* TODO: Sort the callback break list by volume ID */ 235 236 for (; count > 0; callbacks++, count--) { 237 _debug("- Fid { vl=%08x n=%u u=%u } CB { v=%u x=%u t=%u }", 238 callbacks->fid.vid, 239 callbacks->fid.vnode, 240 callbacks->fid.unique, 241 callbacks->cb.version, 242 callbacks->cb.expiry, 243 callbacks->cb.type 244 ); 245 afs_break_one_callback(server, &callbacks->fid); 246 } 247 248 _leave(""); 249 return; 250 } 251 252 /* 253 * Clear the callback interests in a server list. 254 */ 255 void afs_clear_callback_interests(struct afs_net *net, struct afs_server_list *slist) 256 { 257 int i; 258 259 for (i = 0; i < slist->nr_servers; i++) { 260 afs_put_cb_interest(net, slist->servers[i].cb_interest); 261 slist->servers[i].cb_interest = NULL; 262 } 263 } 264