I'm working on a directory-level snapshot feature based on a file system, where a snapshot of a directory is recorded by an inode, and I want to implement how the snapshot sharing mount should be implemented. Specifically, you can locate the specified directory and version to the inode, and then mount the specified snapshot to another directory read-only while mounting the entire file system.
I learned that mount -bind can be used to mount subdirectories of the file system, and look at its source code, but I found that its processing function is do_loopback It is a general binding and mounting logic at the VFS layer, which only handles path mappings and does not involve specific file systems.
like code below
int f2fs_mount_snapshot(struct inode *inode, const int version, char *target_path)
{
struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
struct path mountpoint_path;
struct inode *snapshot_inode = NULL;
struct dentry *snapshot_dentry = NULL;
int ret;
pr_debug("F2FS: Entering f2fs_mount_snapshot(inode=%p, version=%d, target_path=%s)\n",
inode, version, target_path);
// Step 1: Retrieve the snapshot inode
ret = f2fs_get_snapshot_inode(sbi, inode, version, &snapshot_inode);
if (ret) {
f2fs_err(sbi, "Failed to get snapshot inode");
return ret;
}
// Step 2: Create dentry (to represent the mount point)
snapshot_dentry = d_obtain_alias(snapshot_inode);
if (IS_ERR(snapshot_dentry)) {
ret = PTR_ERR(snapshot_dentry);
f2fs_err(sbi, "Failed to obtain dentry for snapshot inode");
goto out_iput;
}
// Step 3: Resolve the target mount path
ret = kern_path(target_path, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &mountpoint_path);
if (ret) {
f2fs_err(sbi, "Failed to lookup mount point %s", target_path);
goto out_dput;
}
// Step 4: Perform loopback mount (bind mount)
down_write(&mountpoint_path.dentry->d_inode->i_rwsem);
ret = do_loopback(mountpoint_path.dentry, snapshot_dentry, 0, 0);
up_write(&mountpoint_path.dentry->d_inode->i_rwsem);
if (ret) {
f2fs_err(sbi, "Failed to loopback mount snapshot");
goto out_path_put;
}
// Step 5: Set mount as read-only (optional)
{
struct vfsmount *mnt = lookup_mnt(&mountpoint_path);
if (mnt) {
mnt->mnt_flags |= MNT_READONLY;
mntput(mnt);
}
}
pr_info("F2FS: Mounted snapshot version %d at %s\n", version, target_path);
out_path_put:
path_put(&mountpoint_path);
out_dput:
dput(snapshot_dentry);
out_iput:
iput(snapshot_inode);
return ret;
}