]> git.karo-electronics.de Git - linux-beck.git/commitdiff
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 10 Jan 2012 01:37:37 +0000 (17:37 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 10 Jan 2012 01:37:37 +0000 (17:37 -0800)
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
  vfs: new helper - d_make_root()
  dcache: use a dispose list in select_parent
  ceph: d_alloc_root() may fail
  ext4: fix failure exits
  isofs: inode leak on mount failure

fs/ceph/super.c
fs/dcache.c
fs/ext4/super.c
fs/isofs/inode.c
include/linux/dcache.h

index 11bd0fc4853fbbcbbceb3b2b1cd424a16d17de32..48f61a12af66eecdd57f792c2b5da44d5c86468f 100644 (file)
@@ -636,19 +636,26 @@ static struct dentry *open_root_dentry(struct ceph_fs_client *fsc,
        req->r_num_caps = 2;
        err = ceph_mdsc_do_request(mdsc, NULL, req);
        if (err == 0) {
+               struct inode *inode = req->r_target_inode;
+               req->r_target_inode = NULL;
                dout("open_root_inode success\n");
-               if (ceph_ino(req->r_target_inode) == CEPH_INO_ROOT &&
+               if (ceph_ino(inode) == CEPH_INO_ROOT &&
                    fsc->sb->s_root == NULL) {
-                       root = d_alloc_root(req->r_target_inode);
+                       root = d_alloc_root(inode);
+                       if (!root) {
+                               iput(inode);
+                               root = ERR_PTR(-ENOMEM);
+                               goto out;
+                       }
                        ceph_init_dentry(root);
                } else {
-                       root = d_obtain_alias(req->r_target_inode);
+                       root = d_obtain_alias(inode);
                }
-               req->r_target_inode = NULL;
                dout("open_root_inode success, root dentry is %p\n", root);
        } else {
                root = ERR_PTR(err);
        }
+out:
        ceph_mdsc_put_request(req);
        return root;
 }
index 9791b1e7eee467cb97f243c6311e5624944b38db..3c6d3113a255c7af1519fdb6aa1c211ec092e992 100644 (file)
@@ -276,15 +276,15 @@ static void dentry_lru_prune(struct dentry *dentry)
        }
 }
 
-static void dentry_lru_move_tail(struct dentry *dentry)
+static void dentry_lru_move_list(struct dentry *dentry, struct list_head *list)
 {
        spin_lock(&dcache_lru_lock);
        if (list_empty(&dentry->d_lru)) {
-               list_add_tail(&dentry->d_lru, &dentry->d_sb->s_dentry_lru);
+               list_add_tail(&dentry->d_lru, list);
                dentry->d_sb->s_nr_dentry_unused++;
                dentry_stat.nr_unused++;
        } else {
-               list_move_tail(&dentry->d_lru, &dentry->d_sb->s_dentry_lru);
+               list_move_tail(&dentry->d_lru, list);
        }
        spin_unlock(&dcache_lru_lock);
 }
@@ -770,14 +770,18 @@ static void shrink_dentry_list(struct list_head *list)
 }
 
 /**
- * __shrink_dcache_sb - shrink the dentry LRU on a given superblock
- * @sb:                superblock to shrink dentry LRU.
- * @count:     number of entries to prune
- * @flags:     flags to control the dentry processing
+ * prune_dcache_sb - shrink the dcache
+ * @sb: superblock
+ * @count: number of entries to try to free
+ *
+ * Attempt to shrink the superblock dcache LRU by @count entries. This is
+ * done when we need more memory an called from the superblock shrinker
+ * function.
  *
- * If flags contains DCACHE_REFERENCED reference dentries will not be pruned.
+ * This function may fail to free any resources if all the dentries are in
+ * use.
  */
-static void __shrink_dcache_sb(struct super_block *sb, int count, int flags)
+void prune_dcache_sb(struct super_block *sb, int count)
 {
        struct dentry *dentry;
        LIST_HEAD(referenced);
@@ -796,13 +800,7 @@ relock:
                        goto relock;
                }
 
