博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
系统rm的处理机制
阅读量:2353 次
发布时间:2019-05-10

本文共 5243 字,大约阅读时间需要 17 分钟。

在linux下,常常可以执行rm -rf /home/tmp/test这样的命令删除一个目录,或是使用其他的参数删除一个文件或目录,纠结在系统内部,这些删除命令是如何处理的呢?

      这些命令其实是由系统提供的可执行程序实现的,而这些程序调用了库函数或是直接调用了系统调用函数,主要的相关的系统调用有两个,下面先介绍这些相关的系统调用函数:

  • asmlinkage long sys_unlink(const char __user *pathname);

             < do_unlinkat

                   < vfs_unlink:检查删除的条目是否是一个挂载点,如果是则返回EBUSY的错误;否则删除该inode,如果这个条目是一个私有条目,则调用安全删除机制将其删除,否则直接调用文件系统的inode删除接口删除;

                                < security_inode_unlink:安全删除,如果是一个非私有数据,则返回0;

                                   dir->i_op->unlink:调用具体文件系统的删除接口;

  

 

  • asmlinkage long sys_rmdir(const char __user *pathname);

              < do_rmdir:查找路径,然后判断删除目录的类型,对目录上锁,找到相应的dentry,调用vfs层的目录删除接口

                       < vfs_rmdir:对目录项上锁,判断删除的目录是否为挂载点,如果是挂载点则返回EBUSY错误;否则,判断删除的inode是否为私有节点,如果是的话则使用安全删除机制删除,返回直接调用文件系统的删除命令;

                                < security_inode_rmdir:

                                    dir->i_op->rmdir:

