Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs

* '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

+63 -53
+11 -4
fs/ceph/super.c
··· 636 636 req->r_num_caps = 2; 637 637 err = ceph_mdsc_do_request(mdsc, NULL, req); 638 638 if (err == 0) { 639 + struct inode *inode = req->r_target_inode; 640 + req->r_target_inode = NULL; 639 641 dout("open_root_inode success\n"); 640 - if (ceph_ino(req->r_target_inode) == CEPH_INO_ROOT && 642 + if (ceph_ino(inode) == CEPH_INO_ROOT && 641 643 fsc->sb->s_root == NULL) { 642 - root = d_alloc_root(req->r_target_inode); 644 + root = d_alloc_root(inode); 645 + if (!root) { 646 + iput(inode); 647 + root = ERR_PTR(-ENOMEM); 648 + goto out; 649 + } 643 650 ceph_init_dentry(root); 644 651 } else { 645 - root = d_obtain_alias(req->r_target_inode); 652 + root = d_obtain_alias(inode); 646 653 } 647 - req->r_target_inode = NULL; 648 654 dout("open_root_inode success, root dentry is %p\n", root); 649 655 } else { 650 656 root = ERR_PTR(err); 651 657 } 658 + out: 652 659 ceph_mdsc_put_request(req); 653 660 return root; 654 661 }
+38 -42
fs/dcache.c
··· 276 276 } 277 277 } 278 278 279 - static void dentry_lru_move_tail(struct dentry *dentry) 279 + static void dentry_lru_move_list(struct dentry *dentry, struct list_head *list) 280 280 { 281 281 spin_lock(&dcache_lru_lock); 282 282 if (list_empty(&dentry->d_lru)) { 283 - list_add_tail(&dentry->d_lru, &dentry->d_sb->s_dentry_lru); 283 + list_add_tail(&dentry->d_lru, list); 284 284 dentry->d_sb->s_nr_dentry_unused++; 285 285 dentry_stat.nr_unused++; 286 286 } else { 287 - list_move_tail(&dentry->d_lru, &dentry->d_sb->s_dentry_lru); 287 + list_move_tail(&dentry->d_lru, list); 288 288 } 289 289 spin_unlock(&dcache_lru_lock); 290 290 } ··· 770 770 } 771 771 772 772 /** 773 - * __shrink_dcache_sb - shrink the dentry LRU on a given superblock 774 - * @sb: superblock to shrink dentry LRU. 775 - * @count: number of entries to prune 776 - * @flags: flags to control the dentry processing 773 + * prune_dcache_sb - shrink the dcache 774 + * @sb: superblock 775 + * @count: number of entries to try to free 777 776 * 778 - * If flags contains DCACHE_REFERENCED reference dentries will not be pruned. 777 + * Attempt to shrink the superblock dcache LRU by @count entries. This is 778 + * done when we need more memory an called from the superblock shrinker 779 + * function. 780 + * 781 + * This function may fail to free any resources if all the dentries are in 782 + * use. 779 783 */ 780 - static void __shrink_dcache_sb(struct super_block *sb, int count, int flags) 784 + void prune_dcache_sb(struct super_block *sb, int count) 781 785 { 782 786 struct dentry *dentry; 783 787 LIST_HEAD(referenced); ··· 800 796 goto relock; 801 797 } 802 798 803 - /* 804 - * If we are honouring the DCACHE_REFERENCED flag and the 805 - * dentry has this flag set, don't free it. Clear the flag 806 - * and put it back on the LRU. 807 - */ 808 - if (flags & DCACHE_REFERENCED && 809 - dentry->d_flags & DCACHE_REFERENCED) { 799 + if (dentry->d_flags & DCACHE_REFERENCED) { 810 800 dentry->d_flags &= ~DCACHE_REFERENCED; 811 801 list_move(&dentry->d_lru, &referenced); 812 802 spin_unlock(&dentry->d_lock); ··· 817 819 spin_unlock(&dcache_lru_lock); 818 820 819 821 shrink_dentry_list(&tmp); 820 - } 821 - 822 - /** 823 - * prune_dcache_sb - shrink the dcache 824 - * @sb: superblock 825 - * @nr_to_scan: number of entries to try to free 826 - * 827 - * Attempt to shrink the superblock dcache LRU by @nr_to_scan entries. This is 828 - * done when we need more memory an called from the superblock shrinker 829 - * function. 830 - * 831 - * This function may fail to free any resources if all the dentries are in 832 - * use. 833 - */ 834 - void prune_dcache_sb(struct super_block *sb, int nr_to_scan) 835 - { 836 - __shrink_dcache_sb(sb, nr_to_scan, DCACHE_REFERENCED); 837 822 } 838 823 839 824 /** ··· 1073 1092 * drop the lock and return early due to latency 1074 1093 * constraints. 1075 1094 */ 1076 - static int select_parent(struct dentry * parent) 1095 + static int select_parent(struct dentry *parent, struct list_head *dispose) 1077 1096 { 1078 1097 struct dentry *this_parent; 1079 1098 struct list_head *next; ··· 1095 1114 1096 1115 spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); 1097 1116 1098 - /* 1099 - * move only zero ref count dentries to the end 1100 - * of the unused list for prune_dcache 1117 + /* 1118 + * move only zero ref count dentries to the dispose list. 1101 1119 */ 1102 1120 if (!dentry->d_count) { 1103 - dentry_lru_move_tail(dentry); 1121 + dentry_lru_move_list(dentry, dispose); 1104 1122 found++; 1105 1123 } else { 1106 1124 dentry_lru_del(dentry); ··· 1161 1181 * 1162 1182 * Prune the dcache to remove unused children of the parent dentry. 1163 1183 */ 1164 - 1165 1184 void shrink_dcache_parent(struct dentry * parent) 1166 1185 { 1167 - struct super_block *sb = parent->d_sb; 1186 + LIST_HEAD(dispose); 1168 1187 int found; 1169 1188 1170 - while ((found = select_parent(parent)) != 0) 1171 - __shrink_dcache_sb(sb, found, 0); 1189 + while ((found = select_parent(parent, &dispose)) != 0) 1190 + shrink_dentry_list(&dispose); 1172 1191 } 1173 1192 EXPORT_SYMBOL(shrink_dcache_parent); 1174 1193 ··· 1439 1460 return res; 1440 1461 } 1441 1462 EXPORT_SYMBOL(d_alloc_root); 1463 + 1464 + struct dentry *d_make_root(struct inode *root_inode) 1465 + { 1466 + struct dentry *res = NULL; 1467 + 1468 + if (root_inode) { 1469 + static const struct qstr name = { .name = "/", .len = 1 }; 1470 + 1471 + res = __d_alloc(root_inode->i_sb, &name); 1472 + if (res) 1473 + d_instantiate(res, root_inode); 1474 + else 1475 + iput(root_inode); 1476 + } 1477 + return res; 1478 + } 1479 + EXPORT_SYMBOL(d_make_root); 1442 1480 1443 1481 static struct dentry * __d_find_any_alias(struct inode *inode) 1444 1482 {
+8 -5
fs/ext4/super.c
··· 3733 3733 } 3734 3734 if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) { 3735 3735 ext4_msg(sb, KERN_ERR, "corrupt root inode, run e2fsck"); 3736 + iput(root); 3736 3737 goto failed_mount4; 3737 3738 } 3738 3739 sb->s_root = d_alloc_root(root); 3739 3740 if (!sb->s_root) { 3741 + iput(root); 3740 3742 ext4_msg(sb, KERN_ERR, "get root dentry failed"); 3741 3743 ret = -ENOMEM; 3742 3744 goto failed_mount4; ··· 3775 3773 if (err) { 3776 3774 ext4_msg(sb, KERN_ERR, "failed to initialize system " 3777 3775 "zone (%d)", err); 3778 - goto failed_mount4; 3776 + goto failed_mount4a; 3779 3777 } 3780 3778 3781 3779 ext4_ext_init(sb); ··· 3832 3830 failed_mount7: 3833 3831 ext4_unregister_li_request(sb); 3834 3832 failed_mount6: 3835 - ext4_ext_release(sb); 3836 - failed_mount5: 3837 3833 ext4_mb_release(sb); 3834 + failed_mount5: 3835 + ext4_ext_release(sb); 3838 3836 ext4_release_system_zone(sb); 3839 - failed_mount4: 3840 - iput(root); 3837 + failed_mount4a: 3838 + dput(sb->s_root); 3841 3839 sb->s_root = NULL; 3840 + failed_mount4: 3842 3841 ext4_msg(sb, KERN_ERR, "mount failed"); 3843 3842 destroy_workqueue(EXT4_SB(sb)->dio_unwritten_wq); 3844 3843 failed_mount_wq:
+5 -2
fs/isofs/inode.c
··· 948 948 949 949 /* get the root dentry */ 950 950 s->s_root = d_alloc_root(inode); 951 - if (!(s->s_root)) 952 - goto out_no_root; 951 + if (!(s->s_root)) { 952 + iput(inode); 953 + error = -ENOMEM; 954 + goto out_no_inode; 955 + } 953 956 954 957 kfree(opt.iocharset); 955 958
+1
include/linux/dcache.h
··· 249 249 250 250 /* only used at mount-time */ 251 251 extern struct dentry * d_alloc_root(struct inode *); 252 + extern struct dentry * d_make_root(struct inode *); 252 253 253 254 /* <clickety>-<click> the ramfs-type tree */ 254 255 extern void d_genocide(struct dentry *);