Blame view
fs/quota/quota_tree.c
16.5 KB
1ccd14b9c quota: Split off ... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
/* * vfsv0 quota IO operations on file */ #include <linux/errno.h> #include <linux/fs.h> #include <linux/mount.h> #include <linux/dqblk_v2.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/module.h> #include <linux/slab.h> #include <linux/quotaops.h> #include <asm/byteorder.h> #include "quota_tree.h" MODULE_AUTHOR("Jan Kara"); MODULE_DESCRIPTION("Quota trie support"); MODULE_LICENSE("GPL"); #define __QUOTA_QT_PARANOIA |
1ccd14b9c quota: Split off ... |
24 25 26 27 28 29 30 31 32 33 34 |
static int get_index(struct qtree_mem_dqinfo *info, qid_t id, int depth) { unsigned int epb = info->dqi_usable_bs >> 2; depth = info->dqi_qtree_depth - depth - 1; while (depth--) id /= epb; return id % epb; } /* Number of entries in one blocks */ |
7a2435d87 quota: Remove sup... |
35 |
static int qtree_dqstr_in_blk(struct qtree_mem_dqinfo *info) |
1ccd14b9c quota: Split off ... |
36 37 38 39 |
{ return (info->dqi_usable_bs - sizeof(struct qt_disk_dqdbheader)) / info->dqi_entry_size; } |
d26ac1a81 quota: Remove dqb... |
40 |
static char *getdqbuf(size_t size) |
1ccd14b9c quota: Split off ... |
41 |
{ |
d26ac1a81 quota: Remove dqb... |
42 |
char *buf = kmalloc(size, GFP_NOFS); |
1ccd14b9c quota: Split off ... |
43 |
if (!buf) |
268157ba6 quota: Coding sty... |
44 45 46 |
printk(KERN_WARNING "VFS: Not enough memory for quota buffers. "); |
1ccd14b9c quota: Split off ... |
47 48 |
return buf; } |
7a2435d87 quota: Remove sup... |
49 |
static ssize_t read_blk(struct qtree_mem_dqinfo *info, uint blk, char *buf) |
1ccd14b9c quota: Split off ... |
50 51 52 53 |
{ struct super_block *sb = info->dqi_sb; memset(buf, 0, info->dqi_usable_bs); |
d26ac1a81 quota: Remove dqb... |
54 |
return sb->s_op->quota_read(sb, info->dqi_type, buf, |
1ccd14b9c quota: Split off ... |
55 56 |
info->dqi_usable_bs, blk << info->dqi_blocksize_bits); } |
7a2435d87 quota: Remove sup... |
57 |
static ssize_t write_blk(struct qtree_mem_dqinfo *info, uint blk, char *buf) |
1ccd14b9c quota: Split off ... |
58 59 |
{ struct super_block *sb = info->dqi_sb; |
1907131bb dquot: Detect par... |
60 |
ssize_t ret; |
1ccd14b9c quota: Split off ... |
61 |
|
1907131bb dquot: Detect par... |
62 |
ret = sb->s_op->quota_write(sb, info->dqi_type, buf, |
1ccd14b9c quota: Split off ... |
63 |
info->dqi_usable_bs, blk << info->dqi_blocksize_bits); |
1907131bb dquot: Detect par... |
64 |
if (ret != info->dqi_usable_bs) { |
fb5ffb0e1 quota: Change quo... |
65 |
quota_error(sb, "dquota write failed"); |
1907131bb dquot: Detect par... |
66 67 68 69 |
if (ret >= 0) ret = -EIO; } return ret; |
1ccd14b9c quota: Split off ... |
70 71 72 73 74 |
} /* Remove empty block from list and return it */ static int get_free_dqblk(struct qtree_mem_dqinfo *info) { |
d26ac1a81 quota: Remove dqb... |
75 |
char *buf = getdqbuf(info->dqi_usable_bs); |
1ccd14b9c quota: Split off ... |
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; int ret, blk; if (!buf) return -ENOMEM; if (info->dqi_free_blk) { blk = info->dqi_free_blk; ret = read_blk(info, blk, buf); if (ret < 0) goto out_buf; info->dqi_free_blk = le32_to_cpu(dh->dqdh_next_free); } else { memset(buf, 0, info->dqi_usable_bs); /* Assure block allocation... */ ret = write_blk(info, info->dqi_blocks, buf); if (ret < 0) goto out_buf; blk = info->dqi_blocks++; } mark_info_dirty(info->dqi_sb, info->dqi_type); ret = blk; out_buf: |
d26ac1a81 quota: Remove dqb... |
99 |
kfree(buf); |
1ccd14b9c quota: Split off ... |
100 101 102 103 |
return ret; } /* Insert empty block to the list */ |
d26ac1a81 quota: Remove dqb... |
104 |
static int put_free_dqblk(struct qtree_mem_dqinfo *info, char *buf, uint blk) |
1ccd14b9c quota: Split off ... |
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
{ struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; int err; dh->dqdh_next_free = cpu_to_le32(info->dqi_free_blk); dh->dqdh_prev_free = cpu_to_le32(0); dh->dqdh_entries = cpu_to_le16(0); err = write_blk(info, blk, buf); if (err < 0) return err; info->dqi_free_blk = blk; mark_info_dirty(info->dqi_sb, info->dqi_type); return 0; } /* Remove given block from the list of blocks with free entries */ |
268157ba6 quota: Coding sty... |
121 122 |
static int remove_free_dqentry(struct qtree_mem_dqinfo *info, char *buf, uint blk) |
1ccd14b9c quota: Split off ... |
123 |
{ |
d26ac1a81 quota: Remove dqb... |
124 |
char *tmpbuf = getdqbuf(info->dqi_usable_bs); |
1ccd14b9c quota: Split off ... |
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; uint nextblk = le32_to_cpu(dh->dqdh_next_free); uint prevblk = le32_to_cpu(dh->dqdh_prev_free); int err; if (!tmpbuf) return -ENOMEM; if (nextblk) { err = read_blk(info, nextblk, tmpbuf); if (err < 0) goto out_buf; ((struct qt_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = dh->dqdh_prev_free; err = write_blk(info, nextblk, tmpbuf); if (err < 0) goto out_buf; } if (prevblk) { err = read_blk(info, prevblk, tmpbuf); if (err < 0) goto out_buf; ((struct qt_disk_dqdbheader *)tmpbuf)->dqdh_next_free = dh->dqdh_next_free; err = write_blk(info, prevblk, tmpbuf); if (err < 0) goto out_buf; } else { info->dqi_free_entry = nextblk; mark_info_dirty(info->dqi_sb, info->dqi_type); } |
d26ac1a81 quota: Remove dqb... |
155 |
kfree(tmpbuf); |
1ccd14b9c quota: Split off ... |
156 157 158 |
dh->dqdh_next_free = dh->dqdh_prev_free = cpu_to_le32(0); /* No matter whether write succeeds block is out of list */ if (write_blk(info, blk, buf) < 0) |
fb5ffb0e1 quota: Change quo... |
159 160 |
quota_error(info->dqi_sb, "Can't write block (%u) " "with free entries", blk); |
1ccd14b9c quota: Split off ... |
161 162 |
return 0; out_buf: |
d26ac1a81 quota: Remove dqb... |
163 |
kfree(tmpbuf); |
1ccd14b9c quota: Split off ... |
164 165 166 167 |
return err; } /* Insert given block to the beginning of list with free entries */ |
268157ba6 quota: Coding sty... |
168 169 |
static int insert_free_dqentry(struct qtree_mem_dqinfo *info, char *buf, uint blk) |
1ccd14b9c quota: Split off ... |
170 |
{ |
d26ac1a81 quota: Remove dqb... |
171 |
char *tmpbuf = getdqbuf(info->dqi_usable_bs); |
1ccd14b9c quota: Split off ... |
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 |
struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; int err; if (!tmpbuf) return -ENOMEM; dh->dqdh_next_free = cpu_to_le32(info->dqi_free_entry); dh->dqdh_prev_free = cpu_to_le32(0); err = write_blk(info, blk, buf); if (err < 0) goto out_buf; if (info->dqi_free_entry) { err = read_blk(info, info->dqi_free_entry, tmpbuf); if (err < 0) goto out_buf; ((struct qt_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = cpu_to_le32(blk); err = write_blk(info, info->dqi_free_entry, tmpbuf); if (err < 0) goto out_buf; } |
d26ac1a81 quota: Remove dqb... |
192 |
kfree(tmpbuf); |
1ccd14b9c quota: Split off ... |
193 194 195 196 |
info->dqi_free_entry = blk; mark_info_dirty(info->dqi_sb, info->dqi_type); return 0; out_buf: |
d26ac1a81 quota: Remove dqb... |
197 |
kfree(tmpbuf); |
1ccd14b9c quota: Split off ... |
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 |
return err; } /* Is the entry in the block free? */ int qtree_entry_unused(struct qtree_mem_dqinfo *info, char *disk) { int i; for (i = 0; i < info->dqi_entry_size; i++) if (disk[i]) return 0; return 1; } EXPORT_SYMBOL(qtree_entry_unused); /* Find space for dquot */ static uint find_free_dqentry(struct qtree_mem_dqinfo *info, struct dquot *dquot, int *err) { uint blk, i; struct qt_disk_dqdbheader *dh; |
d26ac1a81 quota: Remove dqb... |
219 |
char *buf = getdqbuf(info->dqi_usable_bs); |
1ccd14b9c quota: Split off ... |
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 |
char *ddquot; *err = 0; if (!buf) { *err = -ENOMEM; return 0; } dh = (struct qt_disk_dqdbheader *)buf; if (info->dqi_free_entry) { blk = info->dqi_free_entry; *err = read_blk(info, blk, buf); if (*err < 0) goto out_buf; } else { blk = get_free_dqblk(info); if ((int)blk < 0) { *err = blk; |
d26ac1a81 quota: Remove dqb... |
237 |
kfree(buf); |
1ccd14b9c quota: Split off ... |
238 239 240 |
return 0; } memset(buf, 0, info->dqi_usable_bs); |
268157ba6 quota: Coding sty... |
241 242 |
/* This is enough as the block is already zeroed and the entry * list is empty... */ |
1ccd14b9c quota: Split off ... |
243 244 245 246 247 248 249 |
info->dqi_free_entry = blk; mark_info_dirty(dquot->dq_sb, dquot->dq_type); } /* Block will be full? */ if (le16_to_cpu(dh->dqdh_entries) + 1 >= qtree_dqstr_in_blk(info)) { *err = remove_free_dqentry(info, buf, blk); if (*err < 0) { |
fb5ffb0e1 quota: Change quo... |
250 251 |
quota_error(dquot->dq_sb, "Can't remove block (%u) " "from entry free list", blk); |
1ccd14b9c quota: Split off ... |
252 253 254 255 256 |
goto out_buf; } } le16_add_cpu(&dh->dqdh_entries, 1); /* Find free structure in block */ |
268157ba6 quota: Coding sty... |
257 258 259 260 261 262 |
ddquot = buf + sizeof(struct qt_disk_dqdbheader); for (i = 0; i < qtree_dqstr_in_blk(info); i++) { if (qtree_entry_unused(info, ddquot)) break; ddquot += info->dqi_entry_size; } |
1ccd14b9c quota: Split off ... |
263 264 |
#ifdef __QUOTA_QT_PARANOIA if (i == qtree_dqstr_in_blk(info)) { |
fb5ffb0e1 quota: Change quo... |
265 |
quota_error(dquot->dq_sb, "Data block full but it shouldn't"); |
1ccd14b9c quota: Split off ... |
266 267 268 269 270 271 |
*err = -EIO; goto out_buf; } #endif *err = write_blk(info, blk, buf); if (*err < 0) { |
fb5ffb0e1 quota: Change quo... |
272 273 |
quota_error(dquot->dq_sb, "Can't write quota data block %u", blk); |
1ccd14b9c quota: Split off ... |
274 275 276 277 278 |
goto out_buf; } dquot->dq_off = (blk << info->dqi_blocksize_bits) + sizeof(struct qt_disk_dqdbheader) + i * info->dqi_entry_size; |
d26ac1a81 quota: Remove dqb... |
279 |
kfree(buf); |
1ccd14b9c quota: Split off ... |
280 281 |
return blk; out_buf: |
d26ac1a81 quota: Remove dqb... |
282 |
kfree(buf); |
1ccd14b9c quota: Split off ... |
283 284 285 286 287 288 289 |
return 0; } /* Insert reference to structure into the trie */ static int do_insert_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot, uint *treeblk, int depth) { |
d26ac1a81 quota: Remove dqb... |
290 |
char *buf = getdqbuf(info->dqi_usable_bs); |
1ccd14b9c quota: Split off ... |
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 |
int ret = 0, newson = 0, newact = 0; __le32 *ref; uint newblk; if (!buf) return -ENOMEM; if (!*treeblk) { ret = get_free_dqblk(info); if (ret < 0) goto out_buf; *treeblk = ret; memset(buf, 0, info->dqi_usable_bs); newact = 1; } else { ret = read_blk(info, *treeblk, buf); if (ret < 0) { |
fb5ffb0e1 quota: Change quo... |
307 308 |
quota_error(dquot->dq_sb, "Can't read tree quota " "block %u", *treeblk); |
1ccd14b9c quota: Split off ... |
309 310 311 312 313 314 315 316 317 318 |
goto out_buf; } } ref = (__le32 *)buf; newblk = le32_to_cpu(ref[get_index(info, dquot->dq_id, depth)]); if (!newblk) newson = 1; if (depth == info->dqi_qtree_depth - 1) { #ifdef __QUOTA_QT_PARANOIA if (newblk) { |
fb5ffb0e1 quota: Change quo... |
319 320 321 |
quota_error(dquot->dq_sb, "Inserting already present " "quota entry (block %u)", le32_to_cpu(ref[get_index(info, |
1ccd14b9c quota: Split off ... |
322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 |
dquot->dq_id, depth)])); ret = -EIO; goto out_buf; } #endif newblk = find_free_dqentry(info, dquot, &ret); } else { ret = do_insert_tree(info, dquot, &newblk, depth+1); } if (newson && ret >= 0) { ref[get_index(info, dquot->dq_id, depth)] = cpu_to_le32(newblk); ret = write_blk(info, *treeblk, buf); } else if (newact && ret < 0) { put_free_dqblk(info, buf, *treeblk); } out_buf: |
d26ac1a81 quota: Remove dqb... |
339 |
kfree(buf); |
1ccd14b9c quota: Split off ... |
340 341 342 343 344 345 346 347 348 349 350 351 |
return ret; } /* Wrapper for inserting quota structure into tree */ static inline int dq_insert_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot) { int tmp = QT_TREEOFF; return do_insert_tree(info, dquot, &tmp, 0); } /* |
268157ba6 quota: Coding sty... |
352 353 |
* We don't have to be afraid of deadlocks as we never have quotas on quota * files... |
1ccd14b9c quota: Split off ... |
354 355 356 357 358 359 |
*/ int qtree_write_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot) { int type = dquot->dq_type; struct super_block *sb = dquot->dq_sb; ssize_t ret; |
d26ac1a81 quota: Remove dqb... |
360 |
char *ddquot = getdqbuf(info->dqi_entry_size); |
1ccd14b9c quota: Split off ... |
361 362 363 364 365 366 367 368 |
if (!ddquot) return -ENOMEM; /* dq_off is guarded by dqio_mutex */ if (!dquot->dq_off) { ret = dq_insert_tree(info, dquot); if (ret < 0) { |
fb5ffb0e1 quota: Change quo... |
369 370 |
quota_error(sb, "Error %zd occurred while creating " "quota", ret); |
d26ac1a81 quota: Remove dqb... |
371 |
kfree(ddquot); |
1ccd14b9c quota: Split off ... |
372 373 374 375 376 377 |
return ret; } } spin_lock(&dq_data_lock); info->dqi_ops->mem2disk_dqblk(ddquot, dquot); spin_unlock(&dq_data_lock); |
d26ac1a81 quota: Remove dqb... |
378 379 |
ret = sb->s_op->quota_write(sb, type, ddquot, info->dqi_entry_size, dquot->dq_off); |
1ccd14b9c quota: Split off ... |
380 |
if (ret != info->dqi_entry_size) { |
fb5ffb0e1 quota: Change quo... |
381 |
quota_error(sb, "dquota write failed"); |
1ccd14b9c quota: Split off ... |
382 383 384 385 386 |
if (ret >= 0) ret = -ENOSPC; } else { ret = 0; } |
dde958885 quota: Make quota... |
387 |
dqstats_inc(DQST_WRITES); |
d26ac1a81 quota: Remove dqb... |
388 |
kfree(ddquot); |
1ccd14b9c quota: Split off ... |
389 390 391 392 393 394 395 396 397 398 |
return ret; } EXPORT_SYMBOL(qtree_write_dquot); /* Free dquot entry in data block */ static int free_dqentry(struct qtree_mem_dqinfo *info, struct dquot *dquot, uint blk) { struct qt_disk_dqdbheader *dh; |
d26ac1a81 quota: Remove dqb... |
399 |
char *buf = getdqbuf(info->dqi_usable_bs); |
1ccd14b9c quota: Split off ... |
400 401 402 403 404 |
int ret = 0; if (!buf) return -ENOMEM; if (dquot->dq_off >> info->dqi_blocksize_bits != blk) { |
fb5ffb0e1 quota: Change quo... |
405 406 407 |
quota_error(dquot->dq_sb, "Quota structure has offset to " "other block (%u) than it should (%u)", blk, (uint)(dquot->dq_off >> info->dqi_blocksize_bits)); |
1ccd14b9c quota: Split off ... |
408 409 410 411 |
goto out_buf; } ret = read_blk(info, blk, buf); if (ret < 0) { |
fb5ffb0e1 quota: Change quo... |
412 413 |
quota_error(dquot->dq_sb, "Can't read quota data block %u", blk); |
1ccd14b9c quota: Split off ... |
414 415 416 417 418 419 420 421 422 |
goto out_buf; } dh = (struct qt_disk_dqdbheader *)buf; le16_add_cpu(&dh->dqdh_entries, -1); if (!le16_to_cpu(dh->dqdh_entries)) { /* Block got free? */ ret = remove_free_dqentry(info, buf, blk); if (ret >= 0) ret = put_free_dqblk(info, buf, blk); if (ret < 0) { |
fb5ffb0e1 quota: Change quo... |
423 424 |
quota_error(dquot->dq_sb, "Can't move quota data block " "(%u) to free list", blk); |
1ccd14b9c quota: Split off ... |
425 426 427 428 429 430 431 432 433 434 435 |
goto out_buf; } } else { memset(buf + (dquot->dq_off & ((1 << info->dqi_blocksize_bits) - 1)), 0, info->dqi_entry_size); if (le16_to_cpu(dh->dqdh_entries) == qtree_dqstr_in_blk(info) - 1) { /* Insert will write block itself */ ret = insert_free_dqentry(info, buf, blk); if (ret < 0) { |
fb5ffb0e1 quota: Change quo... |
436 437 |
quota_error(dquot->dq_sb, "Can't insert quota " "data block (%u) to free entry list", blk); |
1ccd14b9c quota: Split off ... |
438 439 440 441 442 |
goto out_buf; } } else { ret = write_blk(info, blk, buf); if (ret < 0) { |
fb5ffb0e1 quota: Change quo... |
443 444 |
quota_error(dquot->dq_sb, "Can't write quota " "data block %u", blk); |
1ccd14b9c quota: Split off ... |
445 446 447 448 449 450 |
goto out_buf; } } } dquot->dq_off = 0; /* Quota is now unattached */ out_buf: |
d26ac1a81 quota: Remove dqb... |
451 |
kfree(buf); |
1ccd14b9c quota: Split off ... |
452 453 454 455 456 457 458 |
return ret; } /* Remove reference to dquot from tree */ static int remove_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot, uint *blk, int depth) { |
d26ac1a81 quota: Remove dqb... |
459 |
char *buf = getdqbuf(info->dqi_usable_bs); |
1ccd14b9c quota: Split off ... |
460 461 462 463 464 465 466 467 |
int ret = 0; uint newblk; __le32 *ref = (__le32 *)buf; if (!buf) return -ENOMEM; ret = read_blk(info, *blk, buf); if (ret < 0) { |
055adcbd7 quota: Use %pV an... |
468 469 |
quota_error(dquot->dq_sb, "Can't read quota data block %u", *blk); |
1ccd14b9c quota: Split off ... |
470 471 472 473 474 475 476 477 478 479 480 481 482 |
goto out_buf; } newblk = le32_to_cpu(ref[get_index(info, dquot->dq_id, depth)]); if (depth == info->dqi_qtree_depth - 1) { ret = free_dqentry(info, dquot, newblk); newblk = 0; } else { ret = remove_tree(info, dquot, &newblk, depth+1); } if (ret >= 0 && !newblk) { int i; ref[get_index(info, dquot->dq_id, depth)] = cpu_to_le32(0); /* Block got empty? */ |
d26ac1a81 quota: Remove dqb... |
483 484 |
for (i = 0; i < (info->dqi_usable_bs >> 2) && !ref[i]; i++) ; |
1ccd14b9c quota: Split off ... |
485 486 487 488 489 490 491 492 |
/* Don't put the root block into the free block list */ if (i == (info->dqi_usable_bs >> 2) && *blk != QT_TREEOFF) { put_free_dqblk(info, buf, *blk); *blk = 0; } else { ret = write_blk(info, *blk, buf); if (ret < 0) |
055adcbd7 quota: Use %pV an... |
493 494 495 |
quota_error(dquot->dq_sb, "Can't write quota tree block %u", *blk); |
1ccd14b9c quota: Split off ... |
496 497 498 |
} } out_buf: |
d26ac1a81 quota: Remove dqb... |
499 |
kfree(buf); |
1ccd14b9c quota: Split off ... |
500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 |
return ret; } /* Delete dquot from tree */ int qtree_delete_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot) { uint tmp = QT_TREEOFF; if (!dquot->dq_off) /* Even not allocated? */ return 0; return remove_tree(info, dquot, &tmp, 0); } EXPORT_SYMBOL(qtree_delete_dquot); /* Find entry in block */ static loff_t find_block_dqentry(struct qtree_mem_dqinfo *info, struct dquot *dquot, uint blk) { |
d26ac1a81 quota: Remove dqb... |
518 |
char *buf = getdqbuf(info->dqi_usable_bs); |
1ccd14b9c quota: Split off ... |
519 520 521 522 523 524 525 526 |
loff_t ret = 0; int i; char *ddquot; if (!buf) return -ENOMEM; ret = read_blk(info, blk, buf); if (ret < 0) { |
fb5ffb0e1 quota: Change quo... |
527 528 |
quota_error(dquot->dq_sb, "Can't read quota tree " "block %u", blk); |
1ccd14b9c quota: Split off ... |
529 530 |
goto out_buf; } |
268157ba6 quota: Coding sty... |
531 532 533 534 535 536 |
ddquot = buf + sizeof(struct qt_disk_dqdbheader); for (i = 0; i < qtree_dqstr_in_blk(info); i++) { if (info->dqi_ops->is_id(ddquot, dquot)) break; ddquot += info->dqi_entry_size; } |
1ccd14b9c quota: Split off ... |
537 |
if (i == qtree_dqstr_in_blk(info)) { |
fb5ffb0e1 quota: Change quo... |
538 539 |
quota_error(dquot->dq_sb, "Quota for id %u referenced " "but not present", dquot->dq_id); |
1ccd14b9c quota: Split off ... |
540 541 542 543 544 545 546 |
ret = -EIO; goto out_buf; } else { ret = (blk << info->dqi_blocksize_bits) + sizeof(struct qt_disk_dqdbheader) + i * info->dqi_entry_size; } out_buf: |
d26ac1a81 quota: Remove dqb... |
547 |
kfree(buf); |
1ccd14b9c quota: Split off ... |
548 549 550 551 552 553 554 |
return ret; } /* Find entry for given id in the tree */ static loff_t find_tree_dqentry(struct qtree_mem_dqinfo *info, struct dquot *dquot, uint blk, int depth) { |
d26ac1a81 quota: Remove dqb... |
555 |
char *buf = getdqbuf(info->dqi_usable_bs); |
1ccd14b9c quota: Split off ... |
556 557 558 559 560 561 562 |
loff_t ret = 0; __le32 *ref = (__le32 *)buf; if (!buf) return -ENOMEM; ret = read_blk(info, blk, buf); if (ret < 0) { |
fb5ffb0e1 quota: Change quo... |
563 564 |
quota_error(dquot->dq_sb, "Can't read quota tree block %u", blk); |
1ccd14b9c quota: Split off ... |
565 566 567 568 569 570 571 572 573 574 575 |
goto out_buf; } ret = 0; blk = le32_to_cpu(ref[get_index(info, dquot->dq_id, depth)]); if (!blk) /* No reference? */ goto out_buf; if (depth < info->dqi_qtree_depth - 1) ret = find_tree_dqentry(info, dquot, blk, depth+1); else ret = find_block_dqentry(info, dquot, blk); out_buf: |
d26ac1a81 quota: Remove dqb... |
576 |
kfree(buf); |
1ccd14b9c quota: Split off ... |
577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 |
return ret; } /* Find entry for given id in the tree - wrapper function */ static inline loff_t find_dqentry(struct qtree_mem_dqinfo *info, struct dquot *dquot) { return find_tree_dqentry(info, dquot, QT_TREEOFF, 0); } int qtree_read_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot) { int type = dquot->dq_type; struct super_block *sb = dquot->dq_sb; loff_t offset; |
d26ac1a81 quota: Remove dqb... |
592 |
char *ddquot; |
1ccd14b9c quota: Split off ... |
593 594 595 596 597 |
int ret = 0; #ifdef __QUOTA_QT_PARANOIA /* Invalidated quota? */ if (!sb_dqopt(dquot->dq_sb)->files[type]) { |
fb5ffb0e1 quota: Change quo... |
598 |
quota_error(sb, "Quota invalidated while reading!"); |
1ccd14b9c quota: Split off ... |
599 600 601 602 603 604 605 606 |
return -EIO; } #endif /* Do we know offset of the dquot entry in the quota file? */ if (!dquot->dq_off) { offset = find_dqentry(info, dquot); if (offset <= 0) { /* Entry not present? */ if (offset < 0) |
fb5ffb0e1 quota: Change quo... |
607 608 |
quota_error(sb, "Can't read quota structure " "for id %u", dquot->dq_id); |
1ccd14b9c quota: Split off ... |
609 610 611 612 613 614 615 616 617 618 619 |
dquot->dq_off = 0; set_bit(DQ_FAKE_B, &dquot->dq_flags); memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk)); ret = offset; goto out; } dquot->dq_off = offset; } ddquot = getdqbuf(info->dqi_entry_size); if (!ddquot) return -ENOMEM; |
d26ac1a81 quota: Remove dqb... |
620 621 |
ret = sb->s_op->quota_read(sb, type, ddquot, info->dqi_entry_size, dquot->dq_off); |
1ccd14b9c quota: Split off ... |
622 623 624 |
if (ret != info->dqi_entry_size) { if (ret >= 0) ret = -EIO; |
fb5ffb0e1 quota: Change quo... |
625 626 |
quota_error(sb, "Error while reading quota structure for id %u", dquot->dq_id); |
1ccd14b9c quota: Split off ... |
627 628 |
set_bit(DQ_FAKE_B, &dquot->dq_flags); memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk)); |
d26ac1a81 quota: Remove dqb... |
629 |
kfree(ddquot); |
1ccd14b9c quota: Split off ... |
630 631 632 633 634 635 636 637 638 639 |
goto out; } spin_lock(&dq_data_lock); info->dqi_ops->disk2mem_dqblk(dquot, ddquot); if (!dquot->dq_dqb.dqb_bhardlimit && !dquot->dq_dqb.dqb_bsoftlimit && !dquot->dq_dqb.dqb_ihardlimit && !dquot->dq_dqb.dqb_isoftlimit) set_bit(DQ_FAKE_B, &dquot->dq_flags); spin_unlock(&dq_data_lock); |
d26ac1a81 quota: Remove dqb... |
640 |
kfree(ddquot); |
1ccd14b9c quota: Split off ... |
641 |
out: |
dde958885 quota: Make quota... |
642 |
dqstats_inc(DQST_READS); |
1ccd14b9c quota: Split off ... |
643 644 645 646 647 648 649 650 |
return ret; } EXPORT_SYMBOL(qtree_read_dquot); /* Check whether dquot should not be deleted. We know we are * the only one operating on dquot (thanks to dq_lock) */ int qtree_release_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot) { |
268157ba6 quota: Coding sty... |
651 652 |
if (test_bit(DQ_FAKE_B, &dquot->dq_flags) && !(dquot->dq_dqb.dqb_curinodes | dquot->dq_dqb.dqb_curspace)) |
1ccd14b9c quota: Split off ... |
653 654 655 656 |
return qtree_delete_dquot(info, dquot); return 0; } EXPORT_SYMBOL(qtree_release_dquot); |