现在重点介绍块inode中的元数据操作

 
:const struct inode_operations ext3_dir_inode_operations = {.create = ext3_create,.lookup = ext3_lookup,.link = ext3_link,.unlink = ext3_unlink,.symlink = ext3_symlink,.mkdir = ext3_mkdir,.rmdir = ext3_rmdir,.mknod = ext3_mknod,.rename = ext3_rename,.setattr = ext3_setattr,#ifdef CONFIG_EXT3_FS_XATTR.setxattr = generic_setxattr,.getxattr = generic_getxattr,.listxattr = ext3_listxattr,.removexattr = generic_removexattr,#endif.permission = ext3_permission,};static int ext3_unlink(struct inode * dir, struct dentry *dentry){	int retval;	struct inode * inode;	struct buffer_head * bh;	struct ext3_dir_entry_2 * de;	handle_t *handle;	/* Initialize quotas before so that eventual writes go	 * in separate transaction */	DQUOT_INIT(dentry->d_inode);//申请一个原子操作	handle = ext3_journal_start(dir, EXT3_DELETE_TRANS_BLOCKS(dir->i_sb));	if (IS_ERR(handle))		return PTR_ERR(handle);	if (IS_DIRSYNC(dir))		handle->h_sync = 1;	retval = -ENOENT;//找到inode对应的buffer head	bh = ext3_find_entry (dentry, &de);	if (!bh)		goto end_unlink;	inode = dentry->d_inode;	retval = -EIO;	if (le32_to_cpu(de->inode) != inode->i_ino)		goto end_unlink;	if (!inode->i_nlink) {//inode中的i_nlink字段为0,表示删除的目标文件不存在		ext3_warning (inode->i_sb, "ext3_unlink",			      "Deleting nonexistent file (%lu), %d",			      inode->i_ino, inode->i_nlink);		inode->i_nlink = 1;	}//通过将目标目录下与前一个目录下合并,删除目标目录项	retval = ext3_delete_entry(handle, dir, de, bh);	if (retval)		goto end_unlink;	dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;	ext3_update_dx_flag(dir);	ext3_mark_inode_dirty(handle, dir);	drop_nlink(inode);	if (!inode->i_nlink)//如果inode的i_nlink为0,则认为当前节点为孤儿节点,加入到super block中的孤儿节点链表中		ext3_orphan_add(handle, inode);	inode->i_ctime = dir->i_ctime;	ext3_mark_inode_dirty(handle, inode);	retval = 0;end_unlink:	ext3_journal_stop(handle);	brelse (bh);	return retval;}static int ext3_rmdir (struct inode * dir, struct dentry *dentry){	int retval;	struct inode * inode;	struct buffer_head * bh;	struct ext3_dir_entry_2 * de;	handle_t *handle;	/* Initialize quotas before so that eventual writes go in	 * separate transaction */	DQUOT_INIT(dentry->d_inode);	handle = ext3_journal_start(dir, EXT3_DELETE_TRANS_BLOCKS(dir->i_sb));	if (IS_ERR(handle))		return PTR_ERR(handle);	retval = -ENOENT;	bh = ext3_find_entry (dentry, &de);	if (!bh)		goto end_rmdir;	if (IS_DIRSYNC(dir))		handle->h_sync = 1;	inode = dentry->d_inode;	retval = -EIO;	if (le32_to_cpu(de->inode) != inode->i_ino)		goto end_rmdir;	retval = -ENOTEMPTY;	//判断删除的目录是否是空目录,如果不为空目录,则	//返回ENOTEMPTY的错误	if (!empty_dir (inode))		goto end_rmdir;	//将删除的目标dentry与磁盘上的前一个dentry合并,	//从而删除目标dentry	retval = ext3_delete_entry(handle, dir, de, bh);	if (retval)		goto end_rmdir;	if (inode->i_nlink != 2)		ext3_warning (inode->i_sb, "ext3_rmdir",			      "empty directory has nlink!=2 (%d)",			      inode->i_nlink);	inode->i_version++;	//将i_nlink设置为0	clear_nlink(inode);	/* There's no need to set i_disksize: the fact that i_nlink is	 * zero will ensure that the right thing happens during any	 * recovery. */	inode->i_size = 0;	ext3_orphan_add(handle, inode);	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;	ext3_mark_inode_dirty(handle, inode);	drop_nlink(dir);	ext3_update_dx_flag(dir);	ext3_mark_inode_dirty(handle, dir);end_rmdir:	ext3_journal_stop(handle);	brelse (bh);	return retval;}

接下来看看coreutils中具体的程序流程:与删除相关的源文件主要有

  • remove.h
  • remove.c
  • rm.c
  • rmdir.c

1.首先看remove.h文件,该文件定义了一些与删除操作相关的数据结构:

struct rm_options:定义了rm操作的参数,即上层应用指定的rm -r -f -i等之类的选项

enum RM_status:定义了删除操作的返回状态,即删除成功、出错或是目标目录非空等

 

2.接着重点看看remove.c文件,与rm相关的操作核心函数就在这个文件中

  • 数据结构
enum Prompt_action  {    PA_DESCEND_INTO_DIR = 2,   //进入到目录内部    PA_REMOVE_DIR              //删除目录  };
struct AD_ent   //在active directory堆栈中的一个条目,每个条目对应一个active directory{  Hash_table *unremovable;   //相应目录中,不能删除的条目的文件名(如.和..,以及调用删除操作失败的条目)  enum RM_status status;  union  {    struct dev_ino a; //指示上级目录,当调用chdir进入子目录后,再调用chdir ..时通过该参数回到上次访问的目录下    struct saved_cwd saved_cwd; //重构初始工作目录必须的信息,只有最底层条目才有该结构  } u;};
struct dirstack_state{  struct obstack dir_stack; //正在处理的目录的文件名,当用户进入子目录后,将在堆栈中压入一个新的条目,使用chdir时将堆栈栈顶的元素出栈  struct obstack len_stack; //目录名长度堆栈  struct obstack Active_dir; //active目录的栈,第一个条目是初始工作目录,当用户调用chdir时,将相应的条目压栈  struct cycle_check_state cycle_check_state;  jmp_buf current_arg_jumpbuf;};typedef struct dirstack_state Dirstack_state;

 

  • 处理函数

 

 

 

注意:ext3_rmdir只能删除一个空目录,如果目录非空,则函数将返回ENOTEMPTY的错误。无论是ext3_unlink还是ext3_rmdir函数,当目录为非空时,都不会变量该目录的子目录递归删除非空的目录,因此推测,rm -rf /hone/test这样的shell命令删除一个非空的目录,应该是由shell对命令进行解析和递归调用,传给系统的调用应该只能删除一个目录或是文件,而不能批量删除目录和文件。

参考资料:

转载地址:http://jsztb.baihongyu.com/

你可能感兴趣的文章
flash builder beta2 licensing for this product has expired
查看>>
Spearman Rank Correlation
查看>>
struts2文件上传中,如何限制上传文件的大小、类型
查看>>
8 个 jQuery 的图片展示插件和教程
查看>>
struts2中action跳转到另一个action的方法
查看>>
Jquery表格奇偶行不同颜色
查看>>
struts2防止表单重复提交<s:token/>
查看>>
利用XStream在Java对象和XML之间相互转换
查看>>
trivial note for Formal Languages and Automata
查看>>
myeclipse 解决内存溢出
查看>>
Java反编译小工具!
查看>>
KMP Algorithm
查看>>
第一使用Project
查看>>
PageRank&HITS算法
查看>>
POS Tagger in Java
查看>>
不断叛逆,不断克制
查看>>
10-fold cross-validation 十折交叉验证 .
查看>>
F1-Measure
查看>>
K最近邻(KNN)算法原理和java实现
查看>>
paper report《Finding high-quality content in social media》
查看>>