mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	ovl: check whiteout while reading directory
Don't make a separate pass for checking whiteouts, since we can do it while reading the upper directory. This will make it easier to handle multiple layers. Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
This commit is contained in:
		
							parent
							
								
									b2776bf714
								
							
						
					
					
						commit
						49c21e1cac
					
				
					 1 changed files with 28 additions and 49 deletions
				
			
		| 
						 | 
					@ -40,6 +40,7 @@ struct ovl_readdir_data {
 | 
				
			||||||
	struct rb_root root;
 | 
						struct rb_root root;
 | 
				
			||||||
	struct list_head *list;
 | 
						struct list_head *list;
 | 
				
			||||||
	struct list_head middle;
 | 
						struct list_head middle;
 | 
				
			||||||
 | 
						struct dentry *dir;
 | 
				
			||||||
	int count;
 | 
						int count;
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -126,6 +127,32 @@ static int ovl_cache_entry_add_rb(struct ovl_readdir_data *rdd,
 | 
				
			||||||
	if (p == NULL)
 | 
						if (p == NULL)
 | 
				
			||||||
		return -ENOMEM;
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (d_type == DT_CHR) {
 | 
				
			||||||
 | 
							struct dentry *dentry;
 | 
				
			||||||
 | 
							const struct cred *old_cred;
 | 
				
			||||||
 | 
							struct cred *override_cred;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							override_cred = prepare_creds();
 | 
				
			||||||
 | 
							if (!override_cred) {
 | 
				
			||||||
 | 
								kfree(p);
 | 
				
			||||||
 | 
								return -ENOMEM;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * CAP_DAC_OVERRIDE for lookup
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE);
 | 
				
			||||||
 | 
							old_cred = override_creds(override_cred);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							dentry = lookup_one_len(name, rdd->dir, len);
 | 
				
			||||||
 | 
							if (!IS_ERR(dentry)) {
 | 
				
			||||||
 | 
								p->is_whiteout = ovl_is_whiteout(dentry);
 | 
				
			||||||
 | 
								dput(dentry);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							revert_creds(old_cred);
 | 
				
			||||||
 | 
							put_cred(override_cred);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	list_add_tail(&p->l_node, rdd->list);
 | 
						list_add_tail(&p->l_node, rdd->list);
 | 
				
			||||||
	rb_link_node(&p->node, parent, newp);
 | 
						rb_link_node(&p->node, parent, newp);
 | 
				
			||||||
	rb_insert_color(&p->node, &rdd->root);
 | 
						rb_insert_color(&p->node, &rdd->root);
 | 
				
			||||||
| 
						 | 
					@ -231,49 +258,6 @@ static void ovl_dir_reset(struct file *file)
 | 
				
			||||||
		od->is_real = false;
 | 
							od->is_real = false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int ovl_dir_mark_whiteouts(struct dentry *dir,
 | 
					 | 
				
			||||||
				  struct ovl_readdir_data *rdd)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct ovl_cache_entry *p;
 | 
					 | 
				
			||||||
	struct dentry *dentry;
 | 
					 | 
				
			||||||
	const struct cred *old_cred;
 | 
					 | 
				
			||||||
	struct cred *override_cred;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	override_cred = prepare_creds();
 | 
					 | 
				
			||||||
	if (!override_cred) {
 | 
					 | 
				
			||||||
		ovl_cache_free(rdd->list);
 | 
					 | 
				
			||||||
		return -ENOMEM;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/*
 | 
					 | 
				
			||||||
	 * CAP_DAC_OVERRIDE for lookup
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE);
 | 
					 | 
				
			||||||
	old_cred = override_creds(override_cred);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	mutex_lock(&dir->d_inode->i_mutex);
 | 
					 | 
				
			||||||
	list_for_each_entry(p, rdd->list, l_node) {
 | 
					 | 
				
			||||||
		if (p->is_cursor)
 | 
					 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (p->type != DT_CHR)
 | 
					 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		dentry = lookup_one_len(p->name, dir, p->len);
 | 
					 | 
				
			||||||
		if (IS_ERR(dentry))
 | 
					 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		p->is_whiteout = ovl_is_whiteout(dentry);
 | 
					 | 
				
			||||||
		dput(dentry);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	mutex_unlock(&dir->d_inode->i_mutex);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	revert_creds(old_cred);
 | 
					 | 
				
			||||||
	put_cred(override_cred);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int ovl_dir_read_merged(struct dentry *dentry, struct list_head *list)
 | 
					static int ovl_dir_read_merged(struct dentry *dentry, struct list_head *list)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
| 
						 | 
					@ -290,15 +274,10 @@ static int ovl_dir_read_merged(struct dentry *dentry, struct list_head *list)
 | 
				
			||||||
	ovl_path_upper(dentry, &upperpath);
 | 
						ovl_path_upper(dentry, &upperpath);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (upperpath.dentry) {
 | 
						if (upperpath.dentry) {
 | 
				
			||||||
 | 
							rdd.dir = upperpath.dentry;
 | 
				
			||||||
		err = ovl_dir_read(&upperpath, &rdd);
 | 
							err = ovl_dir_read(&upperpath, &rdd);
 | 
				
			||||||
		if (err)
 | 
							if (err)
 | 
				
			||||||
			goto out;
 | 
								goto out;
 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (lowerpath.dentry) {
 | 
					 | 
				
			||||||
			err = ovl_dir_mark_whiteouts(upperpath.dentry, &rdd);
 | 
					 | 
				
			||||||
			if (err)
 | 
					 | 
				
			||||||
				goto out;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (lowerpath.dentry) {
 | 
						if (lowerpath.dentry) {
 | 
				
			||||||
		/*
 | 
							/*
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue