diff options
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/quota/Kconfig | 8 | ||||
| -rw-r--r-- | fs/quota/quota_v2.c | 165 | ||||
| -rw-r--r-- | fs/quota/quotaio_v2.h | 19 |
3 files changed, 153 insertions, 39 deletions
diff --git a/fs/quota/Kconfig b/fs/quota/Kconfig index 353e78a9ebee..efc02ebb8c70 100644 --- a/fs/quota/Kconfig +++ b/fs/quota/Kconfig | |||
| @@ -46,12 +46,14 @@ config QFMT_V1 | |||
| 46 | format say Y here. | 46 | format say Y here. |
| 47 | 47 | ||
| 48 | config QFMT_V2 | 48 | config QFMT_V2 |
| 49 | tristate "Quota format v2 support" | 49 | tristate "Quota format vfsv0 and vfsv1 support" |
| 50 | depends on QUOTA | 50 | depends on QUOTA |
| 51 | select QUOTA_TREE | 51 | select QUOTA_TREE |
| 52 | help | 52 | help |
| 53 | This quota format allows using quotas with 32-bit UIDs/GIDs. If you | 53 | This config option enables kernel support for vfsv0 and vfsv1 quota |
| 54 | need this functionality say Y here. | 54 | formats. Both these formats support 32-bit UIDs/GIDs and vfsv1 format |
| 55 | also supports 64-bit inode and block quota limits. If you need this | ||
| 56 | functionality say Y here. | ||
| 55 | 57 | ||
| 56 | config QUOTACTL | 58 | config QUOTACTL |
| 57 | bool | 59 | bool |
diff --git a/fs/quota/quota_v2.c b/fs/quota/quota_v2.c index 01f25eae684d..3dfc23e02135 100644 --- a/fs/quota/quota_v2.c +++ b/fs/quota/quota_v2.c | |||
| @@ -23,14 +23,23 @@ MODULE_LICENSE("GPL"); | |||
| 23 | 23 | ||
| 24 | #define __QUOTA_V2_PARANOIA | 24 | #define __QUOTA_V2_PARANOIA |
| 25 | 25 | ||
| 26 | static void v2_mem2diskdqb(void *dp, struct dquot *dquot); | 26 | static void v2r0_mem2diskdqb(void *dp, struct dquot *dquot); |
| 27 | static void v2_disk2memdqb(struct dquot *dquot, void *dp); | 27 | static void v2r0_disk2memdqb(struct dquot *dquot, void *dp); |
| 28 | static int v2_is_id(void *dp, struct dquot *dquot); | 28 | static int v2r0_is_id(void *dp, struct dquot *dquot); |
| 29 | 29 | static void v2r1_mem2diskdqb(void *dp, struct dquot *dquot); | |
| 30 | static struct qtree_fmt_operations v2_qtree_ops = { | 30 | static void v2r1_disk2memdqb(struct dquot *dquot, void *dp); |
| 31 | .mem2disk_dqblk = v2_mem2diskdqb, | 31 | static int v2r1_is_id(void *dp, struct dquot *dquot); |
| 32 | .disk2mem_dqblk = v2_disk2memdqb, | 32 | |
| 33 | .is_id = v2_is_id, | 33 | static struct qtree_fmt_operations v2r0_qtree_ops = { |
| 34 | .mem2disk_dqblk = v2r0_mem2diskdqb, | ||
| 35 | .disk2mem_dqblk = v2r0_disk2memdqb, | ||
| 36 | .is_id = v2r0_is_id, | ||
| 37 | }; | ||
| 38 | |||
| 39 | static struct qtree_fmt_operations v2r1_qtree_ops = { | ||
| 40 | .mem2disk_dqblk = v2r1_mem2diskdqb, | ||
| 41 | .disk2mem_dqblk = v2r1_disk2memdqb, | ||
| 42 | .is_id = v2r1_is_id, | ||
| 34 | }; | 43 | }; |
| 35 | 44 | ||
| 36 | #define QUOTABLOCK_BITS 10 | 45 | #define QUOTABLOCK_BITS 10 |
| @@ -46,23 +55,33 @@ static inline qsize_t v2_qbtos(qsize_t blocks) | |||
| 46 | return blocks << QUOTABLOCK_BITS; | 55 | return blocks << QUOTABLOCK_BITS; |
| 47 | } | 56 | } |
| 48 | 57 | ||
| 58 | static int v2_read_header(struct super_block *sb, int type, | ||
| 59 | struct v2_disk_dqheader *dqhead) | ||
| 60 | { | ||
| 61 | ssize_t size; | ||
| 62 | |||
| 63 | size = sb->s_op->quota_read(sb, type, (char *)dqhead, | ||
| 64 | sizeof(struct v2_disk_dqheader), 0); | ||
| 65 | if (size != sizeof(struct v2_disk_dqheader)) { | ||
| 66 | printk(KERN_WARNING "quota_v2: Failed header read:" | ||
| 67 | " expected=%zd got=%zd\n", | ||
| 68 | sizeof(struct v2_disk_dqheader), size); | ||
| 69 | return 0; | ||
| 70 | } | ||
| 71 | return 1; | ||
| 72 | } | ||
| 73 | |||
| 49 | /* Check whether given file is really vfsv0 quotafile */ | 74 | /* Check whether given file is really vfsv0 quotafile */ |
| 50 | static int v2_check_quota_file(struct super_block *sb, int type) | 75 | static int v2_check_quota_file(struct super_block *sb, int type) |
| 51 | { | 76 | { |
| 52 | struct v2_disk_dqheader dqhead; | 77 | struct v2_disk_dqheader dqhead; |
| 53 | ssize_t size; | ||
| 54 | static const uint quota_magics[] = V2_INITQMAGICS; | 78 | static const uint quota_magics[] = V2_INITQMAGICS; |
| 55 | static const uint quota_versions[] = V2_INITQVERSIONS; | 79 | static const uint quota_versions[] = V2_INITQVERSIONS; |
| 56 | 80 | ||
| 57 | size = sb->s_op->quota_read(sb, type, (char *)&dqhead, | 81 | if (!v2_read_header(sb, type, &dqhead)) |
| 58 | sizeof(struct v2_disk_dqheader), 0); | ||
| 59 | if (size != sizeof(struct v2_disk_dqheader)) { | ||
| 60 | printk("quota_v2: failed read expected=%zd got=%zd\n", | ||
| 61 | sizeof(struct v2_disk_dqheader), size); | ||
| 62 | return 0; | 82 | return 0; |
| 63 | } | ||
| 64 | if (le32_to_cpu(dqhead.dqh_magic) != quota_magics[type] || | 83 | if (le32_to_cpu(dqhead.dqh_magic) != quota_magics[type] || |
| 65 | le32_to_cpu(dqhead.dqh_version) != quota_versions[type]) | 84 | le32_to_cpu(dqhead.dqh_version) > quota_versions[type]) |
| 66 | return 0; | 85 | return 0; |
| 67 | return 1; | 86 | return 1; |
| 68 | } | 87 | } |
| @@ -71,14 +90,20 @@ static int v2_check_quota_file(struct super_block *sb, int type) | |||
| 71 | static int v2_read_file_info(struct super_block *sb, int type) | 90 | static int v2_read_file_info(struct super_block *sb, int type) |
| 72 | { | 91 | { |
| 73 | struct v2_disk_dqinfo dinfo; | 92 | struct v2_disk_dqinfo dinfo; |
| 93 | struct v2_disk_dqheader dqhead; | ||
| 74 | struct mem_dqinfo *info = sb_dqinfo(sb, type); | 94 | struct mem_dqinfo *info = sb_dqinfo(sb, type); |
| 75 | struct qtree_mem_dqinfo *qinfo; | 95 | struct qtree_mem_dqinfo *qinfo; |
| 76 | ssize_t size; | 96 | ssize_t size; |
| 97 | unsigned int version; | ||
| 98 | |||
| 99 | if (!v2_read_header(sb, type, &dqhead)) | ||
| 100 | return 0; | ||
| 101 | version = le32_to_cpu(dqhead.dqh_version); | ||
| 77 | 102 | ||
| 78 | size = sb->s_op->quota_read(sb, type, (char *)&dinfo, | 103 | size = sb->s_op->quota_read(sb, type, (char *)&dinfo, |
| 79 | sizeof(struct v2_disk_dqinfo), V2_DQINFOOFF); | 104 | sizeof(struct v2_disk_dqinfo), V2_DQINFOOFF); |
| 80 | if (size != sizeof(struct v2_disk_dqinfo)) { | 105 | if (size != sizeof(struct v2_disk_dqinfo)) { |
| 81 | printk(KERN_WARNING "Can't read info structure on device %s.\n", | 106 | printk(KERN_WARNING "quota_v2: Can't read info structure on device %s.\n", |
| 82 | sb->s_id); | 107 | sb->s_id); |
| 83 | return -1; | 108 | return -1; |
| 84 | } | 109 | } |
| @@ -89,9 +114,15 @@ static int v2_read_file_info(struct super_block *sb, int type) | |||
| 89 | return -1; | 114 | return -1; |
| 90 | } | 115 | } |
| 91 | qinfo = info->dqi_priv; | 116 | qinfo = info->dqi_priv; |
| 92 | /* limits are stored as unsigned 32-bit data */ | 117 | if (version == 0) { |
| 93 | info->dqi_maxblimit = 0xffffffff; | 118 | /* limits are stored as unsigned 32-bit data */ |
| 94 | info->dqi_maxilimit = 0xffffffff; | 119 | info->dqi_maxblimit = 0xffffffff; |
| 120 | info->dqi_maxilimit = 0xffffffff; | ||
| 121 | } else { | ||
| 122 | /* used space is stored as unsigned 64-bit value */ | ||
| 123 | info->dqi_maxblimit = 0xffffffffffffffff; /* 2^64-1 */ | ||
| 124 | info->dqi_maxilimit = 0xffffffffffffffff; | ||
| 125 | } | ||
| 95 | info->dqi_bgrace = le32_to_cpu(dinfo.dqi_bgrace); | 126 | info->dqi_bgrace = le32_to_cpu(dinfo.dqi_bgrace); |
| 96 | info->dqi_igrace = le32_to_cpu(dinfo.dqi_igrace); | 127 | info->dqi_igrace = le32_to_cpu(dinfo.dqi_igrace); |
| 97 | info->dqi_flags = le32_to_cpu(dinfo.dqi_flags); | 128 | info->dqi_flags = le32_to_cpu(dinfo.dqi_flags); |
| @@ -103,8 +134,13 @@ static int v2_read_file_info(struct super_block *sb, int type) | |||
| 103 | qinfo->dqi_blocksize_bits = V2_DQBLKSIZE_BITS; | 134 | qinfo->dqi_blocksize_bits = V2_DQBLKSIZE_BITS; |
| 104 | qinfo->dqi_usable_bs = 1 << V2_DQBLKSIZE_BITS; | 135 | qinfo->dqi_usable_bs = 1 << V2_DQBLKSIZE_BITS; |
| 105 | qinfo->dqi_qtree_depth = qtree_depth(qinfo); | 136 | qinfo->dqi_qtree_depth = qtree_depth(qinfo); |
| 106 | qinfo->dqi_entry_size = sizeof(struct v2_disk_dqblk); | 137 | if (version == 0) { |
| 107 | qinfo->dqi_ops = &v2_qtree_ops; | 138 | qinfo->dqi_entry_size = sizeof(struct v2r0_disk_dqblk); |
| 139 | qinfo->dqi_ops = &v2r0_qtree_ops; | ||
| 140 | } else { | ||
| 141 | qinfo->dqi_entry_size = sizeof(struct v2r1_disk_dqblk); | ||
| 142 | qinfo->dqi_ops = &v2r1_qtree_ops; | ||
| 143 | } | ||
| 108 | return 0; | 144 | return 0; |
| 109 | } | 145 | } |
| 110 | 146 | ||
| @@ -135,9 +171,9 @@ static int v2_write_file_info(struct super_block *sb, int type) | |||
| 135 | return 0; | 171 | return 0; |
| 136 | } | 172 | } |
| 137 | 173 | ||
| 138 | static void v2_disk2memdqb(struct dquot *dquot, void *dp) | 174 | static void v2r0_disk2memdqb(struct dquot *dquot, void *dp) |
| 139 | { | 175 | { |
| 140 | struct v2_disk_dqblk *d = dp, empty; | 176 | struct v2r0_disk_dqblk *d = dp, empty; |
| 141 | struct mem_dqblk *m = &dquot->dq_dqb; | 177 | struct mem_dqblk *m = &dquot->dq_dqb; |
| 142 | 178 | ||
| 143 | m->dqb_ihardlimit = le32_to_cpu(d->dqb_ihardlimit); | 179 | m->dqb_ihardlimit = le32_to_cpu(d->dqb_ihardlimit); |
| @@ -149,15 +185,15 @@ static void v2_disk2memdqb(struct dquot *dquot, void *dp) | |||
| 149 | m->dqb_curspace = le64_to_cpu(d->dqb_curspace); | 185 | m->dqb_curspace = le64_to_cpu(d->dqb_curspace); |
| 150 | m->dqb_btime = le64_to_cpu(d->dqb_btime); | 186 | m->dqb_btime = le64_to_cpu(d->dqb_btime); |
| 151 | /* We need to escape back all-zero structure */ | 187 | /* We need to escape back all-zero structure */ |
| 152 | memset(&empty, 0, sizeof(struct v2_disk_dqblk)); | 188 | memset(&empty, 0, sizeof(struct v2r0_disk_dqblk)); |
| 153 | empty.dqb_itime = cpu_to_le64(1); | 189 | empty.dqb_itime = cpu_to_le64(1); |
| 154 | if (!memcmp(&empty, dp, sizeof(struct v2_disk_dqblk))) | 190 | if (!memcmp(&empty, dp, sizeof(struct v2r0_disk_dqblk))) |
| 155 | m->dqb_itime = 0; | 191 | m->dqb_itime = 0; |
| 156 | } | 192 | } |
| 157 | 193 | ||
| 158 | static void v2_mem2diskdqb(void *dp, struct dquot *dquot) | 194 | static void v2r0_mem2diskdqb(void *dp, struct dquot *dquot) |
| 159 | { | 195 | { |
| 160 | struct v2_disk_dqblk *d = dp; | 196 | struct v2r0_disk_dqblk *d = dp; |
| 161 | struct mem_dqblk *m = &dquot->dq_dqb; | 197 | struct mem_dqblk *m = &dquot->dq_dqb; |
| 162 | struct qtree_mem_dqinfo *info = | 198 | struct qtree_mem_dqinfo *info = |
| 163 | sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv; | 199 | sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv; |
| @@ -175,9 +211,60 @@ static void v2_mem2diskdqb(void *dp, struct dquot *dquot) | |||
| 175 | d->dqb_itime = cpu_to_le64(1); | 211 | d->dqb_itime = cpu_to_le64(1); |
| 176 | } | 212 | } |
| 177 | 213 | ||
| 178 | static int v2_is_id(void *dp, struct dquot *dquot) | 214 | static int v2r0_is_id(void *dp, struct dquot *dquot) |
| 215 | { | ||
| 216 | struct v2r0_disk_dqblk *d = dp; | ||
| 217 | struct qtree_mem_dqinfo *info = | ||
| 218 | sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv; | ||
| 219 | |||
| 220 | if (qtree_entry_unused(info, dp)) | ||
| 221 | return 0; | ||
| 222 | return le32_to_cpu(d->dqb_id) == dquot->dq_id; | ||
| 223 | } | ||
| 224 | |||
| 225 | static void v2r1_disk2memdqb(struct dquot *dquot, void *dp) | ||
| 226 | { | ||
| 227 | struct v2r1_disk_dqblk *d = dp, empty; | ||
| 228 | struct mem_dqblk *m = &dquot->dq_dqb; | ||
| 229 | |||
| 230 | m->dqb_ihardlimit = le64_to_cpu(d->dqb_ihardlimit); | ||
| 231 | m->dqb_isoftlimit = le64_to_cpu(d->dqb_isoftlimit); | ||
| 232 | m->dqb_curinodes = le64_to_cpu(d->dqb_curinodes); | ||
| 233 | m->dqb_itime = le64_to_cpu(d->dqb_itime); | ||
| 234 | m->dqb_bhardlimit = v2_qbtos(le64_to_cpu(d->dqb_bhardlimit)); | ||
| 235 | m->dqb_bsoftlimit = v2_qbtos(le64_to_cpu(d->dqb_bsoftlimit)); | ||
| 236 | m->dqb_curspace = le64_to_cpu(d->dqb_curspace); | ||
| 237 | m->dqb_btime = le64_to_cpu(d->dqb_btime); | ||
| 238 | /* We need to escape back all-zero structure */ | ||
| 239 | memset(&empty, 0, sizeof(struct v2r1_disk_dqblk)); | ||
| 240 | empty.dqb_itime = cpu_to_le64(1); | ||
| 241 | if (!memcmp(&empty, dp, sizeof(struct v2r1_disk_dqblk))) | ||
| 242 | m->dqb_itime = 0; | ||
| 243 | } | ||
| 244 | |||
| 245 | static void v2r1_mem2diskdqb(void *dp, struct dquot *dquot) | ||
| 246 | { | ||
| 247 | struct v2r1_disk_dqblk *d = dp; | ||
| 248 | struct mem_dqblk *m = &dquot->dq_dqb; | ||
| 249 | struct qtree_mem_dqinfo *info = | ||
| 250 | sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv; | ||
| 251 | |||
| 252 | d->dqb_ihardlimit = cpu_to_le64(m->dqb_ihardlimit); | ||
| 253 | d->dqb_isoftlimit = cpu_to_le64(m->dqb_isoftlimit); | ||
| 254 | d->dqb_curinodes = cpu_to_le64(m->dqb_curinodes); | ||
| 255 | d->dqb_itime = cpu_to_le64(m->dqb_itime); | ||
| 256 | d->dqb_bhardlimit = cpu_to_le64(v2_stoqb(m->dqb_bhardlimit)); | ||
| 257 | d->dqb_bsoftlimit = cpu_to_le64(v2_stoqb(m->dqb_bsoftlimit)); | ||
| 258 | d->dqb_curspace = cpu_to_le64(m->dqb_curspace); | ||
| 259 | d->dqb_btime = cpu_to_le64(m->dqb_btime); | ||
| 260 | d->dqb_id = cpu_to_le32(dquot->dq_id); | ||
| 261 | if (qtree_entry_unused(info, dp)) | ||
| 262 | d->dqb_itime = cpu_to_le64(1); | ||
| 263 | } | ||
| 264 | |||
| 265 | static int v2r1_is_id(void *dp, struct dquot *dquot) | ||
| 179 | { | 266 | { |
| 180 | struct v2_disk_dqblk *d = dp; | 267 | struct v2r1_disk_dqblk *d = dp; |
| 181 | struct qtree_mem_dqinfo *info = | 268 | struct qtree_mem_dqinfo *info = |
| 182 | sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv; | 269 | sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv; |
| 183 | 270 | ||
| @@ -217,20 +304,32 @@ static const struct quota_format_ops v2_format_ops = { | |||
| 217 | .release_dqblk = v2_release_dquot, | 304 | .release_dqblk = v2_release_dquot, |
| 218 | }; | 305 | }; |
| 219 | 306 | ||
| 220 | static struct quota_format_type v2_quota_format = { | 307 | static struct quota_format_type v2r0_quota_format = { |
| 221 | .qf_fmt_id = QFMT_VFS_V0, | 308 | .qf_fmt_id = QFMT_VFS_V0, |
| 222 | .qf_ops = &v2_format_ops, | 309 | .qf_ops = &v2_format_ops, |
| 223 | .qf_owner = THIS_MODULE | 310 | .qf_owner = THIS_MODULE |
| 224 | }; | 311 | }; |
| 225 | 312 | ||
| 313 | static struct quota_format_type v2r1_quota_format = { | ||
| 314 | .qf_fmt_id = QFMT_VFS_V1, | ||
| 315 | .qf_ops = &v2_format_ops, | ||
| 316 | .qf_owner = THIS_MODULE | ||
| 317 | }; | ||
| 318 | |||
| 226 | static int __init init_v2_quota_format(void) | 319 | static int __init init_v2_quota_format(void) |
| 227 | { | 320 | { |
| 228 | return register_quota_format(&v2_quota_format); | 321 | int ret; |
| 322 | |||
| 323 | ret = register_quota_format(&v2r0_quota_format); | ||
| 324 | if (ret) | ||
| 325 | return ret; | ||
| 326 | return register_quota_format(&v2r1_quota_format); | ||
| 229 | } | 327 | } |
| 230 | 328 | ||
| 231 | static void __exit exit_v2_quota_format(void) | 329 | static void __exit exit_v2_quota_format(void) |
| 232 | { | 330 | { |
| 233 | unregister_quota_format(&v2_quota_format); | 331 | unregister_quota_format(&v2r0_quota_format); |
| 332 | unregister_quota_format(&v2r1_quota_format); | ||
| 234 | } | 333 | } |
| 235 | 334 | ||
| 236 | module_init(init_v2_quota_format); | 335 | module_init(init_v2_quota_format); |
diff --git a/fs/quota/quotaio_v2.h b/fs/quota/quotaio_v2.h index 530fe580685c..f1966b42c2fd 100644 --- a/fs/quota/quotaio_v2.h +++ b/fs/quota/quotaio_v2.h | |||
| @@ -17,8 +17,8 @@ | |||
| 17 | } | 17 | } |
| 18 | 18 | ||
| 19 | #define V2_INITQVERSIONS {\ | 19 | #define V2_INITQVERSIONS {\ |
| 20 | 0, /* USRQUOTA */\ | 20 | 1, /* USRQUOTA */\ |
| 21 | 0 /* GRPQUOTA */\ | 21 | 1 /* GRPQUOTA */\ |
| 22 | } | 22 | } |
| 23 | 23 | ||
| 24 | /* First generic header */ | 24 | /* First generic header */ |
| @@ -32,7 +32,7 @@ struct v2_disk_dqheader { | |||
| 32 | * (as it appears on disk) - the file is a radix tree whose leaves point | 32 | * (as it appears on disk) - the file is a radix tree whose leaves point |
| 33 | * to blocks of these structures. | 33 | * to blocks of these structures. |
| 34 | */ | 34 | */ |
| 35 | struct v2_disk_dqblk { | 35 | struct v2r0_disk_dqblk { |
| 36 | __le32 dqb_id; /* id this quota applies to */ | 36 | __le32 dqb_id; /* id this quota applies to */ |
| 37 | __le32 dqb_ihardlimit; /* absolute limit on allocated inodes */ | 37 | __le32 dqb_ihardlimit; /* absolute limit on allocated inodes */ |
| 38 | __le32 dqb_isoftlimit; /* preferred inode limit */ | 38 | __le32 dqb_isoftlimit; /* preferred inode limit */ |
| @@ -44,6 +44,19 @@ struct v2_disk_dqblk { | |||
| 44 | __le64 dqb_itime; /* time limit for excessive inode use */ | 44 | __le64 dqb_itime; /* time limit for excessive inode use */ |
| 45 | }; | 45 | }; |
| 46 | 46 | ||
| 47 | struct v2r1_disk_dqblk { | ||
| 48 | __le32 dqb_id; /* id this quota applies to */ | ||
| 49 | __le32 dqb_pad; | ||
| 50 | __le64 dqb_ihardlimit; /* absolute limit on allocated inodes */ | ||
| 51 | __le64 dqb_isoftlimit; /* preferred inode limit */ | ||
| 52 | __le64 dqb_curinodes; /* current # allocated inodes */ | ||
| 53 | __le64 dqb_bhardlimit; /* absolute limit on disk space (in QUOTABLOCK_SIZE) */ | ||
| 54 | __le64 dqb_bsoftlimit; /* preferred limit on disk space (in QUOTABLOCK_SIZE) */ | ||
| 55 | __le64 dqb_curspace; /* current space occupied (in bytes) */ | ||
| 56 | __le64 dqb_btime; /* time limit for excessive disk use */ | ||
| 57 | __le64 dqb_itime; /* time limit for excessive inode use */ | ||
| 58 | }; | ||
| 59 | |||
| 47 | /* Header with type and version specific information */ | 60 | /* Header with type and version specific information */ |
| 48 | struct v2_disk_dqinfo { | 61 | struct v2_disk_dqinfo { |
| 49 | __le32 dqi_bgrace; /* Time before block soft limit becomes hard limit */ | 62 | __le32 dqi_bgrace; /* Time before block soft limit becomes hard limit */ |
