|
@@ -92,6 +92,59 @@ static noinline void cachefiles_printk_object(struct cachefiles_object *object,
|
|
|
kfree(keybuf);
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * 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
|
|
|
*/
|
|
@@ -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;
|
|
|
|