fs/nfsd/nfs4state.c

Source file repositories/reference/linux-study-clean/fs/nfsd/nfs4state.c

File Facts

System
Linux kernel
Corpus path
fs/nfsd/nfs4state.c
Extension
.c
Size
260082 bytes
Lines
9706
Domain
Core OS
Bucket
VFS And Filesystem Core
Inferred role
Core OS: operation-table or driver-model contract
Status
pattern 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

static const struct file_operations client_states_fops = {
	.open		= client_states_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= client_opens_release,
};

/*
 * Normally we refuse to destroy clients that are in use, but here the
 * administrator is telling us to just do it.  We also want to wait
 * so the caller has a guarantee that the client's locks are gone by
 * the time the write returns:
 */
static void force_expire_client(struct nfs4_client *clp)
{
	struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
	bool already_expired;

	trace_nfsd_clid_admin_expired(&clp->cl_clientid);

	spin_lock(&nn->client_lock);
	clp->cl_time = 0;
	spin_unlock(&nn->client_lock);

	wait_event(expiry_wq, atomic_read(&clp->cl_rpc_users) == 0);
	spin_lock(&nn->client_lock);
	already_expired = list_empty(&clp->cl_lru);
	if (!already_expired)
		unhash_client_locked(clp);
	spin_unlock(&nn->client_lock);

	if (!already_expired)
		expire_client(clp);
	else
		wait_event(expiry_wq, clp->cl_nfsd_dentry == NULL);
}

static ssize_t client_ctl_write(struct file *file, const char __user *buf,
				   size_t size, loff_t *pos)
{
	char *data;
	struct nfs4_client *clp;

	data = simple_transaction_get(file, buf, size);
	if (IS_ERR(data))
		return PTR_ERR(data);
	if (size != 7 || 0 != memcmp(data, "expire\n", 7))
		return -EINVAL;
	clp = get_nfsdfs_clp(file_inode(file));
	if (!clp)
		return -ENXIO;
	force_expire_client(clp);
	nfsd4_put_client(clp);
	return 7;
}

static const struct file_operations client_ctl_fops = {
	.write		= client_ctl_write,
	.release	= simple_transaction_release,
};

static const struct tree_descr client_files[] = {
	[0] = {"info", &client_info_fops, S_IRUSR},
	[1] = {"states", &client_states_fops, S_IRUSR},
	[2] = {"ctl", &client_ctl_fops, S_IWUSR},
	[3] = {""},
};

static int
nfsd4_cb_recall_any_done(struct nfsd4_callback *cb,
				struct rpc_task *task)
{
	trace_nfsd_cb_recall_any_done(cb, task);
	switch (task->tk_status) {
	case -NFS4ERR_DELAY:
		rpc_delay(task, 2 * HZ);
		return 0;
	default:
		return 1;
	}
}

static void
nfsd4_cb_recall_any_release(struct nfsd4_callback *cb)
{
	struct nfs4_client *clp = cb->cb_clp;

	nfsd4_put_client(clp);
}

Annotation

Implementation Notes