.fstrash
) will act as a basket. The essence of moving to the trash will be to ensure that at the time of deletion of the file to create for him a "hard link" in this directory. In this case, the delete operation, following the operation of creating a hard link, will delete only the “old name” of the file, but not its contents.ext4
) static struct qstr fstrash = { .len = 8, .name = ".fstrash", }; static int fstrash_unlink(struct inode * inode, struct dentry * dentry) { int result = -EINVAL; /* handle real deletes only */ if (dentry->d_inode->i_nlink == 1) { struct dentry * trash = NULL; trash = d_lookup(inode->i_sb->s_root, &fstrash); if (trash) { /* don't loop while deleting from the trash itself */ if (trash->d_inode && (trash->d_inode != inode)) result = move_to_trash(trash, dentry); dput(trash); } } return result; }
i_nlink
) on the dentry
element describing the file. Comparison with the unit is necessary in order to make sure that the requested operation (deletion) leads to the deletion of the file, since The i_nlink
counter contains the number of directory entries that refer to this file (the number of hard links). Obviously, the value "1" corresponds to the only (last) link.trash->d_inode != inode
), the function of creating a hard link is called (moving the file to the basket) - move_to_trash : static int move_to_trash(struct dentry * trash, struct dentry * object) { int result; char name[64]; struct dentry * de; snprintf(name, sizeof(name), "XXX-%lu-%s", \ object->d_inode->i_ino, object->d_name.name); de = d_alloc_name(trash, name); if (!de) return -ENOMEM; trash->d_inode->i_op->lookup(trash->d_inode, de, 0); inc_nlink(object->d_inode); mutex_lock(&trash->d_inode->i_mutex); result = trash->d_inode->i_op->link(object, trash->d_inode, de); mutex_unlock(&trash->d_inode->i_mutex); drop_nlink(object->d_inode); if (!result) mark_inode_dirty(object->d_inode); dput(de); return result; }
XXX-<_>-<_>
)i_op->lookup
operation for a new file namei_op->link
mark_inode_dirty
function, which signals the system to synchronize the metadata of this file. DECLARE_KHOOK(ext4_unlink); int khook_ext4_unlink(struct inode * inode, struct dentry * dentry) { int result; KHOOK_USAGE_INC(ext4_unlink); fstrash_unlink(inode, dentry); result = KHOOK_ORIGIN(ext4_unlink, inode, dentry); KHOOK_USAGE_DEC(ext4_unlink); return result; }
ext4_unlink
function ext4_unlink
called by the kernel from the vfs_unlink function, which in turn performs the necessary synchronization, preventing competitive access to information for the duration of the operation: 3398 int vfs_unlink(struct inode *dir, struct dentry *dentry) 3399 { ... 3408 mutex_lock(&dentry->d_inode->i_mutex); 3409 if (d_mountpoint(dentry)) 3410 error = -EBUSY; 3411 else { 3412 error = security_inode_unlink(dir, dentry); 3413 if (!error) { 3414 error = dir->i_op->unlink(dir, dentry); 3415 if (!error) 3416 dont_mount(dentry); 3417 } 3418 } 3419 mutex_unlock(&dentry->d_inode->i_mutex); ... 3428 }
i_op->unlink(...)
operation is protected by the corresponding synchronization primitive ( d_inode->i_mutex
).cron
task that runs at regular intervals (for example, 5 minutes) and cleans up, as an option, everything that lies in the basket by mask /.fstrash/XXX_*
. Everyone can choose the time for himself as well as by what criteria to clean :)Source: https://habr.com/ru/post/210364/
All Articles