Whamcloud - gitweb
LU-6722 ldiskfs: fix credits at ldiskfs_delete_inode
[fs/lustre-release.git] / ldiskfs / kernel_patches / patches / rhel6.5 / ext4-give-warning-with-dir-htree-growing.patch
1 diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
2 index 938487a..47313fd 100644
3 --- a/fs/ext4/ext4.h
4 +++ b/fs/ext4/ext4.h
5 @@ -1178,6 +1178,7 @@ struct ext4_sb_info {
6         unsigned int s_mb_group_prealloc;
7         unsigned int s_max_writeback_mb_bump;
8         unsigned long s_max_dir_size;
9 +       unsigned long s_warning_dir_size;
10         /* where last allocation was done - for stream allocation */
11         unsigned long s_mb_last_group;
12         unsigned long s_mb_last_start;
13 diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
14 index 992dc58..57ff920 100644
15 --- a/fs/ext4/namei.c
16 +++ b/fs/ext4/namei.c
17 @@ -370,11 +370,19 @@ struct ext4_dir_lock_data {
18  
19  #define ext4_htree_lock_data(l) ((struct ext4_dir_lock_data *)(l)->lk_private)
20  #define ext4_find_entry(dir, name, dirent) __ext4_find_entry(dir, name, dirent, NULL)
21 -#define ext4_add_entry(handle, dentry, inode) __ext4_add_entry(handle, dentry, inode, NULL)
22 -
23  /* NB: ext4_lblk_t is 32 bits so we use high bits to identify invalid blk */
24  #define EXT4_HTREE_NODE_CHANGED        (0xcafeULL << 32)
25  
26 +inline int ext4_add_entry(handle_t *handle, struct dentry *dentry,
27 +                           struct inode *inode)
28 +{
29 +       int ret = __ext4_add_entry(handle, dentry, inode, NULL);
30 +
31 +       if (ret == -ENOBUFS)
32 +               ret = 0;
33 +       return ret;
34 +}
35 +
36  static void ext4_htree_event_cb(void *target, void *event)
37  {
38         u64 *block = (u64 *)target;
39 @@ -2053,6 +2061,54 @@ int __ext4_add_entry(handle_t *handle, struct dentry *dentry,
40  }
41  EXPORT_SYMBOL(__ext4_add_entry);
42  
43 +static unsigned long __ext4_max_dir_size(struct dx_frame *frames,
44 +                              struct dx_frame *frame, struct inode *dir)
45 +{
46 +       unsigned long max_dir_size;
47 +
48 +       if (EXT4_SB(dir->i_sb)->s_max_dir_size) {
49 +               max_dir_size = EXT4_SB(dir->i_sb)->s_max_dir_size;
50 +       } else {
51 +               max_dir_size = EXT4_BLOCK_SIZE(dir->i_sb);
52 +               while (frame >= frames) {
53 +                       max_dir_size *= dx_get_limit(frame->entries);
54 +                       if (frame == frames)
55 +                               break;
56 +                       frame--;
57 +               }
58 +               /* use 75% of max dir size in average */
59 +               max_dir_size = max_dir_size / 4 * 3;
60 +       }
61 +       return max_dir_size;
62 +}
63 +
64 +/*
65 + * With hash tree growing, it is easy to hit ENOSPC, but it is hard
66 + * to predict when it will happen. let's give administrators warning
67 + * when reaching 5/8 and 11/16 of limit
68 + */
69 +static inline bool dir_size_in_warning_range(struct dx_frame *frames,
70 +                                            struct dx_frame *frame,
71 +                                            struct inode *dir)
72 +{
73 +       unsigned long size1, size2;
74 +       struct super_block *sb = dir->i_sb;
75 +
76 +       if (unlikely(!EXT4_SB(sb)->s_warning_dir_size))
77 +               EXT4_SB(sb)->s_warning_dir_size =
78 +                       __ext4_max_dir_size(frames, frame, dir);
79 +
80 +       size1 = EXT4_SB(sb)->s_warning_dir_size / 16 * 10;
81 +       size1 = size1 & ~(EXT4_BLOCK_SIZE(sb) - 1);
82 +       size2 = EXT4_SB(sb)->s_warning_dir_size / 16 * 11;
83 +       size2 = size2 & ~(EXT4_BLOCK_SIZE(sb) - 1);
84 +       if (in_range(dir->i_size, size1, EXT4_BLOCK_SIZE(sb)) ||
85 +           in_range(dir->i_size, size2, EXT4_BLOCK_SIZE(sb)))
86 +               return true;
87 +
88 +       return false;
89 +}
90 +
91  /*
92   * Returns 0 for success, or a negative error value
93   */
94 @@ -2068,6 +2124,7 @@ static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry,
95         struct ext4_dir_entry_2 *de;
96         int restart;
97         int err;
98 +       bool ret_warn = false;
99  
100  again:
101         restart = 0;
102 @@ -2088,6 +2145,11 @@ again:
103         /* Block full, should compress but for now just split */
104         dxtrace(printk(KERN_DEBUG "using %u of %u node entries\n",
105                        dx_get_count(entries), dx_get_limit(entries)));
106 +
107 +       if (frame - frames + 1 >= ext4_dir_htree_level(sb) ||
108 +           EXT4_SB(dir->i_sb)->s_max_dir_size)
109 +               ret_warn = dir_size_in_warning_range(frames, frame, dir);
110 +
111         /* Need to split index? */
112         if (dx_get_count(entries) == dx_get_limit(entries)) {
113                 ext4_lblk_t newblock;
114 @@ -2119,7 +2181,7 @@ again:
115                                          "reach max htree level :%d",
116                                          dir->i_ino, levels);
117                         if (ext4_dir_htree_level(sb) < EXT4_HTREE_LEVEL) {
118 -                               ext4_warning(sb, "Large directory feature is"
119 +                               ext4_warning(sb, "Large directory feature is "
120                                                  "not enabled on this "
121                                                  "filesystem");
122                         }
123 @@ -2248,6 +2310,8 @@ cleanup:
124          * repeat dx_probe() to find out valid htree-path */
125         if (restart && err == 0)
126                 goto again;
127 +       if (err == 0 && ret_warn)
128 +               err = -ENOBUFS;
129         return err;
130  }
131  
132 diff --git a/fs/ext4/super.c b/fs/ext4/super.c
133 index f02a632..b8ed072 100644
134 --- a/fs/ext4/super.c
135 +++ b/fs/ext4/super.c
136 @@ -1813,6 +1813,8 @@ set_qf_format:
137                         if (option < 0)
138                                 return 0;
139                         sbi->s_max_dir_size = option * 1024;
140 +                       /* reset s_warning_dir_size and make it re-calculated */
141 +                       sbi->s_warning_dir_size = 0;
142                         break;
143                 case Opt_stripe:
144                         if (match_int(&args[0], &option))
145 @@ -2577,6 +2579,7 @@ EXT4_ATTR_OFFSET(inode_readahead_blks, 0644, sbi_ui_show,
146                  inode_readahead_blks_store, s_inode_readahead_blks);
147  EXT4_RW_ATTR_SBI_UI(inode_goal, s_inode_goal);
148  EXT4_RW_ATTR_SBI_UI(max_dir_size, s_max_dir_size);
149 +EXT4_RW_ATTR_SBI_UI(warning_dir_size, s_warning_dir_size);
150  EXT4_RW_ATTR_SBI_UI(mb_stats, s_mb_stats);
151  EXT4_RW_ATTR_SBI_UI(mb_max_to_scan, s_mb_max_to_scan);
152  EXT4_RW_ATTR_SBI_UI(mb_min_to_scan, s_mb_min_to_scan);
153 @@ -2594,6 +2597,7 @@ static struct attribute *ext4_attrs[] = {
154         ATTR_LIST(inode_readahead_blks),
155         ATTR_LIST(inode_goal),
156         ATTR_LIST(max_dir_size),
157 +       ATTR_LIST(warning_dir_size),
158         ATTR_LIST(mb_stats),
159         ATTR_LIST(mb_max_to_scan),
160         ATTR_LIST(mb_min_to_scan),
161 @@ -3119,6 +3123,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
162         sb->s_fs_info = sbi;
163         sbi->s_mount_opt = 0;
164         sbi->s_max_dir_size = 0;
165 +       sbi->s_warning_dir_size = 0;
166         sbi->s_resuid = EXT4_DEF_RESUID;
167         sbi->s_resgid = EXT4_DEF_RESGID;
168         sbi->s_inode_readahead_blks = EXT4_DEF_INODE_READAHEAD_BLKS;