Merge branch 'fscache-fixes' into for-next
authorAl Viro <viro@zeniv.linux.org.uk>
Tue, 23 Jun 2015 22:01:30 +0000 (18:01 -0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Tue, 23 Jun 2015 22:01:30 +0000 (18:01 -0400)
1  2 
fs/cachefiles/namei.c

diff --combined fs/cachefiles/namei.c
index ab857ab9f40d91a375a31030e1872f9ebd704837,1d60195fc5187f8b95191e89d3f400d8d9b9ee3a..fc1056f5c96a3c750c3c5c9009048b234a7fd745
@@@ -97,7 -97,8 +97,8 @@@ static noinline void cachefiles_printk_
   *   call vfs_unlink(), vfs_rmdir() or vfs_rename()
   */
  static void cachefiles_mark_object_buried(struct cachefiles_cache *cache,
-                                         struct dentry *dentry)
+                                         struct dentry *dentry,
+                                         enum fscache_why_object_killed why)
  {
        struct cachefiles_object *object;
        struct rb_node *p;
@@@ -132,8 -133,9 +133,9 @@@ found_dentry
                pr_err("\n");
                pr_err("Error: Can't preemptively bury live object\n");
                cachefiles_printk_object(object, NULL);
-       } else if (test_and_set_bit(CACHEFILES_OBJECT_BURIED, &object->flags)) {
-               pr_err("Error: Object already preemptively buried\n");
+       } else {
+               if (why != FSCACHE_OBJECT_IS_STALE)
+                       fscache_object_mark_killed(&object->fscache, why);
        }
  
        write_unlock(&cache->active_lock);
