Whamcloud - gitweb
LU-14195 ldiskfs: update patches for Linux 5.10
[fs/lustre-release.git] / ldiskfs / kernel_patches / patches / linux-5.10 / ext4-give-warning-with-dir-htree-growing.patch
1 ---
2  fs/ext4/ext4.h  |    1 
3  fs/ext4/namei.c |   68 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--
4  fs/ext4/super.c |    2 +
5  fs/ext4/sysfs.c |    2 +
6  4 files changed, 71 insertions(+), 2 deletions(-)
7
8 --- a/fs/ext4/ext4.h
9 +++ b/fs/ext4/ext4.h
10 @@ -1547,6 +1547,7 @@ struct ext4_sb_info {
11         unsigned int s_mb_group_prealloc;
12         unsigned int s_mb_max_inode_prealloc;
13         unsigned int s_max_dir_size_kb;
14 +       unsigned long s_warning_dir_size;
15         /* where last allocation was done - for stream allocation */
16         unsigned long s_mb_last_group;
17         unsigned long s_mb_last_start;
18 --- a/fs/ext4/namei.c
19 +++ b/fs/ext4/namei.c
20 @@ -775,12 +775,20 @@ struct ext4_dir_lock_data {
21  #define ext4_htree_lock_data(l)        ((struct ext4_dir_lock_data *)(l)->lk_private)
22  #define ext4_find_entry(dir, name, dirent, inline) \
23                         ext4_find_entry_locked(dir, name, dirent, inline, NULL)
24 -#define ext4_add_entry(handle, dentry, inode) \
25 -                       ext4_add_entry_locked(handle, dentry, inode, NULL)
26  
27  /* NB: ext4_lblk_t is 32 bits so we use high bits to identify invalid blk */
28  #define EXT4_HTREE_NODE_CHANGED        (0xcafeULL << 32)
29  
30 +inline int ext4_add_entry(handle_t *handle, struct dentry *dentry,
31 +                         struct inode *inode)
32 +{
33 +       int ret = ext4_add_entry_locked(handle, dentry, inode, NULL);
34 +
35 +       if (ret == -ENOBUFS)
36 +               ret = 0;
37 +       return ret;
38 +}
39 +
40  static void ext4_htree_event_cb(void *target, void *event)
41  {
42         u64 *block = (u64 *)target;
43 @@ -2657,6 +2665,54 @@ out:
44         return err;
45  }
46  
47 +static unsigned long __ext4_max_dir_size(struct dx_frame *frames,
48 +                              struct dx_frame *frame, struct inode *dir)
49 +{
50 +       unsigned long max_dir_size;
51 +
52 +       if (EXT4_SB(dir->i_sb)->s_max_dir_size_kb) {
53 +               max_dir_size = EXT4_SB(dir->i_sb)->s_max_dir_size_kb << 10;
54 +       } else {
55 +               max_dir_size = EXT4_BLOCK_SIZE(dir->i_sb);
56 +               while (frame >= frames) {
57 +                       max_dir_size *= dx_get_limit(frame->entries);
58 +                       if (frame == frames)
59 +                               break;
60 +                       frame--;
61 +               }
62 +               /* use 75% of max dir size in average */
63 +               max_dir_size = max_dir_size / 4 * 3;
64 +       }
65 +       return max_dir_size;
66 +}
67 +
68 +/*
69 + * With hash tree growing, it is easy to hit ENOSPC, but it is hard
70 + * to predict when it will happen. let's give administrators warning
71 + * when reaching 3/5 and 2/3 of limit
72 + */
73 +static inline bool dir_size_in_warning_range(struct dx_frame *frames,
74 +                                            struct dx_frame *frame,
75 +                                            struct inode *dir)
76 +{
77 +       unsigned long size1, size2;
78 +       struct super_block *sb = dir->i_sb;
79 +
80 +       if (unlikely(!EXT4_SB(sb)->s_warning_dir_size))
81 +               EXT4_SB(sb)->s_warning_dir_size =
82 +                       __ext4_max_dir_size(frames, frame, dir);
83 +
84 +       size1 = EXT4_SB(sb)->s_warning_dir_size / 16 * 10;
85 +       size1 = size1 & ~(EXT4_BLOCK_SIZE(sb) - 1);
86 +       size2 = EXT4_SB(sb)->s_warning_dir_size / 16 * 11;
87 +       size2 = size2 & ~(EXT4_BLOCK_SIZE(sb) - 1);
88 +       if (in_range(dir->i_size, size1, EXT4_BLOCK_SIZE(sb)) ||
89 +           in_range(dir->i_size, size2, EXT4_BLOCK_SIZE(sb)))
90 +               return true;
91 +
92 +       return false;
93 +}
94 +
95  /*
96   *     ext4_add_entry()
97   *
98 @@ -2796,6 +2852,7 @@ static int ext4_dx_add_entry(handle_t *h
99         struct ext4_dir_entry_2 *de;
100         int restart;
101         int err;
102 +       bool ret_warn = false;
103  
104  again:
105         restart = 0;
106 @@ -2824,6 +2881,11 @@ again:
107         /* Block full, should compress but for now just split */
108         dxtrace(printk(KERN_DEBUG "using %u of %u node entries\n",
109                        dx_get_count(entries), dx_get_limit(entries)));
110 +
111 +       if (frame - frames + 1 >= ext4_dir_htree_level(sb) ||
112 +           EXT4_SB(sb)->s_warning_dir_size)
113 +               ret_warn = dir_size_in_warning_range(frames, frame, dir);
114 +
115         /* Need to split index? */
116         if (dx_get_count(entries) == dx_get_limit(entries)) {
117                 ext4_lblk_t newblock;
118 @@ -2987,6 +3049,8 @@ cleanup:
119          */
120         if (restart && err == 0)
121                 goto again;
122 +       if (err == 0 && ret_warn)
123 +               err = -ENOBUFS;
124         return err;
125  }
126  
127 --- a/fs/ext4/super.c
128 +++ b/fs/ext4/super.c
129 @@ -2243,6 +2243,8 @@ static int handle_mount_opt(struct super
130                 sbi->s_li_wait_mult = arg;
131         } else if (token == Opt_max_dir_size_kb) {
132                 sbi->s_max_dir_size_kb = arg;
133 +               /* reset s_warning_dir_size and make it re-calculated */
134 +               sbi->s_warning_dir_size = 0;
135  #ifdef CONFIG_EXT4_DEBUG
136         } else if (token == Opt_fc_debug_max_replay) {
137                 sbi->s_fc_debug_max_replay = arg;
138 --- a/fs/ext4/sysfs.c
139 +++ b/fs/ext4/sysfs.c
140 @@ -214,6 +214,7 @@ EXT4_ATTR_OFFSET(inode_readahead_blks, 0
141  EXT4_RW_ATTR_SBI_UI(inode_goal, s_inode_goal);
142  EXT4_RW_ATTR_SBI_UI(max_dir_size, s_max_dir_size_kb);
143  EXT4_RW_ATTR_SBI_UI(max_dir_size_kb, s_max_dir_size_kb);
144 +EXT4_RW_ATTR_SBI_UI(warning_dir_size, s_warning_dir_size);
145  EXT4_RW_ATTR_SBI_UI(mb_stats, s_mb_stats);
146  EXT4_RW_ATTR_SBI_UI(mb_max_to_scan, s_mb_max_to_scan);
147  EXT4_RW_ATTR_SBI_UI(mb_min_to_scan, s_mb_min_to_scan);
148 @@ -264,6 +265,7 @@ static struct attribute *ext4_attrs[] =
149         ATTR_LIST(inode_goal),
150         ATTR_LIST(max_dir_size),
151         ATTR_LIST(max_dir_size_kb),
152 +       ATTR_LIST(warning_dir_size),
153         ATTR_LIST(mb_stats),
154         ATTR_LIST(mb_max_to_scan),
155         ATTR_LIST(mb_min_to_scan),