-               /*
-                * If we are honouring the DCACHE_REFERENCED flag and the
-                * dentry has this flag set, don't free it.  Clear the flag
-                * and put it back on the LRU.
-                */
-               if (flags & DCACHE_REFERENCED &&
-                               dentry->d_flags & DCACHE_REFERENCED) {
+               if (dentry->d_flags & DCACHE_REFERENCED) {
                        dentry->d_flags &= ~DCACHE_REFERENCED;
                        list_move(&dentry->d_lru, &referenced);
                        spin_unlock(&dentry->d_lock);
@@ -821,23 +819,6 @@ relock:
        shrink_dentry_list(&tmp);
 }
 
-/**
- * prune_dcache_sb - shrink the dcache
- * @sb: superblock
- * @nr_to_scan: number of entries to try to free
- *
- * Attempt to shrink the superblock dcache LRU by @nr_to_scan entries. This is
- * done when we need more memory an called from the superblock shrinker
- * function.
- *
- * This function may fail to free any resources if all the dentries are in
- * use.
- */
-void prune_dcache_sb(struct super_block *sb, int nr_to_scan)
-{
-       __shrink_dcache_sb(sb, nr_to_scan, DCACHE_REFERENCED);
-}
-
 /**
  * shrink_dcache_sb - shrink dcache for a superblock
  * @sb: superblock
@@ -1092,7 +1073,7 @@ EXPORT_SYMBOL(have_submounts);
  * drop the lock and return early due to latency
  * constraints.
  */
-static int select_parent(struct dentry * parent)
+static int select_parent(struct dentry *parent, struct list_head *dispose)
 {
        struct dentry *this_parent;
        struct list_head *next;
@@ -1114,12 +1095,11 @@ resume:
 
                spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
 
-               /* 
-                * move only zero ref count dentries to the end 
-                * of the unused list for prune_dcache
+               /*
+                * move only zero ref count dentries to the dispose list.
                 */
                if (!dentry->d_count) {
-                       dentry_lru_move_tail(dentry);
+                       dentry_lru_move_list(dentry, dispose);
                        found++;
                } else {
                        dentry_lru_del(dentry);
@@ -1181,14 +1161,13 @@ rename_retry:
  *
  * Prune the dcache to remove unused children of the parent dentry.
  */
 void shrink_dcache_parent(struct dentry * parent)
 {
-       struct super_block *sb = parent->d_sb;
+       LIST_HEAD(dispose);
        int found;
 
-       while ((found = select_parent(parent)) != 0)
-               __shrink_dcache_sb(sb, found, 0);
+       while ((found = select_parent(parent, &dispose)) != 0)
+               shrink_dentry_list(&dispose);
 }
 EXPORT_SYMBOL(shrink_dcache_parent);
 
@@ -1461,6 +1440,23 @@ struct dentry * d_alloc_root(struct inode * root_inode)
 }
 EXPORT_SYMBOL(d_alloc_root);
 
+struct dentry *d_make_root(struct inode *root_inode)
+{
+       struct dentry *res = NULL;
+
+       if (root_inode) {
+               static const struct qstr name = { .name = "/", .len = 1 };
+
+               res = __d_alloc(root_inode->i_sb, &name);
+               if (res)
+                       d_instantiate(res, root_inode);
+               else
+                       iput(root_inode);
+       }
+       return res;
+}
+EXPORT_SYMBOL(d_make_root);
+
 static struct dentry * __d_find_any_alias(struct inode *inode)
 {
        struct dentry *alias;
index 64e2529ae9bbd861aca945a609fa7c7fc251d919..ed3ce82e2de4ce8ef303075028db8651a1571e17 100644 (file)
@@ -3733,10 +3733,12 @@ no_journal:
        }
        if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) {
                ext4_msg(sb, KERN_ERR, "corrupt root inode, run e2fsck");
+               iput(root);
                goto failed_mount4;
        }
        sb->s_root = d_alloc_root(root);
        if (!sb->s_root) {
+               iput(root);
                ext4_msg(sb, KERN_ERR, "get root dentry failed");
                ret = -ENOMEM;
                goto failed_mount4;
@@ -3773,7 +3775,7 @@ no_journal:
        if (err) {
                ext4_msg(sb, KERN_ERR, "failed to initialize system "
                         "zone (%d)", err);
-               goto failed_mount4;
+               goto failed_mount4a;
        }
 
        ext4_ext_init(sb);
@@ -3830,13 +3832,14 @@ cantfind_ext4:
 failed_mount7:
        ext4_unregister_li_request(sb);
 failed_mount6:
-       ext4_ext_release(sb);
-failed_mount5:
        ext4_mb_release(sb);
+failed_mount5:
+       ext4_ext_release(sb);
        ext4_release_system_zone(sb);
-failed_mount4:
-       iput(root);
+failed_mount4a:
+       dput(sb->s_root);
        sb->s_root = NULL;
+failed_mount4:
        ext4_msg(sb, KERN_ERR, "mount failed");
        destroy_workqueue(EXT4_SB(sb)->dio_unwritten_wq);
 failed_mount_wq:
index 7b99f5f460be1bfeab87c80e01bec6cb2870f7ee..bd62c76fb5df8a08d8d11bdae311ecc8a3054039 100644 (file)
@@ -948,8 +948,11 @@ root_found:
 
        /* get the root dentry */
        s->s_root = d_alloc_root(inode);
-       if (!(s->s_root))
-               goto out_no_root;
+       if (!(s->s_root)) {
+               iput(inode);
+               error = -ENOMEM;
+               goto out_no_inode;
+       }
 
        kfree(opt.iocharset);
 
index ed9f74f6c519a1f071348d691d69c7ed5795e938..a47bda5f76db125288898fb1aea2f098bc2dfa42 100644 (file)
@@ -249,6 +249,7 @@ extern int d_invalidate(struct dentry *);
 
 /* only used at mount-time */
 extern struct dentry * d_alloc_root(struct inode *);
+extern struct dentry * d_make_root(struct inode *);
 
 /* <clickety>-<click> the ramfs-type tree */
 extern void d_genocide(struct dentry *);