diff options
Diffstat (limited to 'fs/cachefiles/namei.c')
| -rw-r--r-- | fs/cachefiles/namei.c | 98 | 
1 files changed, 86 insertions, 12 deletions
diff --git a/fs/cachefiles/namei.c b/fs/cachefiles/namei.c index d5db84a1ee0d..f4a7840bf42c 100644 --- a/fs/cachefiles/namei.c +++ b/fs/cachefiles/namei.c @@ -93,6 +93,59 @@ static noinline void cachefiles_printk_object(struct cachefiles_object *object,  }  /* + * mark the owner of a dentry, if there is one, to indicate that that dentry + * has been preemptively deleted + * - the caller must hold the i_mutex on the dentry's parent as required to + *   call vfs_unlink(), vfs_rmdir() or vfs_rename() + */ +static void cachefiles_mark_object_buried(struct cachefiles_cache *cache, +					  struct dentry *dentry) +{ +	struct cachefiles_object *object; +	struct rb_node *p; + +	_enter(",'%*.*s'", +	       dentry->d_name.len, dentry->d_name.len, dentry->d_name.name); + +	write_lock(&cache->active_lock); + +	p = cache->active_nodes.rb_node; +	while (p) { +		object = rb_entry(p, struct cachefiles_object, active_node); +		if (object->dentry > dentry) +			p = p->rb_left; +		else if (object->dentry < dentry) +			p = p->rb_right; +		else +			goto found_dentry; +	} + +	write_unlock(&cache->active_lock); +	_leave(" [no owner]"); +	return; + +	/* found the dentry for  */ +found_dentry: +	kdebug("preemptive burial: OBJ%x [%s] %p", +	       object->fscache.debug_id, +	       fscache_object_states[object->fscache.state], +	       dentry); + +	if (object->fscache.state < FSCACHE_OBJECT_DYING) { +		printk(KERN_ERR "\n"); +		printk(KERN_ERR "CacheFiles: Error:" +		       " Can't preemptively bury live object\n"); +		cachefiles_printk_object(object, NULL); +	} else if (test_and_set_bit(CACHEFILES_OBJECT_BURIED, &object->flags)) { +		printk(KERN_ERR "CacheFiles: Error:" +		       " Object already preemptively buried\n"); +	} + +	write_unlock(&cache->active_lock); +	_leave(" [owner marked]"); +} + +/*   * record the fact that an object is now active   */  static int cachefiles_mark_object_active(struct cachefiles_cache *cache, @@ -219,7 +272,8 @@ requeue:   */  static int cachefiles_bury_object(struct cachefiles_cache *cache,  				  struct dentry *dir, -				  struct dentry *rep) +				  struct dentry *rep, +				  bool preemptive)  {  	struct dentry *grave, *trap;  	char nbuffer[8 + 8 + 1]; @@ -229,11 +283,16 @@ static int cachefiles_bury_object(struct cachefiles_cache *cache,  	       dir->d_name.len, dir->d_name.len, dir->d_name.name,  	       rep->d_name.len, rep->d_name.len, rep->d_name.name); +	_debug("remove %p from %p", rep, dir); +  	/* non-directories can just be unlinked */  	if (!S_ISDIR(rep->d_inode->i_mode)) {  		_debug("unlink stale object");  		ret = vfs_unlink(dir->d_inode, rep); +		if (preemptive) +			cachefiles_mark_object_buried(cache, rep); +  		mutex_unlock(&dir->d_inode->i_mutex);  		if (ret == -EIO) @@ -325,6 +384,9 @@ try_again:  	if (ret != 0 && ret != -ENOMEM)  		cachefiles_io_error(cache, "Rename failed with error %d", ret); +	if (preemptive) +		cachefiles_mark_object_buried(cache, rep); +  	unlock_rename(cache->graveyard, dir);  	dput(grave);  	_leave(" = 0"); @@ -340,7 +402,7 @@ int cachefiles_delete_object(struct cachefiles_cache *cache,  	struct dentry *dir;  	int ret; -	_enter(",{%p}", object->dentry); +	_enter(",OBJ%x{%p}", object->fscache.debug_id, object->dentry);  	ASSERT(object->dentry);  	ASSERT(object->dentry->d_inode); @@ -350,15 +412,25 @@ int cachefiles_delete_object(struct cachefiles_cache *cache,  	mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT); -	/* we need to check that our parent is _still_ our parent - it may have -	 * been renamed */ -	if (dir == object->dentry->d_parent) { -		ret = cachefiles_bury_object(cache, dir, object->dentry); -	} else { -		/* it got moved, presumably by cachefilesd culling it, so it's -		 * no longer in the key path and we can ignore it */ +	if (test_bit(CACHEFILES_OBJECT_BURIED, &object->flags)) { +		/* object allocation for the same key preemptively deleted this +		 * object's file so that it could create its own file */ +		_debug("object preemptively buried");  		mutex_unlock(&dir->d_inode->i_mutex);  		ret = 0; +	} else { +		/* we need to check that our parent is _still_ our parent - it +		 * may have been renamed */ +		if (dir == object->dentry->d_parent) { +			ret = cachefiles_bury_object(cache, dir, +						     object->dentry, false); +		} else { +			/* it got moved, presumably by cachefilesd culling it, +			 * so it's no longer in the key path and we can ignore +			 * it */ +			mutex_unlock(&dir->d_inode->i_mutex); +			ret = 0; +		}  	}  	dput(dir); @@ -381,7 +453,9 @@ int cachefiles_walk_to_object(struct cachefiles_object *parent,  	const char *name;  	int ret, nlen; -	_enter("{%p},,%s,", parent->dentry, key); +	_enter("OBJ%x{%p},OBJ%x,%s,", +	       parent->fscache.debug_id, parent->dentry, +	       object->fscache.debug_id, key);  	cache = container_of(parent->fscache.cache,  			     struct cachefiles_cache, cache); @@ -509,7 +583,7 @@ lookup_again:  			 * mutex) */  			object->dentry = NULL; -			ret = cachefiles_bury_object(cache, dir, next); +			ret = cachefiles_bury_object(cache, dir, next, true);  			dput(next);  			next = NULL; @@ -828,7 +902,7 @@ int cachefiles_cull(struct cachefiles_cache *cache, struct dentry *dir,  	/*  actually remove the victim (drops the dir mutex) */  	_debug("bury"); -	ret = cachefiles_bury_object(cache, dir, victim); +	ret = cachefiles_bury_object(cache, dir, victim, false);  	if (ret < 0)  		goto error;  | 