@@@ -265,7 -267,8 +267,8 @@@ requeue
  static int cachefiles_bury_object(struct cachefiles_cache *cache,
                                  struct dentry *dir,
                                  struct dentry *rep,
-                                 bool preemptive)
+                                 bool preemptive,
+                                 enum fscache_why_object_killed why)
  {
        struct dentry *grave, *trap;
        struct path path, path_to_graveyard;
        _debug("remove %p from %p", rep, dir);
  
        /* non-directories can just be unlinked */
 -      if (!S_ISDIR(rep->d_inode->i_mode)) {
 +      if (!d_is_dir(rep)) {
                _debug("unlink stale object");
  
                path.mnt = cache->mnt;
                if (ret < 0) {
                        cachefiles_io_error(cache, "Unlink security error");
                } else {
 -                      ret = vfs_unlink(dir->d_inode, rep, NULL);
 +                      ret = vfs_unlink(d_inode(dir), rep, NULL);
  
                        if (preemptive)
-                               cachefiles_mark_object_buried(cache, rep);
+                               cachefiles_mark_object_buried(cache, rep, why);
                }
  
 -              mutex_unlock(&dir->d_inode->i_mutex);
 +              mutex_unlock(&d_inode(dir)->i_mutex);
  
                if (ret == -EIO)
                        cachefiles_io_error(cache, "Unlink failed");
  
        /* directories have to be moved to the graveyard */
        _debug("move stale object to graveyard");
 -      mutex_unlock(&dir->d_inode->i_mutex);
 +      mutex_unlock(&d_inode(dir)->i_mutex);
  
  try_again:
        /* first step is to make up a grave dentry in the graveyard */
                return 0;
        }
  
 -      if (!S_ISDIR(cache->graveyard->d_inode->i_mode)) {
 +      if (!d_can_lookup(cache->graveyard)) {
                unlock_rename(cache->graveyard, dir);
                cachefiles_io_error(cache, "Graveyard no longer a directory");
                return -EIO;
                return -EIO;
        }
  
 -      if (grave->d_inode) {
 +      if (d_is_positive(grave)) {
                unlock_rename(cache->graveyard, dir);
                dput(grave);
                grave = NULL;
        if (ret < 0) {
                cachefiles_io_error(cache, "Rename security error %d", ret);
        } else {
 -              ret = vfs_rename(dir->d_inode, rep,
 -                               cache->graveyard->d_inode, grave, NULL, 0);
 +              ret = vfs_rename(d_inode(dir), rep,
 +                               d_inode(cache->graveyard), grave, NULL, 0);
                if (ret != 0 && ret != -ENOMEM)
                        cachefiles_io_error(cache,
                                            "Rename failed with error %d", ret);
  
                if (preemptive)
-                       cachefiles_mark_object_buried(cache, rep);
+                       cachefiles_mark_object_buried(cache, rep, why);
        }
  
        unlock_rename(cache->graveyard, dir);
@@@ -415,30 -418,31 +418,31 @@@ int cachefiles_delete_object(struct cac
        _enter(",OBJ%x{%p}", object->fscache.debug_id, object->dentry);
  
        ASSERT(object->dentry);
 -      ASSERT(object->dentry->d_inode);
 +      ASSERT(d_backing_inode(object->dentry));
        ASSERT(object->dentry->d_parent);
  
        dir = dget_parent(object->dentry);
  
 -      mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT);
 +      mutex_lock_nested(&d_inode(dir)->i_mutex, I_MUTEX_PARENT);
  
-       if (test_bit(CACHEFILES_OBJECT_BURIED, &object->flags)) {
+       if (test_bit(FSCACHE_OBJECT_KILLED_BY_CACHE, &object->fscache.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);
 +              mutex_unlock(&d_inode(dir)->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);
+                                                    object->dentry, false,
+                                                    FSCACHE_OBJECT_WAS_RETIRED);
                } 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);
 +                      mutex_unlock(&d_inode(dir)->i_mutex);
                        ret = 0;
                }
        }
@@@ -473,9 -477,9 +477,9 @@@ int cachefiles_walk_to_object(struct ca
        path.mnt = cache->mnt;
  
        ASSERT(parent->dentry);
 -      ASSERT(parent->dentry->d_inode);
 +      ASSERT(d_backing_inode(parent->dentry));
  
 -      if (!(S_ISDIR(parent->dentry->d_inode->i_mode))) {
 +      if (!(d_is_dir(parent->dentry))) {
                // TODO: convert file to dir
                _leave("looking up in none directory");
                return -ENOBUFS;
@@@ -497,7 -501,7 +501,7 @@@ lookup_again
        /* search the current directory for the element name */
        _debug("lookup '%s'", name);
  
 -      mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT);
 +      mutex_lock_nested(&d_inode(dir)->i_mutex, I_MUTEX_PARENT);
  
        start = jiffies;
        next = lookup_one_len(name, dir, nlen);
        if (IS_ERR(next))
                goto lookup_error;
  
 -      _debug("next -> %p %s", next, next->d_inode ? "positive" : "negative");
 +      _debug("next -> %p %s", next, d_backing_inode(next) ? "positive" : "negative");
  
        if (!key)
 -              object->new = !next->d_inode;
 +              object->new = !d_backing_inode(next);
  
        /* if this element of the path doesn't exist, then the lookup phase
         * failed, and we can release any readers in the certain knowledge that
         * there's nothing for them to actually read */
 -      if (!next->d_inode)
 +      if (d_is_negative(next))
                fscache_object_lookup_negative(&object->fscache);
  
        /* we need to create the object if it's negative */
        if (key || object->type == FSCACHE_COOKIE_TYPE_INDEX) {
                /* index objects and intervening tree levels must be subdirs */
 -              if (!next->d_inode) {
 +              if (d_is_negative(next)) {
                        ret = cachefiles_has_space(cache, 1, 0);
                        if (ret < 0)
-                               goto create_error;
+                               goto no_space_error;
  
                        path.dentry = dir;
                        ret = security_path_mkdir(&path, next, 0);
                        if (ret < 0)
                                goto create_error;
                        start = jiffies;
 -                      ret = vfs_mkdir(dir->d_inode, next, 0);
 +                      ret = vfs_mkdir(d_inode(dir), next, 0);
                        cachefiles_hist(cachefiles_mkdir_histogram, start);
                        if (ret < 0)
                                goto create_error;
  
 -                      ASSERT(next->d_inode);
 +                      ASSERT(d_backing_inode(next));
  
                        _debug("mkdir -> %p{%p{ino=%lu}}",
 -                             next, next->d_inode, next->d_inode->i_ino);
 +                             next, d_backing_inode(next), d_backing_inode(next)->i_ino);
  
 -              } else if (!S_ISDIR(next->d_inode->i_mode)) {
 +              } else if (!d_can_lookup(next)) {
                        pr_err("inode %lu is not a directory\n",
 -                             next->d_inode->i_ino);
 +                             d_backing_inode(next)->i_ino);
                        ret = -ENOBUFS;
                        goto error;
                }
  
        } else {
                /* non-index objects start out life as files */
 -              if (!next->d_inode) {
 +              if (d_is_negative(next)) {
                        ret = cachefiles_has_space(cache, 1, 0);
                        if (ret < 0)
-                               goto create_error;
+                               goto no_space_error;
  
                        path.dentry = dir;
                        ret = security_path_mknod(&path, next, S_IFREG, 0);
                        if (ret < 0)
                                goto create_error;
                        start = jiffies;
 -                      ret = vfs_create(dir->d_inode, next, S_IFREG, true);
 +                      ret = vfs_create(d_inode(dir), next, S_IFREG, true);
                        cachefiles_hist(cachefiles_create_histogram, start);
                        if (ret < 0)
                                goto create_error;
  
 -                      ASSERT(next->d_inode);
 +                      ASSERT(d_backing_inode(next));
  
                        _debug("create -> %p{%p{ino=%lu}}",
 -                             next, next->d_inode, next->d_inode->i_ino);
 +                             next, d_backing_inode(next), d_backing_inode(next)->i_ino);
  
 -              } else if (!S_ISDIR(next->d_inode->i_mode) &&
 -                         !S_ISREG(next->d_inode->i_mode)
 +              } else if (!d_can_lookup(next) &&
 +                         !d_is_reg(next)
                           ) {
                        pr_err("inode %lu is not a file or directory\n",
 -                             next->d_inode->i_ino);
 +                             d_backing_inode(next)->i_ino);
                        ret = -ENOBUFS;
                        goto error;
                }
        /* process the next component */
        if (key) {
                _debug("advance");
 -              mutex_unlock(&dir->d_inode->i_mutex);
 +              mutex_unlock(&d_inode(dir)->i_mutex);
                dput(dir);
                dir = next;
                next = NULL;
                         * mutex) */
                        object->dentry = NULL;
  
-                       ret = cachefiles_bury_object(cache, dir, next, true);
+                       ret = cachefiles_bury_object(cache, dir, next, true,
+                                                    FSCACHE_OBJECT_IS_STALE);
                        dput(next);
                        next = NULL;
  
                                goto delete_error;
  
                        _debug("redo lookup");
+                       fscache_object_retrying_stale(&object->fscache);
                        goto lookup_again;
                }
        }
        /* note that we're now using this object */
        ret = cachefiles_mark_object_active(cache, object);
  
 -      mutex_unlock(&dir->d_inode->i_mutex);
 +      mutex_unlock(&d_inode(dir)->i_mutex);
        dput(dir);
        dir = NULL;
  
  
        /* open a file interface onto a data file */
        if (object->type != FSCACHE_COOKIE_TYPE_INDEX) {
 -              if (S_ISREG(object->dentry->d_inode->i_mode)) {
 +              if (d_is_reg(object->dentry)) {
                        const struct address_space_operations *aops;
  
                        ret = -EPERM;
 -                      aops = object->dentry->d_inode->i_mapping->a_ops;
 +                      aops = d_backing_inode(object->dentry)->i_mapping->a_ops;
                        if (!aops->bmap)
                                goto check_error;
  
        object->new = 0;
        fscache_obtained_object(&object->fscache);
  
 -      _leave(" = 0 [%lu]", object->dentry->d_inode->i_ino);
 +      _leave(" = 0 [%lu]", d_backing_inode(object->dentry)->i_ino);
        return 0;
  
+ no_space_error:
+       fscache_object_mark_killed(&object->fscache, FSCACHE_OBJECT_NO_SPACE);
  create_error:
        _debug("create error %d", ret);
        if (ret == -EIO)
@@@ -695,7 -703,7 +703,7 @@@ lookup_error
                cachefiles_io_error(cache, "Lookup failed");
        next = NULL;
  error:
 -      mutex_unlock(&dir->d_inode->i_mutex);
 +      mutex_unlock(&d_inode(dir)->i_mutex);
        dput(next);
  error_out2:
        dput(dir);
@@@ -719,7 -727,7 +727,7 @@@ struct dentry *cachefiles_get_directory
        _enter(",,%s", dirname);
  
        /* search the current directory for the element name */
 -      mutex_lock(&dir->d_inode->i_mutex);
 +      mutex_lock(&d_inode(dir)->i_mutex);
  
        start = jiffies;
        subdir = lookup_one_len(dirname, dir, strlen(dirname));
        }
  
        _debug("subdir -> %p %s",
 -             subdir, subdir->d_inode ? "positive" : "negative");
 +             subdir, d_backing_inode(subdir) ? "positive" : "negative");
  
        /* we need to create the subdir if it doesn't exist yet */
 -      if (!subdir->d_inode) {
 +      if (d_is_negative(subdir)) {
                ret = cachefiles_has_space(cache, 1, 0);
                if (ret < 0)
                        goto mkdir_error;
                ret = security_path_mkdir(&path, subdir, 0700);
                if (ret < 0)
                        goto mkdir_error;
 -              ret = vfs_mkdir(dir->d_inode, subdir, 0700);
 +              ret = vfs_mkdir(d_inode(dir), subdir, 0700);
                if (ret < 0)
                        goto mkdir_error;
  
 -              ASSERT(subdir->d_inode);
 +              ASSERT(d_backing_inode(subdir));
  
                _debug("mkdir -> %p{%p{ino=%lu}}",
                       subdir,
 -                     subdir->d_inode,
 -                     subdir->d_inode->i_ino);
 +                     d_backing_inode(subdir),
 +                     d_backing_inode(subdir)->i_ino);
        }
  
 -      mutex_unlock(&dir->d_inode->i_mutex);
 +      mutex_unlock(&d_inode(dir)->i_mutex);
  
        /* we need to make sure the subdir is a directory */
 -      ASSERT(subdir->d_inode);
 +      ASSERT(d_backing_inode(subdir));
  
 -      if (!S_ISDIR(subdir->d_inode->i_mode)) {
 +      if (!d_can_lookup(subdir)) {
                pr_err("%s is not a directory\n", dirname);
                ret = -EIO;
                goto check_error;
        }
  
        ret = -EPERM;
 -      if (!subdir->d_inode->i_op->setxattr ||
 -          !subdir->d_inode->i_op->getxattr ||
 -          !subdir->d_inode->i_op->lookup ||
 -          !subdir->d_inode->i_op->mkdir ||
 -          !subdir->d_inode->i_op->create ||
 -          (!subdir->d_inode->i_op->rename &&
 -           !subdir->d_inode->i_op->rename2) ||
 -          !subdir->d_inode->i_op->rmdir ||
 -          !subdir->d_inode->i_op->unlink)
 +      if (!d_backing_inode(subdir)->i_op->setxattr ||
 +          !d_backing_inode(subdir)->i_op->getxattr ||
 +          !d_backing_inode(subdir)->i_op->lookup ||
 +          !d_backing_inode(subdir)->i_op->mkdir ||
 +          !d_backing_inode(subdir)->i_op->create ||
 +          (!d_backing_inode(subdir)->i_op->rename &&
 +           !d_backing_inode(subdir)->i_op->rename2) ||
 +          !d_backing_inode(subdir)->i_op->rmdir ||
 +          !d_backing_inode(subdir)->i_op->unlink)
                goto check_error;
  
 -      _leave(" = [%lu]", subdir->d_inode->i_ino);
 +      _leave(" = [%lu]", d_backing_inode(subdir)->i_ino);
        return subdir;
  
  check_error:
        return ERR_PTR(ret);
  
  mkdir_error:
 -      mutex_unlock(&dir->d_inode->i_mutex);
 +      mutex_unlock(&d_inode(dir)->i_mutex);
        dput(subdir);
        pr_err("mkdir %s failed with error %d\n", dirname, ret);
        return ERR_PTR(ret);
  
  lookup_error:
 -      mutex_unlock(&dir->d_inode->i_mutex);
 +      mutex_unlock(&d_inode(dir)->i_mutex);
        ret = PTR_ERR(subdir);
        pr_err("Lookup %s failed with error %d\n", dirname, ret);
        return ERR_PTR(ret);
  
  nomem_d_alloc:
 -      mutex_unlock(&dir->d_inode->i_mutex);
 +      mutex_unlock(&d_inode(dir)->i_mutex);
        _leave(" = -ENOMEM");
        return ERR_PTR(-ENOMEM);
  }
@@@ -827,7 -835,7 +835,7 @@@ static struct dentry *cachefiles_check_
        //       dir, filename);
  
        /* look up the victim */
 -      mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT);
 +      mutex_lock_nested(&d_inode(dir)->i_mutex, I_MUTEX_PARENT);
  
        start = jiffies;
        victim = lookup_one_len(filename, dir, strlen(filename));
                goto lookup_error;
  
        //_debug("victim -> %p %s",
 -      //       victim, victim->d_inode ? "positive" : "negative");
 +      //       victim, d_backing_inode(victim) ? "positive" : "negative");
  
        /* if the object is no longer there then we probably retired the object
         * at the netfs's request whilst the cull was in progress
         */
 -      if (!victim->d_inode) {
 -              mutex_unlock(&dir->d_inode->i_mutex);
 +      if (d_is_negative(victim)) {
 +              mutex_unlock(&d_inode(dir)->i_mutex);
                dput(victim);
                _leave(" = -ENOENT [absent]");
                return ERR_PTR(-ENOENT);
  
  object_in_use:
        read_unlock(&cache->active_lock);
 -      mutex_unlock(&dir->d_inode->i_mutex);
 +      mutex_unlock(&d_inode(dir)->i_mutex);
        dput(victim);
        //_leave(" = -EBUSY [in use]");
        return ERR_PTR(-EBUSY);
  
  lookup_error:
 -      mutex_unlock(&dir->d_inode->i_mutex);
 +      mutex_unlock(&d_inode(dir)->i_mutex);
        ret = PTR_ERR(victim);
        if (ret == -ENOENT) {
                /* file or dir now absent - probably retired by netfs */
@@@ -913,7 -921,7 +921,7 @@@ int cachefiles_cull(struct cachefiles_c
                return PTR_ERR(victim);
  
        _debug("victim -> %p %s",
 -             victim, victim->d_inode ? "positive" : "negative");
 +             victim, d_backing_inode(victim) ? "positive" : "negative");
  
        /* okay... the victim is not being used so we can cull it
         * - start by marking it as stale
        /*  actually remove the victim (drops the dir mutex) */
        _debug("bury");
  
-       ret = cachefiles_bury_object(cache, dir, victim, false);
+       ret = cachefiles_bury_object(cache, dir, victim, false,
+                                    FSCACHE_OBJECT_WAS_CULLED);
        if (ret < 0)
                goto error;
  
        return 0;
  
  error_unlock:
 -      mutex_unlock(&dir->d_inode->i_mutex);
 +      mutex_unlock(&d_inode(dir)->i_mutex);
  error:
        dput(victim);
        if (ret == -ENOENT) {
@@@ -971,7 -980,7 +980,7 @@@ int cachefiles_check_in_use(struct cach
        if (IS_ERR(victim))
                return PTR_ERR(victim);
  
 -      mutex_unlock(&dir->d_inode->i_mutex);
 +      mutex_unlock(&d_inode(dir)->i_mutex);
        dput(victim);
        //_leave(" = 0");
        return 0;