162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (c) 2002, 2007 Red Hat, Inc. All rights reserved. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * This software may be freely redistributed under the terms of the 562306a36Sopenharmony_ci * GNU General Public License. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * You should have received a copy of the GNU General Public License 862306a36Sopenharmony_ci * along with this program; if not, write to the Free Software 962306a36Sopenharmony_ci * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * Authors: David Woodhouse <dwmw2@infradead.org> 1262306a36Sopenharmony_ci * David Howells <dhowells@redhat.com> 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci */ 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include <linux/kernel.h> 1762306a36Sopenharmony_ci#include <linux/module.h> 1862306a36Sopenharmony_ci#include <linux/init.h> 1962306a36Sopenharmony_ci#include <linux/circ_buf.h> 2062306a36Sopenharmony_ci#include <linux/sched.h> 2162306a36Sopenharmony_ci#include "internal.h" 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci/* 2462306a36Sopenharmony_ci * Handle invalidation of an mmap'd file. We invalidate all the PTEs referring 2562306a36Sopenharmony_ci * to the pages in this file's pagecache, forcing the kernel to go through 2662306a36Sopenharmony_ci * ->fault() or ->page_mkwrite() - at which point we can handle invalidation 2762306a36Sopenharmony_ci * more fully. 2862306a36Sopenharmony_ci */ 2962306a36Sopenharmony_civoid afs_invalidate_mmap_work(struct work_struct *work) 3062306a36Sopenharmony_ci{ 3162306a36Sopenharmony_ci struct afs_vnode *vnode = container_of(work, struct afs_vnode, cb_work); 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci unmap_mapping_pages(vnode->netfs.inode.i_mapping, 0, 0, false); 3462306a36Sopenharmony_ci} 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_civoid afs_server_init_callback_work(struct work_struct *work) 3762306a36Sopenharmony_ci{ 3862306a36Sopenharmony_ci struct afs_server *server = container_of(work, struct afs_server, initcb_work); 3962306a36Sopenharmony_ci struct afs_vnode *vnode; 4062306a36Sopenharmony_ci struct afs_cell *cell = server->cell; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci down_read(&cell->fs_open_mmaps_lock); 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci list_for_each_entry(vnode, &cell->fs_open_mmaps, cb_mmap_link) { 4562306a36Sopenharmony_ci if (vnode->cb_server == server) { 4662306a36Sopenharmony_ci clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags); 4762306a36Sopenharmony_ci queue_work(system_unbound_wq, &vnode->cb_work); 4862306a36Sopenharmony_ci } 4962306a36Sopenharmony_ci } 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci up_read(&cell->fs_open_mmaps_lock); 5262306a36Sopenharmony_ci} 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci/* 5562306a36Sopenharmony_ci * Allow the fileserver to request callback state (re-)initialisation. 5662306a36Sopenharmony_ci * Unfortunately, UUIDs are not guaranteed unique. 5762306a36Sopenharmony_ci */ 5862306a36Sopenharmony_civoid afs_init_callback_state(struct afs_server *server) 5962306a36Sopenharmony_ci{ 6062306a36Sopenharmony_ci rcu_read_lock(); 6162306a36Sopenharmony_ci do { 6262306a36Sopenharmony_ci server->cb_s_break++; 6362306a36Sopenharmony_ci atomic_inc(&server->cell->fs_s_break); 6462306a36Sopenharmony_ci if (!list_empty(&server->cell->fs_open_mmaps)) 6562306a36Sopenharmony_ci queue_work(system_unbound_wq, &server->initcb_work); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci } while ((server = rcu_dereference(server->uuid_next))); 6862306a36Sopenharmony_ci rcu_read_unlock(); 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci/* 7262306a36Sopenharmony_ci * actually break a callback 7362306a36Sopenharmony_ci */ 7462306a36Sopenharmony_civoid __afs_break_callback(struct afs_vnode *vnode, enum afs_cb_break_reason reason) 7562306a36Sopenharmony_ci{ 7662306a36Sopenharmony_ci _enter(""); 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci clear_bit(AFS_VNODE_NEW_CONTENT, &vnode->flags); 7962306a36Sopenharmony_ci if (test_and_clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) { 8062306a36Sopenharmony_ci vnode->cb_break++; 8162306a36Sopenharmony_ci vnode->cb_v_break = vnode->volume->cb_v_break; 8262306a36Sopenharmony_ci afs_clear_permits(vnode); 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci if (vnode->lock_state == AFS_VNODE_LOCK_WAITING_FOR_CB) 8562306a36Sopenharmony_ci afs_lock_may_be_available(vnode); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci if (reason != afs_cb_break_for_deleted && 8862306a36Sopenharmony_ci vnode->status.type == AFS_FTYPE_FILE && 8962306a36Sopenharmony_ci atomic_read(&vnode->cb_nr_mmap)) 9062306a36Sopenharmony_ci queue_work(system_unbound_wq, &vnode->cb_work); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci trace_afs_cb_break(&vnode->fid, vnode->cb_break, reason, true); 9362306a36Sopenharmony_ci } else { 9462306a36Sopenharmony_ci trace_afs_cb_break(&vnode->fid, vnode->cb_break, reason, false); 9562306a36Sopenharmony_ci } 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_civoid afs_break_callback(struct afs_vnode *vnode, enum afs_cb_break_reason reason) 9962306a36Sopenharmony_ci{ 10062306a36Sopenharmony_ci write_seqlock(&vnode->cb_lock); 10162306a36Sopenharmony_ci __afs_break_callback(vnode, reason); 10262306a36Sopenharmony_ci write_sequnlock(&vnode->cb_lock); 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci/* 10662306a36Sopenharmony_ci * Look up a volume by volume ID under RCU conditions. 10762306a36Sopenharmony_ci */ 10862306a36Sopenharmony_cistatic struct afs_volume *afs_lookup_volume_rcu(struct afs_cell *cell, 10962306a36Sopenharmony_ci afs_volid_t vid) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci struct afs_volume *volume = NULL; 11262306a36Sopenharmony_ci struct rb_node *p; 11362306a36Sopenharmony_ci int seq = 1; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci do { 11662306a36Sopenharmony_ci /* Unfortunately, rbtree walking doesn't give reliable results 11762306a36Sopenharmony_ci * under just the RCU read lock, so we have to check for 11862306a36Sopenharmony_ci * changes. 11962306a36Sopenharmony_ci */ 12062306a36Sopenharmony_ci seq++; /* 2 on the 1st/lockless path, otherwise odd */ 12162306a36Sopenharmony_ci read_seqbegin_or_lock(&cell->volume_lock, &seq); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci p = rcu_dereference_raw(cell->volumes.rb_node); 12462306a36Sopenharmony_ci while (p) { 12562306a36Sopenharmony_ci volume = rb_entry(p, struct afs_volume, cell_node); 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci if (volume->vid < vid) 12862306a36Sopenharmony_ci p = rcu_dereference_raw(p->rb_left); 12962306a36Sopenharmony_ci else if (volume->vid > vid) 13062306a36Sopenharmony_ci p = rcu_dereference_raw(p->rb_right); 13162306a36Sopenharmony_ci else 13262306a36Sopenharmony_ci break; 13362306a36Sopenharmony_ci volume = NULL; 13462306a36Sopenharmony_ci } 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci } while (need_seqretry(&cell->volume_lock, seq)); 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci done_seqretry(&cell->volume_lock, seq); 13962306a36Sopenharmony_ci return volume; 14062306a36Sopenharmony_ci} 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci/* 14362306a36Sopenharmony_ci * allow the fileserver to explicitly break one callback 14462306a36Sopenharmony_ci * - happens when 14562306a36Sopenharmony_ci * - the backing file is changed 14662306a36Sopenharmony_ci * - a lock is released 14762306a36Sopenharmony_ci */ 14862306a36Sopenharmony_cistatic void afs_break_one_callback(struct afs_volume *volume, 14962306a36Sopenharmony_ci struct afs_fid *fid) 15062306a36Sopenharmony_ci{ 15162306a36Sopenharmony_ci struct super_block *sb; 15262306a36Sopenharmony_ci struct afs_vnode *vnode; 15362306a36Sopenharmony_ci struct inode *inode; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci if (fid->vnode == 0 && fid->unique == 0) { 15662306a36Sopenharmony_ci /* The callback break applies to an entire volume. */ 15762306a36Sopenharmony_ci write_lock(&volume->cb_v_break_lock); 15862306a36Sopenharmony_ci volume->cb_v_break++; 15962306a36Sopenharmony_ci trace_afs_cb_break(fid, volume->cb_v_break, 16062306a36Sopenharmony_ci afs_cb_break_for_volume_callback, false); 16162306a36Sopenharmony_ci write_unlock(&volume->cb_v_break_lock); 16262306a36Sopenharmony_ci return; 16362306a36Sopenharmony_ci } 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci /* See if we can find a matching inode - even an I_NEW inode needs to 16662306a36Sopenharmony_ci * be marked as it can have its callback broken before we finish 16762306a36Sopenharmony_ci * setting up the local inode. 16862306a36Sopenharmony_ci */ 16962306a36Sopenharmony_ci sb = rcu_dereference(volume->sb); 17062306a36Sopenharmony_ci if (!sb) 17162306a36Sopenharmony_ci return; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci inode = find_inode_rcu(sb, fid->vnode, afs_ilookup5_test_by_fid, fid); 17462306a36Sopenharmony_ci if (inode) { 17562306a36Sopenharmony_ci vnode = AFS_FS_I(inode); 17662306a36Sopenharmony_ci afs_break_callback(vnode, afs_cb_break_for_callback); 17762306a36Sopenharmony_ci } else { 17862306a36Sopenharmony_ci trace_afs_cb_miss(fid, afs_cb_break_for_callback); 17962306a36Sopenharmony_ci } 18062306a36Sopenharmony_ci} 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_cistatic void afs_break_some_callbacks(struct afs_server *server, 18362306a36Sopenharmony_ci struct afs_callback_break *cbb, 18462306a36Sopenharmony_ci size_t *_count) 18562306a36Sopenharmony_ci{ 18662306a36Sopenharmony_ci struct afs_callback_break *residue = cbb; 18762306a36Sopenharmony_ci struct afs_volume *volume; 18862306a36Sopenharmony_ci afs_volid_t vid = cbb->fid.vid; 18962306a36Sopenharmony_ci size_t i; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci volume = afs_lookup_volume_rcu(server->cell, vid); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci /* TODO: Find all matching volumes if we couldn't match the server and 19462306a36Sopenharmony_ci * break them anyway. 19562306a36Sopenharmony_ci */ 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci for (i = *_count; i > 0; cbb++, i--) { 19862306a36Sopenharmony_ci if (cbb->fid.vid == vid) { 19962306a36Sopenharmony_ci _debug("- Fid { vl=%08llx n=%llu u=%u }", 20062306a36Sopenharmony_ci cbb->fid.vid, 20162306a36Sopenharmony_ci cbb->fid.vnode, 20262306a36Sopenharmony_ci cbb->fid.unique); 20362306a36Sopenharmony_ci --*_count; 20462306a36Sopenharmony_ci if (volume) 20562306a36Sopenharmony_ci afs_break_one_callback(volume, &cbb->fid); 20662306a36Sopenharmony_ci } else { 20762306a36Sopenharmony_ci *residue++ = *cbb; 20862306a36Sopenharmony_ci } 20962306a36Sopenharmony_ci } 21062306a36Sopenharmony_ci} 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci/* 21362306a36Sopenharmony_ci * allow the fileserver to break callback promises 21462306a36Sopenharmony_ci */ 21562306a36Sopenharmony_civoid afs_break_callbacks(struct afs_server *server, size_t count, 21662306a36Sopenharmony_ci struct afs_callback_break *callbacks) 21762306a36Sopenharmony_ci{ 21862306a36Sopenharmony_ci _enter("%p,%zu,", server, count); 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci ASSERT(server != NULL); 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci rcu_read_lock(); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci while (count > 0) 22562306a36Sopenharmony_ci afs_break_some_callbacks(server, callbacks, &count); 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci rcu_read_unlock(); 22862306a36Sopenharmony_ci return; 22962306a36Sopenharmony_ci} 230