Whamcloud - gitweb
LU-4708 ldiskfs: do not copy NUL terminator from direntry
[fs/lustre-release.git] / ldiskfs / kernel_patches / patches / sles11sp2 / ext4-make-quota-as-first-class-supported-feature.patch
1 From 7c319d328505b7781b65238ae9f53293b5ee0ca8 Mon Sep 17 00:00:00 2001
2 From: Aditya Kali <adityakali@google.com>
3 Date: Sun, 22 Jul 2012 20:21:31 -0400
4 Subject: ext4: make quota as first class supported feature
5 Git-commit: 7c319d32, 281b5995
6 Patch-mainline: v3.6-rc1
7
8 This patch adds support for quotas as a first class feature in ext4;
9 which is to say, the quota files are stored in hidden inodes as file
10 system metadata, instead of as separate files visible in the file system
11 directory hierarchy.
12
13 It is based on the proposal at:
14 https://ext4.wiki.kernel.org/index.php/Design_For_1st_Class_Quota_in_Ext4
15
16 This patch introduces a new feature - EXT4_FEATURE_RO_COMPAT_QUOTA
17 which, when turned on, enables quota accounting at mount time
18 iteself. Also, the quota inodes are stored in two additional superblock
19 fields.  Some changes introduced by this patch that should be pointed
20 out are:
21
22 1) Two new ext4-superblock fields - s_usr_quota_inum and
23    s_grp_quota_inum for storing the quota inodes in use.
24 2) Default quota inodes are: inode#3 for tracking userquota and inode#4
25    for tracking group quota. The superblock fields can be set to use
26    other inodes as well.
27 3) If the QUOTA feature and corresponding quota inodes are set in
28    superblock, the quota usage tracking is turned on at mount time. On
29    'quotaon' ioctl, the quota limits enforcement is turned
30    on. 'quotaoff' ioctl turns off only the limits enforcement in this
31    case.
32 4) When QUOTA feature is in use, the quota mount options 'quota',
33    'usrquota', 'grpquota' are ignored by the kernel.
34 5) mke2fs or tune2fs can be used to set the QUOTA feature and initialize
35    quota inodes. The default reserved inodes will not be visible to user
36    as regular files.
37 6) The quota-tools will need to be modified to support hidden quota
38    files on ext4. E2fsprogs will also include support for creating and
39    fixing quota files.
40 7) Support is only for the new V2 quota file format.
41
42 Tested-by: Jan Kara <jack@suse.cz>
43 Reviewed-by: Jan Kara <jack@suse.cz>
44 Reviewed-by: Johann Lombardi <johann@whamcloud.com>
45 Signed-off-by: Aditya Kali <adityakali@google.com>
46 Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
47 Acked-by: Jeff Mahoney <jeffm@suse.com>
48 ---
49  fs/ext4/ext4.h      |   10 +++
50  fs/ext4/ext4_jbd2.h |   16 ++++--
51  fs/ext4/super.c     |  137 ++++++++++++++++++++++++++++++++++++++++++++++++++--
52  3 files changed, 153 insertions(+), 10 deletions(-)
53
54 --- a/fs/ext4/ext4.h
55 +++ b/fs/ext4/ext4.h
56 @@ -1063,7 +1063,10 @@ struct ext4_super_block {
57         __u8    s_last_error_func[32];  /* function where the error happened */
58  #define EXT4_S_ERR_END offsetof(struct ext4_super_block, s_mount_opts)
59         __u8    s_mount_opts[64];
60 -       __le32  s_reserved[112];        /* Padding to the end of the block */
61 +       __le32  s_usr_quota_inum;       /* inode for tracking user quota */
62 +       __le32  s_grp_quota_inum;       /* inode for tracking group quota */
63 +       __le32  s_overhead_clusters;    /* overhead blocks/clusters in fs */
64 +       __le32  s_reserved[109];        /* Padding to the end of the block */
65  };
66
67  #define EXT4_S_ERR_LEN (EXT4_S_ERR_END - EXT4_S_ERR_START)
68 @@ -1238,6 +1241,8 @@ static inline struct timespec ext4_curre
69  static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino)
70  {
71         return ino == EXT4_ROOT_INO ||
72 +               ino == EXT4_USR_QUOTA_INO ||
73 +               ino == EXT4_GRP_QUOTA_INO ||
74                 ino == EXT4_JOURNAL_INO ||
75                 ino == EXT4_RESIZE_INO ||
76                 (ino >= EXT4_FIRST_INO(sb) &&
77 @@ -1398,7 +1403,8 @@ static inline void ext4_clear_state_flag
78                                          EXT4_FEATURE_RO_COMPAT_DIR_NLINK | \
79                                          EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE | \
80                                          EXT4_FEATURE_RO_COMPAT_BTREE_DIR |\
81 -                                        EXT4_FEATURE_RO_COMPAT_HUGE_FILE)
82 +                                        EXT4_FEATURE_RO_COMPAT_HUGE_FILE |\
83 +                                        EXT4_FEATURE_RO_COMPAT_QUOTA)
84
85  /*
86   * Default values for user and/or group using reserved blocks
87 --- a/fs/ext4/ext4_jbd2.h
88 +++ b/fs/ext4/ext4_jbd2.h
89 @@ -87,14 +87,20 @@
90  #ifdef CONFIG_QUOTA
91  /* Amount of blocks needed for quota update - we know that the structure was
92   * allocated so we need to update only data block */
93 -#define EXT4_QUOTA_TRANS_BLOCKS(sb) (test_opt(sb, QUOTA) ? 1 : 0)
94 +#define EXT4_QUOTA_TRANS_BLOCKS(sb) ((test_opt(sb, QUOTA) ||\
95 +               EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_QUOTA)) ?\
96 +               1 : 0)
97  /* Amount of blocks needed for quota insert/delete - we do some block writes
98   * but inode, sb and group updates are done only once */
99 -#define EXT4_QUOTA_INIT_BLOCKS(sb) (test_opt(sb, QUOTA) ? (DQUOT_INIT_ALLOC*\
100 -               (EXT4_SINGLEDATA_TRANS_BLOCKS(sb)-3)+3+DQUOT_INIT_REWRITE) : 0)
101 +#define EXT4_QUOTA_INIT_BLOCKS(sb) ((test_opt(sb, QUOTA) ||\
102 +               EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_QUOTA)) ?\
103 +               (DQUOT_INIT_ALLOC*(EXT4_SINGLEDATA_TRANS_BLOCKS(sb)-3)\
104 +                +3+DQUOT_INIT_REWRITE) : 0)
105
106 -#define EXT4_QUOTA_DEL_BLOCKS(sb) (test_opt(sb, QUOTA) ? (DQUOT_DEL_ALLOC*\
107 -               (EXT4_SINGLEDATA_TRANS_BLOCKS(sb)-3)+3+DQUOT_DEL_REWRITE) : 0)
108 +#define EXT4_QUOTA_DEL_BLOCKS(sb) ((test_opt(sb, QUOTA) ||\
109 +               EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_QUOTA)) ?\
110 +               (DQUOT_DEL_ALLOC*(EXT4_SINGLEDATA_TRANS_BLOCKS(sb)-3)\
111 +                +3+DQUOT_DEL_REWRITE) : 0)
112  #else
113  #define EXT4_QUOTA_TRANS_BLOCKS(sb) 0
114  #define EXT4_QUOTA_INIT_BLOCKS(sb) 0
115 --- a/fs/ext4/super.c
116 +++ b/fs/ext4/super.c
117 @@ -1241,12 +1241,18 @@ static int ext4_mark_dquot_dirty(struct
118  static int ext4_write_info(struct super_block *sb, int type);
119  static int ext4_quota_on(struct super_block *sb, int type, int format_id,
120                          struct path *path);
121 +static int ext4_quota_on_sysfile(struct super_block *sb, int type,
122 +                                int format_id);
123  static int ext4_quota_off(struct super_block *sb, int type);
124 +static int ext4_quota_off_sysfile(struct super_block *sb, int type);
125  static int ext4_quota_on_mount(struct super_block *sb, int type);
126  static ssize_t ext4_quota_read(struct super_block *sb, int type, char *data,
127                                size_t len, loff_t off);
128  static ssize_t ext4_quota_write(struct super_block *sb, int type,
129                                 const char *data, size_t len, loff_t off);
130 +static int ext4_quota_enable(struct super_block *sb, int type, int format_id,
131 +                            unsigned int flags);
132 +static int ext4_enable_quotas(struct super_block *sb);
133
134  static const struct dquot_operations ext4_quota_operations = {
135         .get_reserved_space = ext4_get_reserved_space,
136 @@ -1268,6 +1274,16 @@ static const struct quotactl_ops ext4_qc
137         .get_dqblk      = dquot_get_dqblk,
138         .set_dqblk      = dquot_set_dqblk
139  };
140 +
141 +static const struct quotactl_ops ext4_qctl_sysfile_operations = {
142 +       .quota_on_meta  = ext4_quota_on_sysfile,
143 +       .quota_off      = ext4_quota_off_sysfile,
144 +       .quota_sync     = dquot_quota_sync,
145 +       .get_info       = dquot_get_dqinfo,
146 +       .set_info       = dquot_set_dqinfo,
147 +       .get_dqblk      = dquot_get_dqblk,
148 +       .set_dqblk      = dquot_set_dqblk
149 +};
150  #endif
151
152  static const struct super_operations ext4_sops = {
153 @@ -2689,6 +2705,16 @@ static int ext4_feature_set_ok(struct su
154                         return 0;
155                 }
156         }
157 +
158 +#ifndef CONFIG_QUOTA
159 +       if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_QUOTA) &&
160 +           !readonly) {
161 +               ext4_msg(sb, KERN_ERR,
162 +                        "Filesystem with quota feature cannot be mounted RDWR "
163 +                        "without CONFIG_QUOTA");
164 +               return 0;
165 +       }
166 +#endif  /* CONFIG_QUOTA */
167         return 1;
168  }
169
170 @@ -3528,6 +3554,11 @@ static int ext4_fill_super(struct super_
171  #ifdef CONFIG_QUOTA
172         sb->s_qcop = &ext4_qctl_operations;
173         sb->dq_op = &ext4_quota_operations;
174 +
175 +       if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_QUOTA)) {
176 +               /* Use qctl operations for hidden quota files. */
177 +               sb->s_qcop = &ext4_qctl_sysfile_operations;
178 +       }
179  #endif
180         memcpy(sb->s_uuid, es->s_uuid, sizeof(es->s_uuid));
181
182 @@ -3755,6 +3786,16 @@ no_journal:
183         } else
184                 descr = "out journal";
185
186 +#ifdef CONFIG_QUOTA
187 +       /* Enable quota usage during mount. */
188 +       if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_QUOTA) &&
189 +           !(sb->s_flags & MS_RDONLY)) {
190 +               ret = ext4_enable_quotas(sb);
191 +               if (ret)
192 +                       goto failed_mount7;
193 +       }
194 +#endif  /* CONFIG_QUOTA */
195 +
196         ext4_msg(sb, KERN_INFO, "mounted filesystem with%s. "
197                  "Opts: %s%s%s", descr, sbi->s_es->s_mount_opts,
198                  *sbi->s_es->s_mount_opts ? "; " : "", orig_data);
199 @@ -4493,16 +4534,26 @@ static int ext4_remount(struct super_blo
200         if (sbi->s_journal == NULL)
201                 ext4_commit_super(sb, 1);
202
203 +       unlock_super(sb);
204  #ifdef CONFIG_QUOTA
205         /* Release old quota file names */
206         for (i = 0; i < MAXQUOTAS; i++)
207                 if (old_opts.s_qf_names[i] &&
208                     old_opts.s_qf_names[i] != sbi->s_qf_names[i])
209                         kfree(old_opts.s_qf_names[i]);
210 +       if (enable_quota) {
211 +               if (sb_any_quota_suspended(sb))
212 +                       dquot_resume(sb, -1);
213 +               else if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
214 +                                       EXT4_FEATURE_RO_COMPAT_QUOTA)) {
215 +                       err = ext4_enable_quotas(sb);
216 +                       if (err) {
217 +                               lock_super(sb);
218 +                               goto restore_opts;
219 +                       }
220 +               }
221 +       }
222  #endif
223 -       unlock_super(sb);
224 -       if (enable_quota)
225 -               dquot_resume(sb, -1);
226
227         ext4_msg(sb, KERN_INFO, "re-mounted. Opts: %s", orig_data);
228         kfree(orig_data);
229 @@ -4750,6 +4801,74 @@ static int ext4_quota_on(struct super_bl
230         return dquot_quota_on(sb, type, format_id, path);
231  }
232
233 +static int ext4_quota_enable(struct super_block *sb, int type, int format_id,
234 +                            unsigned int flags)
235 +{
236 +       int err;
237 +       struct inode *qf_inode;
238 +       unsigned long qf_inums[MAXQUOTAS] = {
239 +               le32_to_cpu(EXT4_SB(sb)->s_es->s_usr_quota_inum),
240 +               le32_to_cpu(EXT4_SB(sb)->s_es->s_grp_quota_inum)
241 +       };
242 +
243 +       BUG_ON(!EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_QUOTA));
244 +
245 +       if (!qf_inums[type])
246 +               return -EPERM;
247 +
248 +       qf_inode = ext4_iget(sb, qf_inums[type]);
249 +       if (IS_ERR(qf_inode)) {
250 +               ext4_error(sb, "Bad quota inode # %lu", qf_inums[type]);
251 +               return PTR_ERR(qf_inode);
252 +       }
253 +
254 +       err = dquot_enable(qf_inode, type, format_id, flags);
255 +       iput(qf_inode);
256 +
257 +       return err;
258 +}
259 +
260 +/* Enable usage tracking for all quota types. */
261 +static int ext4_enable_quotas(struct super_block *sb)
262 +{
263 +       int type, err = 0;
264 +       unsigned long qf_inums[MAXQUOTAS] = {
265 +               le32_to_cpu(EXT4_SB(sb)->s_es->s_usr_quota_inum),
266 +               le32_to_cpu(EXT4_SB(sb)->s_es->s_grp_quota_inum)
267 +       };
268 +
269 +       sb_dqopt(sb)->flags |= DQUOT_QUOTA_SYS_FILE;
270 +       for (type = 0; type < MAXQUOTAS; type++) {
271 +               if (qf_inums[type]) {
272 +                       err = ext4_quota_enable(sb, type, QFMT_VFS_V1,
273 +                                               DQUOT_USAGE_ENABLED);
274 +                       if (err) {
275 +                               ext4_warning(sb,
276 +                                       "Failed to enable quota (type=%d) "
277 +                                       "tracking. Please run e2fsck to fix.",
278 +                                       type);
279 +                               return err;
280 +                       }
281 +               }
282 +       }
283 +       return 0;
284 +}
285 +
286 +/*
287 + * quota_on function that is used when QUOTA feature is set.
288 + */
289 +static int ext4_quota_on_sysfile(struct super_block *sb, int type,
290 +                                int format_id)
291 +{
292 +       if (!EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_QUOTA))
293 +               return -EINVAL;
294 +
295 +       /*
296 +        * USAGE was enabled at mount time. Only need to enable LIMITS now.
297 +        */
298 +       return ext4_quota_enable(sb, type, format_id, DQUOT_LIMITS_ENABLED);
299 +}
300 +
301  static int ext4_quota_off(struct super_block *sb, int type)
302  {
303         struct inode *inode = sb_dqopt(sb)->files[type];
304 @@ -4776,6 +4895,18 @@ out:
305         return dquot_quota_off(sb, type);
306  }
307
308 +/*
309 + * quota_off function that is used when QUOTA feature is set.
310 + */
311 +static int ext4_quota_off_sysfile(struct super_block *sb, int type)
312 +{
313 +       if (!EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_QUOTA))
314 +               return -EINVAL;
315 +
316 +       /* Disable only the limits. */
317 +       return dquot_disable(sb, type, DQUOT_LIMITS_ENABLED);
318 +}
319 +
320  /* Read data from quotafile - avoid pagecache and such because we cannot afford
321   * acquiring the locks... As quota files are never truncated and quota code
322   * itself serializes the operations (and no one else should touch the files)