fs/afs/symlink.c

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

File Facts

System
Linux kernel
Corpus path
fs/afs/symlink.c
Extension
.c
Size
6883 bytes
Lines
279
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 (i_size > PAGE_SIZE - 1) {
			trace_afs_file_error(vnode, -EFBIG, afs_file_error_dir_big);
			return -EFBIG;
		}
		vnode->directory_size = i_size;

		/* Copy the symlink. */
		symlink = kmalloc_flex(struct afs_symlink, content, i_size + 1,
				       GFP_KERNEL);
		if (!symlink)
			return -ENOMEM;

		refcount_set(&symlink->ref, 1);
		symlink->content[i_size] = 0;

		const char *s = kmap_local_folio(folioq_folio(vnode->directory, 0), 0);

		memcpy(symlink->content, s, i_size);
		kunmap_local(s);

		afs_replace_symlink(vnode, symlink);
	}

	if (!fscache_cookie_enabled(netfs_i_cookie(&vnode->netfs))) {
		netfs_free_folioq_buffer(vnode->directory);
		vnode->directory = NULL;
		vnode->directory_size = 0;
	}

	return ret;
}

static ssize_t afs_read_symlink(struct afs_vnode *vnode)
{
	ssize_t ret;

	fscache_use_cookie(afs_vnode_cache(vnode), false);
	ret = afs_do_read_symlink(vnode);
	fscache_unuse_cookie(afs_vnode_cache(vnode), NULL, NULL);
	return ret;
}

static void afs_put_link(void *arg)
{
	afs_put_symlink(arg);
}

const char *afs_get_link(struct dentry *dentry, struct inode *inode,
			 struct delayed_call *callback)
{
	struct afs_symlink *symlink;
	struct afs_vnode *vnode = AFS_FS_I(inode);
	ssize_t ret;

	if (!dentry) {
		/* RCU pathwalk. */
		symlink = rcu_dereference(vnode->symlink);
		if (!symlink || !afs_check_validity(vnode))
			return ERR_PTR(-ECHILD);
		set_delayed_call(callback, NULL, NULL);
		return symlink->content;
	}

	if (vnode->symlink) {
		ret = afs_validate(vnode, NULL);
		if (ret < 0)
			return ERR_PTR(ret);

		down_read(&vnode->validate_lock);
		if (vnode->symlink)
			goto good;
		up_read(&vnode->validate_lock);
	}

	if (down_write_killable(&vnode->validate_lock) < 0)
		return ERR_PTR(-ERESTARTSYS);
	if (!vnode->symlink) {
		ret = afs_read_symlink(vnode);
		if (ret < 0) {
			up_write(&vnode->validate_lock);
			return ERR_PTR(ret);
		}
	}

	downgrade_write(&vnode->validate_lock);
	
good:
	symlink = rcu_dereference_protected(vnode->symlink,
					    lockdep_is_held(&vnode->validate_lock));
	refcount_inc(&symlink->ref);

Annotation

Implementation Notes