18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2002, 2007 Red Hat, Inc. All rights reserved. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * This software may be freely redistributed under the terms of the 58c2ecf20Sopenharmony_ci * GNU General Public License. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * You should have received a copy of the GNU General Public License 88c2ecf20Sopenharmony_ci * along with this program; if not, write to the Free Software 98c2ecf20Sopenharmony_ci * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Authors: David Woodhouse <dwmw2@infradead.org> 128c2ecf20Sopenharmony_ci * David Howells <dhowells@redhat.com> 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci */ 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <linux/kernel.h> 178c2ecf20Sopenharmony_ci#include <linux/module.h> 188c2ecf20Sopenharmony_ci#include <linux/init.h> 198c2ecf20Sopenharmony_ci#include <linux/circ_buf.h> 208c2ecf20Sopenharmony_ci#include <linux/sched.h> 218c2ecf20Sopenharmony_ci#include "internal.h" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci/* 248c2ecf20Sopenharmony_ci * Allow the fileserver to request callback state (re-)initialisation. 258c2ecf20Sopenharmony_ci * Unfortunately, UUIDs are not guaranteed unique. 268c2ecf20Sopenharmony_ci */ 278c2ecf20Sopenharmony_civoid afs_init_callback_state(struct afs_server *server) 288c2ecf20Sopenharmony_ci{ 298c2ecf20Sopenharmony_ci rcu_read_lock(); 308c2ecf20Sopenharmony_ci do { 318c2ecf20Sopenharmony_ci server->cb_s_break++; 328c2ecf20Sopenharmony_ci server = rcu_dereference(server->uuid_next); 338c2ecf20Sopenharmony_ci } while (0); 348c2ecf20Sopenharmony_ci rcu_read_unlock(); 358c2ecf20Sopenharmony_ci} 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci/* 388c2ecf20Sopenharmony_ci * actually break a callback 398c2ecf20Sopenharmony_ci */ 408c2ecf20Sopenharmony_civoid __afs_break_callback(struct afs_vnode *vnode, enum afs_cb_break_reason reason) 418c2ecf20Sopenharmony_ci{ 428c2ecf20Sopenharmony_ci _enter(""); 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci clear_bit(AFS_VNODE_NEW_CONTENT, &vnode->flags); 458c2ecf20Sopenharmony_ci if (test_and_clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) { 468c2ecf20Sopenharmony_ci vnode->cb_break++; 478c2ecf20Sopenharmony_ci afs_clear_permits(vnode); 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci if (vnode->lock_state == AFS_VNODE_LOCK_WAITING_FOR_CB) 508c2ecf20Sopenharmony_ci afs_lock_may_be_available(vnode); 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci trace_afs_cb_break(&vnode->fid, vnode->cb_break, reason, true); 538c2ecf20Sopenharmony_ci } else { 548c2ecf20Sopenharmony_ci trace_afs_cb_break(&vnode->fid, vnode->cb_break, reason, false); 558c2ecf20Sopenharmony_ci } 568c2ecf20Sopenharmony_ci} 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_civoid afs_break_callback(struct afs_vnode *vnode, enum afs_cb_break_reason reason) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci write_seqlock(&vnode->cb_lock); 618c2ecf20Sopenharmony_ci __afs_break_callback(vnode, reason); 628c2ecf20Sopenharmony_ci write_sequnlock(&vnode->cb_lock); 638c2ecf20Sopenharmony_ci} 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci/* 668c2ecf20Sopenharmony_ci * Look up a volume by volume ID under RCU conditions. 678c2ecf20Sopenharmony_ci */ 688c2ecf20Sopenharmony_cistatic struct afs_volume *afs_lookup_volume_rcu(struct afs_cell *cell, 698c2ecf20Sopenharmony_ci afs_volid_t vid) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci struct afs_volume *volume = NULL; 728c2ecf20Sopenharmony_ci struct rb_node *p; 738c2ecf20Sopenharmony_ci int seq = 1; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci do { 768c2ecf20Sopenharmony_ci /* Unfortunately, rbtree walking doesn't give reliable results 778c2ecf20Sopenharmony_ci * under just the RCU read lock, so we have to check for 788c2ecf20Sopenharmony_ci * changes. 798c2ecf20Sopenharmony_ci */ 808c2ecf20Sopenharmony_ci seq++; /* 2 on the 1st/lockless path, otherwise odd */ 818c2ecf20Sopenharmony_ci read_seqbegin_or_lock(&cell->volume_lock, &seq); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci p = rcu_dereference_raw(cell->volumes.rb_node); 848c2ecf20Sopenharmony_ci while (p) { 858c2ecf20Sopenharmony_ci volume = rb_entry(p, struct afs_volume, cell_node); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci if (volume->vid < vid) 888c2ecf20Sopenharmony_ci p = rcu_dereference_raw(p->rb_left); 898c2ecf20Sopenharmony_ci else if (volume->vid > vid) 908c2ecf20Sopenharmony_ci p = rcu_dereference_raw(p->rb_right); 918c2ecf20Sopenharmony_ci else 928c2ecf20Sopenharmony_ci break; 938c2ecf20Sopenharmony_ci volume = NULL; 948c2ecf20Sopenharmony_ci } 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci } while (need_seqretry(&cell->volume_lock, seq)); 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci done_seqretry(&cell->volume_lock, seq); 998c2ecf20Sopenharmony_ci return volume; 1008c2ecf20Sopenharmony_ci} 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci/* 1038c2ecf20Sopenharmony_ci * allow the fileserver to explicitly break one callback 1048c2ecf20Sopenharmony_ci * - happens when 1058c2ecf20Sopenharmony_ci * - the backing file is changed 1068c2ecf20Sopenharmony_ci * - a lock is released 1078c2ecf20Sopenharmony_ci */ 1088c2ecf20Sopenharmony_cistatic void afs_break_one_callback(struct afs_volume *volume, 1098c2ecf20Sopenharmony_ci struct afs_fid *fid) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci struct super_block *sb; 1128c2ecf20Sopenharmony_ci struct afs_vnode *vnode; 1138c2ecf20Sopenharmony_ci struct inode *inode; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci if (fid->vnode == 0 && fid->unique == 0) { 1168c2ecf20Sopenharmony_ci /* The callback break applies to an entire volume. */ 1178c2ecf20Sopenharmony_ci write_lock(&volume->cb_v_break_lock); 1188c2ecf20Sopenharmony_ci volume->cb_v_break++; 1198c2ecf20Sopenharmony_ci trace_afs_cb_break(fid, volume->cb_v_break, 1208c2ecf20Sopenharmony_ci afs_cb_break_for_volume_callback, false); 1218c2ecf20Sopenharmony_ci write_unlock(&volume->cb_v_break_lock); 1228c2ecf20Sopenharmony_ci return; 1238c2ecf20Sopenharmony_ci } 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci /* See if we can find a matching inode - even an I_NEW inode needs to 1268c2ecf20Sopenharmony_ci * be marked as it can have its callback broken before we finish 1278c2ecf20Sopenharmony_ci * setting up the local inode. 1288c2ecf20Sopenharmony_ci */ 1298c2ecf20Sopenharmony_ci sb = rcu_dereference(volume->sb); 1308c2ecf20Sopenharmony_ci if (!sb) 1318c2ecf20Sopenharmony_ci return; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci inode = find_inode_rcu(sb, fid->vnode, afs_ilookup5_test_by_fid, fid); 1348c2ecf20Sopenharmony_ci if (inode) { 1358c2ecf20Sopenharmony_ci vnode = AFS_FS_I(inode); 1368c2ecf20Sopenharmony_ci afs_break_callback(vnode, afs_cb_break_for_callback); 1378c2ecf20Sopenharmony_ci } else { 1388c2ecf20Sopenharmony_ci trace_afs_cb_miss(fid, afs_cb_break_for_callback); 1398c2ecf20Sopenharmony_ci } 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistatic void afs_break_some_callbacks(struct afs_server *server, 1438c2ecf20Sopenharmony_ci struct afs_callback_break *cbb, 1448c2ecf20Sopenharmony_ci size_t *_count) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci struct afs_callback_break *residue = cbb; 1478c2ecf20Sopenharmony_ci struct afs_volume *volume; 1488c2ecf20Sopenharmony_ci afs_volid_t vid = cbb->fid.vid; 1498c2ecf20Sopenharmony_ci size_t i; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci volume = afs_lookup_volume_rcu(server->cell, vid); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci /* TODO: Find all matching volumes if we couldn't match the server and 1548c2ecf20Sopenharmony_ci * break them anyway. 1558c2ecf20Sopenharmony_ci */ 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci for (i = *_count; i > 0; cbb++, i--) { 1588c2ecf20Sopenharmony_ci if (cbb->fid.vid == vid) { 1598c2ecf20Sopenharmony_ci _debug("- Fid { vl=%08llx n=%llu u=%u }", 1608c2ecf20Sopenharmony_ci cbb->fid.vid, 1618c2ecf20Sopenharmony_ci cbb->fid.vnode, 1628c2ecf20Sopenharmony_ci cbb->fid.unique); 1638c2ecf20Sopenharmony_ci --*_count; 1648c2ecf20Sopenharmony_ci if (volume) 1658c2ecf20Sopenharmony_ci afs_break_one_callback(volume, &cbb->fid); 1668c2ecf20Sopenharmony_ci } else { 1678c2ecf20Sopenharmony_ci *residue++ = *cbb; 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci } 1708c2ecf20Sopenharmony_ci} 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci/* 1738c2ecf20Sopenharmony_ci * allow the fileserver to break callback promises 1748c2ecf20Sopenharmony_ci */ 1758c2ecf20Sopenharmony_civoid afs_break_callbacks(struct afs_server *server, size_t count, 1768c2ecf20Sopenharmony_ci struct afs_callback_break *callbacks) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci _enter("%p,%zu,", server, count); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci ASSERT(server != NULL); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci rcu_read_lock(); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci while (count > 0) 1858c2ecf20Sopenharmony_ci afs_break_some_callbacks(server, callbacks, &count); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci rcu_read_unlock(); 1888c2ecf20Sopenharmony_ci return; 1898c2ecf20Sopenharmony_ci} 190