fs/overlayfs/dir.c

Source file repositories/reference/linux-study-clean/fs/overlayfs/dir.c

File Facts

System
Linux kernel
Corpus path
fs/overlayfs/dir.c
Extension
.c
Size
36365 bytes
Lines
1497
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

struct ovl_renamedata {
	struct renamedata;
	struct dentry *opaquedir;
	bool cleanup_whiteout;
	bool update_nlink;
	bool overwrite;
};

static int ovl_rename_start(struct ovl_renamedata *ovlrd, struct list_head *list)
{
	struct dentry *old = ovlrd->old_dentry;
	struct dentry *new = ovlrd->new_dentry;
	bool is_dir = d_is_dir(old);
	bool new_is_dir = d_is_dir(new);
	int err;

	if (ovlrd->flags & ~(RENAME_EXCHANGE | RENAME_NOREPLACE))
		return -EINVAL;

	ovlrd->flags &= ~RENAME_NOREPLACE;

	/* Don't copy up directory trees */
	err = -EXDEV;
	if (!ovl_can_move(old))
		return err;
	if (!ovlrd->overwrite && !ovl_can_move(new))
		return err;

	if (ovlrd->overwrite && new_is_dir && !ovl_pure_upper(new)) {
		err = ovl_check_empty_dir(new, list);
		if (err)
			return err;
	}

	if (ovlrd->overwrite) {
		if (ovl_lower_positive(old)) {
			if (!ovl_dentry_is_whiteout(new)) {
				/* Whiteout source */
				ovlrd->flags |= RENAME_WHITEOUT;
			} else {
				/* Switch whiteouts */
				ovlrd->flags |= RENAME_EXCHANGE;
			}
		} else if (is_dir && ovl_dentry_is_whiteout(new)) {
			ovlrd->flags |= RENAME_EXCHANGE;
			ovlrd->cleanup_whiteout = true;
		}
	}

	err = ovl_copy_up(old);
	if (err)
		return err;

	err = ovl_copy_up(new->d_parent);
	if (err)
		return err;

	if (!ovlrd->overwrite) {
		err = ovl_copy_up(new);
		if (err)
			return err;
	} else if (d_inode(new)) {
		err = ovl_nlink_start(new);
		if (err)
			return err;

		ovlrd->update_nlink = true;
	}

	if (!ovlrd->update_nlink) {
		/* ovl_nlink_start() took ovl_want_write() */
		err = ovl_want_write(old);
		if (err)
			return err;
	}

	return 0;
}

static int ovl_rename_upper(struct ovl_renamedata *ovlrd, struct list_head *list)
{
	struct dentry *old = ovlrd->old_dentry;
	struct dentry *new = ovlrd->new_dentry;
	struct ovl_fs *ofs = OVL_FS(old->d_sb);
	struct dentry *old_upperdir = ovl_dentry_upper(old->d_parent);
	struct dentry *new_upperdir = ovl_dentry_upper(new->d_parent);
	bool is_dir = d_is_dir(old);
	bool new_is_dir = d_is_dir(new);
	bool samedir = old->d_parent == new->d_parent;
	struct renamedata rd = {};

Annotation

Implementation Notes