fs/afs/callback.c

Source file repositories/reference/linux-study-clean/fs/afs/callback.c

File Facts

System
Linux kernel
Corpus path
fs/afs/callback.c
Extension
.c
Size
7401 bytes
Lines
266
Domain
Core OS
Bucket
VFS And Filesystem Core
Inferred role
Core OS: implementation source
Status
source implementation candidate

Why This File Exists

Core operating-system implementation surface: boot, tasks, memory, VFS, syscall-facing interfaces, synchronization, credentials, and isolation.

Dependency Surface

Detected Declarations

Annotated Snippet

if (vnode->cb_v_check != atomic_read(&volume->cb_v_break)) {
			afs_clear_cb_promise(vnode, afs_cb_promise_clear_vol_init_cb);
			queue_work(system_dfl_wq, &vnode->cb_work);
		}
	}

	up_read(&volume->open_mmaps_lock);
}

/*
 * Allow the fileserver to request callback state (re-)initialisation.
 * Unfortunately, UUIDs are not guaranteed unique.
 */
void afs_init_callback_state(struct afs_server *server)
{
	struct afs_server_entry *se;

	down_read(&server->cell->vs_lock);

	list_for_each_entry(se, &server->volumes, slink) {
		se->cb_expires_at = AFS_NO_CB_PROMISE;
		se->volume->cb_expires_at = AFS_NO_CB_PROMISE;
		trace_afs_cb_v_break(se->volume->vid, atomic_read(&se->volume->cb_v_break),
				     afs_cb_break_for_s_reinit);
		if (!list_empty(&se->volume->open_mmaps))
			afs_volume_init_callback(se->volume);
	}

	up_read(&server->cell->vs_lock);
}

/*
 * actually break a callback
 */
void __afs_break_callback(struct afs_vnode *vnode, enum afs_cb_break_reason reason)
{
	_enter("");

	clear_bit(AFS_VNODE_NEW_CONTENT, &vnode->flags);
	if (afs_clear_cb_promise(vnode, afs_cb_promise_clear_cb_break)) {
		vnode->cb_break++;
		vnode->cb_v_check = atomic_read(&vnode->volume->cb_v_break);
		afs_clear_permits(vnode);

		if (vnode->lock_state == AFS_VNODE_LOCK_WAITING_FOR_CB)
			afs_lock_may_be_available(vnode);

		if (reason != afs_cb_break_for_deleted &&
		    vnode->status.type == AFS_FTYPE_FILE &&
		    atomic_read(&vnode->cb_nr_mmap))
			queue_work(system_dfl_wq, &vnode->cb_work);

		trace_afs_cb_break(&vnode->fid, vnode->cb_break, reason, true);
	} else {
		trace_afs_cb_break(&vnode->fid, vnode->cb_break, reason, false);
	}
}

void afs_break_callback(struct afs_vnode *vnode, enum afs_cb_break_reason reason)
{
	write_seqlock(&vnode->cb_lock);
	__afs_break_callback(vnode, reason);
	write_sequnlock(&vnode->cb_lock);
}

/*
 * Look up a volume by volume ID under RCU conditions.
 */
static struct afs_volume *afs_lookup_volume_rcu(struct afs_cell *cell,
						afs_volid_t vid)
{
	struct afs_volume *volume = NULL;
	struct rb_node *p;
	int seq = 1;

	for (;;) {
		/* Unfortunately, rbtree walking doesn't give reliable results
		 * under just the RCU read lock, so we have to check for
		 * changes.
		 */
		seq++; /* 2 on the 1st/lockless path, otherwise odd */
		read_seqbegin_or_lock(&cell->volume_lock, &seq);

		p = rcu_dereference_raw(cell->volumes.rb_node);
		while (p) {
			volume = rb_entry(p, struct afs_volume, cell_node);

			if (volume->vid < vid)
				p = rcu_dereference_raw(p->rb_left);
			else if (volume->vid > vid)

Annotation

Implementation Notes