delete by apk: call sdcardfs_lookup then vfat_unlink, 空间释放err。
再来看下mmc0/data分区(f2fs)的删除流程:
delete by apk: call sdcardfs_unlink then f2fs_unlink, 空间释ok。
rm: 和apk一样,先走sdcardfs_unlink再f2fs_unlink,空间释放ok。
那就有一个疑问:同样的rm unlink系统调用,SD卡(vfat)删除时为什么不走sdcardfs_unlink?mark to check later。
rm unlink flow on data/sdcardfs on f2fs:
[ 1509.351490] [<c034ef3c>] (f2fs_unlink) from [<c023b7f4>] (vfs_unlink2+0xe8/0x17c) [ 1509.351508] [<c023b7f4>] (vfs_unlink2) from [<c02fd798>] (sdcardfs_unlink+0xc8/0x198) [ 1509.351526] [<c02fd798>] (sdcardfs_unlink) from [<c023b7f4>] (vfs_unlink2+0xe8/0x17c) [ 1509.351544] [<c023b7f4>] (vfs_unlink2) from [<c023ff4c>] (do_unlinkat+0xd4/0x1c4) [ 1509.351561] [<c023ff4c>] (do_unlinkat) from [<c0106aa0>] (ret_fast_syscall+0x0/0x44)
rm unlink flow on SD/sdcardfs on vfat:
[ 1489.624809] [<c02fa5f4>] (vfat_unlink) from [<c023b7f4>] (vfs_unlink2+0xe8/0x17c) [ 1489.624829] [<c023b7f4>] (vfs_unlink2) from [<c023ff4c>] (do_unlinkat+0xd4/0x1c4) [ 1489.624847] [<c023ff4c>] (do_unlinkat) from [<c0106aa0>] (ret_fast_syscall+0x0/0x44)
so lets check do_unlinkat why not to free space:
staticlongdo_unlinkat(int dfd, constchar __user *pathname) { ... if (!IS_ERR(dentry)) { /* Why not before? Because we want correct error value */ if (nd.last.name[nd.last.len]) goto slashes; inode = dentry->d_inode; if (d_is_negative(dentry)) goto slashes; ihold(inode); error = security_path_unlink(&nd.path, dentry); if (error) goto exit2; error = vfs_unlink2(nd.path.mnt, nd.path.dentry->d_inode, dentry, &delegated_inode); exit2: dput(dentry); } mutex_unlock(&nd.path.dentry->d_inode->i_mutex); if (inode) iput(inode); /* truncate the inode here *///tj: 这里是关键
input:
/** * iput - put an inode * @inode: inode to put * * Puts an inode, dropping its usage count. If the inode use count hits * zero, the inode is then freed and may also be destroyed. * * Consequently, iput() can sleep. */ voidiput(struct inode *inode) { if (!inode) return; BUG_ON(inode->i_state & I_CLEAR); retry: if (atomic_dec_and_lock(&inode->i_count, &inode->i_lock)) { if (inode->i_nlink && (inode->i_state & I_DIRTY_TIME)) { atomic_inc(&inode->i_count); inode->i_state &= ~I_DIRTY_TIME; spin_unlock(&inode->i_lock); trace_writeback_lazytime_iput(inode); mark_inode_dirty_sync(inode); goto retry; } iput_final(inode); //tj: 最终要走这里 } }
iput_final:
/* * Called when we're dropping the last reference * to an inode. * * Call the FS "drop_inode()" function, defaulting to * the legacy UNIX filesystem behaviour. If it tells * us to evict inode, do so. Otherwise, retain inode * in cache if fs is alive, sync and evict if fs is * shutting down. */ staticvoidiput_final(struct inode *inode) { structsuper_block *sb = inode->i_sb; conststructsuper_operations *op = inode->i_sb->s_op; int drop;
WARN_ON(inode->i_state & I_NEW);
if (op->drop_inode) drop = op->drop_inode(inode); else drop = generic_drop_inode(inode);
if (!list_empty(&inode->i_wb_list)) inode_wb_list_del(inode);
inode_sb_list_del(inode);
/* * Wait for flusher thread to be done with the inode so that filesystem * does not start destroying it while writeback is still running. Since * the inode has I_FREEING set, flusher thread won't start new work on * the inode. We just have to wait for running writeback to finish. */ inode_wait_for_writeback(inode);
if (op->evict_inode) { op->evict_inode(inode); // tj: call fat_evict_inode
/* * This protects against truncating a file bigger than it was then * trying to write into the hole. */ if (MSDOS_I(inode)->mmu_private > offset) MSDOS_I(inode)->mmu_private = offset;