fs/cachefiles/ondemand.c

Source file repositories/reference/linux-study-clean/fs/cachefiles/ondemand.c

File Facts

System
Linux kernel
Corpus path
fs/cachefiles/ondemand.c
Extension
.c
Size
20033 bytes
Lines
762
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 cachefiles_ondemand_fd_fops = {
	.owner		= THIS_MODULE,
	.release	= cachefiles_ondemand_fd_release,
	.write_iter	= cachefiles_ondemand_fd_write_iter,
	.llseek		= cachefiles_ondemand_fd_llseek,
	.unlocked_ioctl	= cachefiles_ondemand_fd_ioctl,
};

/*
 * OPEN request Completion (copen)
 * - command: "copen <id>,<cache_size>"
 *   <cache_size> indicates the object size if >=0, error code if negative
 */
int cachefiles_ondemand_copen(struct cachefiles_cache *cache, char *args)
{
	struct cachefiles_req *req;
	struct fscache_cookie *cookie;
	struct cachefiles_ondemand_info *info;
	char *pid, *psize;
	unsigned long id;
	long size;
	int ret;
	XA_STATE(xas, &cache->reqs, 0);

	if (!test_bit(CACHEFILES_ONDEMAND_MODE, &cache->flags))
		return -EOPNOTSUPP;

	if (!*args) {
		pr_err("Empty id specified\n");
		return -EINVAL;
	}

	pid = args;
	psize = strchr(args, ',');
	if (!psize) {
		pr_err("Cache size is not specified\n");
		return -EINVAL;
	}

	*psize = 0;
	psize++;

	ret = kstrtoul(pid, 0, &id);
	if (ret)
		return ret;

	xa_lock(&cache->reqs);
	xas.xa_index = id;
	req = xas_load(&xas);
	if (!req || req->msg.opcode != CACHEFILES_OP_OPEN ||
	    !req->object->ondemand->ondemand_id) {
		xa_unlock(&cache->reqs);
		return -EINVAL;
	}
	xas_store(&xas, NULL);
	xa_unlock(&cache->reqs);

	info = req->object->ondemand;
	/* fail OPEN request if copen format is invalid */
	ret = kstrtol(psize, 0, &size);
	if (ret) {
		req->error = ret;
		goto out;
	}

	/* fail OPEN request if daemon reports an error */
	if (size < 0) {
		if (!IS_ERR_VALUE(size)) {
			req->error = -EINVAL;
			ret = -EINVAL;
		} else {
			req->error = size;
			ret = 0;
		}
		goto out;
	}

	spin_lock(&info->lock);
	/*
	 * The anonymous fd was closed before copen ? Fail the request.
	 *
	 *             t1             |             t2
	 * ---------------------------------------------------------
	 *                             cachefiles_ondemand_copen
	 *                             req = xa_erase(&cache->reqs, id)
	 * // Anon fd is maliciously closed.
	 * cachefiles_ondemand_fd_release
	 * xa_lock(&cache->reqs)
	 * cachefiles_ondemand_set_object_close(object)
	 * xa_unlock(&cache->reqs)

Annotation

Implementation Notes