Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.26-rc9 698 lines 21 kB view raw
1/* 2 * vfsv0 quota IO operations on file 3 */ 4 5#include <linux/errno.h> 6#include <linux/fs.h> 7#include <linux/mount.h> 8#include <linux/dqblk_v2.h> 9#include <linux/quotaio_v2.h> 10#include <linux/kernel.h> 11#include <linux/init.h> 12#include <linux/module.h> 13#include <linux/slab.h> 14 15#include <asm/byteorder.h> 16 17MODULE_AUTHOR("Jan Kara"); 18MODULE_DESCRIPTION("Quota format v2 support"); 19MODULE_LICENSE("GPL"); 20 21#define __QUOTA_V2_PARANOIA 22 23typedef char *dqbuf_t; 24 25#define GETIDINDEX(id, depth) (((id) >> ((V2_DQTREEDEPTH-(depth)-1)*8)) & 0xff) 26#define GETENTRIES(buf) ((struct v2_disk_dqblk *)(((char *)buf)+sizeof(struct v2_disk_dqdbheader))) 27 28/* Check whether given file is really vfsv0 quotafile */ 29static int v2_check_quota_file(struct super_block *sb, int type) 30{ 31 struct v2_disk_dqheader dqhead; 32 ssize_t size; 33 static const uint quota_magics[] = V2_INITQMAGICS; 34 static const uint quota_versions[] = V2_INITQVERSIONS; 35 36 size = sb->s_op->quota_read(sb, type, (char *)&dqhead, sizeof(struct v2_disk_dqheader), 0); 37 if (size != sizeof(struct v2_disk_dqheader)) { 38 printk("quota_v2: failed read expected=%zd got=%zd\n", 39 sizeof(struct v2_disk_dqheader), size); 40 return 0; 41 } 42 if (le32_to_cpu(dqhead.dqh_magic) != quota_magics[type] || 43 le32_to_cpu(dqhead.dqh_version) != quota_versions[type]) 44 return 0; 45 return 1; 46} 47 48/* Read information header from quota file */ 49static int v2_read_file_info(struct super_block *sb, int type) 50{ 51 struct v2_disk_dqinfo dinfo; 52 struct mem_dqinfo *info = sb_dqopt(sb)->info+type; 53 ssize_t size; 54 55 size = sb->s_op->quota_read(sb, type, (char *)&dinfo, 56 sizeof(struct v2_disk_dqinfo), V2_DQINFOOFF); 57 if (size != sizeof(struct v2_disk_dqinfo)) { 58 printk(KERN_WARNING "Can't read info structure on device %s.\n", 59 sb->s_id); 60 return -1; 61 } 62 /* limits are stored as unsigned 32-bit data */ 63 info->dqi_maxblimit = 0xffffffff; 64 info->dqi_maxilimit = 0xffffffff; 65 info->dqi_bgrace = le32_to_cpu(dinfo.dqi_bgrace); 66 info->dqi_igrace = le32_to_cpu(dinfo.dqi_igrace); 67 info->dqi_flags = le32_to_cpu(dinfo.dqi_flags); 68 info->u.v2_i.dqi_blocks = le32_to_cpu(dinfo.dqi_blocks); 69 info->u.v2_i.dqi_free_blk = le32_to_cpu(dinfo.dqi_free_blk); 70 info->u.v2_i.dqi_free_entry = le32_to_cpu(dinfo.dqi_free_entry); 71 return 0; 72} 73 74/* Write information header to quota file */ 75static int v2_write_file_info(struct super_block *sb, int type) 76{ 77 struct v2_disk_dqinfo dinfo; 78 struct mem_dqinfo *info = sb_dqopt(sb)->info+type; 79 ssize_t size; 80 81 spin_lock(&dq_data_lock); 82 info->dqi_flags &= ~DQF_INFO_DIRTY; 83 dinfo.dqi_bgrace = cpu_to_le32(info->dqi_bgrace); 84 dinfo.dqi_igrace = cpu_to_le32(info->dqi_igrace); 85 dinfo.dqi_flags = cpu_to_le32(info->dqi_flags & DQF_MASK); 86 spin_unlock(&dq_data_lock); 87 dinfo.dqi_blocks = cpu_to_le32(info->u.v2_i.dqi_blocks); 88 dinfo.dqi_free_blk = cpu_to_le32(info->u.v2_i.dqi_free_blk); 89 dinfo.dqi_free_entry = cpu_to_le32(info->u.v2_i.dqi_free_entry); 90 size = sb->s_op->quota_write(sb, type, (char *)&dinfo, 91 sizeof(struct v2_disk_dqinfo), V2_DQINFOOFF); 92 if (size != sizeof(struct v2_disk_dqinfo)) { 93 printk(KERN_WARNING "Can't write info structure on device %s.\n", 94 sb->s_id); 95 return -1; 96 } 97 return 0; 98} 99 100static void disk2memdqb(struct mem_dqblk *m, struct v2_disk_dqblk *d) 101{ 102 m->dqb_ihardlimit = le32_to_cpu(d->dqb_ihardlimit); 103 m->dqb_isoftlimit = le32_to_cpu(d->dqb_isoftlimit); 104 m->dqb_curinodes = le32_to_cpu(d->dqb_curinodes); 105 m->dqb_itime = le64_to_cpu(d->dqb_itime); 106 m->dqb_bhardlimit = le32_to_cpu(d->dqb_bhardlimit); 107 m->dqb_bsoftlimit = le32_to_cpu(d->dqb_bsoftlimit); 108 m->dqb_curspace = le64_to_cpu(d->dqb_curspace); 109 m->dqb_btime = le64_to_cpu(d->dqb_btime); 110} 111 112static void mem2diskdqb(struct v2_disk_dqblk *d, struct mem_dqblk *m, qid_t id) 113{ 114 d->dqb_ihardlimit = cpu_to_le32(m->dqb_ihardlimit); 115 d->dqb_isoftlimit = cpu_to_le32(m->dqb_isoftlimit); 116 d->dqb_curinodes = cpu_to_le32(m->dqb_curinodes); 117 d->dqb_itime = cpu_to_le64(m->dqb_itime); 118 d->dqb_bhardlimit = cpu_to_le32(m->dqb_bhardlimit); 119 d->dqb_bsoftlimit = cpu_to_le32(m->dqb_bsoftlimit); 120 d->dqb_curspace = cpu_to_le64(m->dqb_curspace); 121 d->dqb_btime = cpu_to_le64(m->dqb_btime); 122 d->dqb_id = cpu_to_le32(id); 123} 124 125static dqbuf_t getdqbuf(void) 126{ 127 dqbuf_t buf = kmalloc(V2_DQBLKSIZE, GFP_NOFS); 128 if (!buf) 129 printk(KERN_WARNING "VFS: Not enough memory for quota buffers.\n"); 130 return buf; 131} 132 133static inline void freedqbuf(dqbuf_t buf) 134{ 135 kfree(buf); 136} 137 138static inline ssize_t read_blk(struct super_block *sb, int type, uint blk, dqbuf_t buf) 139{ 140 memset(buf, 0, V2_DQBLKSIZE); 141 return sb->s_op->quota_read(sb, type, (char *)buf, 142 V2_DQBLKSIZE, blk << V2_DQBLKSIZE_BITS); 143} 144 145static inline ssize_t write_blk(struct super_block *sb, int type, uint blk, dqbuf_t buf) 146{ 147 return sb->s_op->quota_write(sb, type, (char *)buf, 148 V2_DQBLKSIZE, blk << V2_DQBLKSIZE_BITS); 149} 150 151/* Remove empty block from list and return it */ 152static int get_free_dqblk(struct super_block *sb, int type) 153{ 154 dqbuf_t buf = getdqbuf(); 155 struct mem_dqinfo *info = sb_dqinfo(sb, type); 156 struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf; 157 int ret, blk; 158 159 if (!buf) 160 return -ENOMEM; 161 if (info->u.v2_i.dqi_free_blk) { 162 blk = info->u.v2_i.dqi_free_blk; 163 if ((ret = read_blk(sb, type, blk, buf)) < 0) 164 goto out_buf; 165 info->u.v2_i.dqi_free_blk = le32_to_cpu(dh->dqdh_next_free); 166 } 167 else { 168 memset(buf, 0, V2_DQBLKSIZE); 169 /* Assure block allocation... */ 170 if ((ret = write_blk(sb, type, info->u.v2_i.dqi_blocks, buf)) < 0) 171 goto out_buf; 172 blk = info->u.v2_i.dqi_blocks++; 173 } 174 mark_info_dirty(sb, type); 175 ret = blk; 176out_buf: 177 freedqbuf(buf); 178 return ret; 179} 180 181/* Insert empty block to the list */ 182static int put_free_dqblk(struct super_block *sb, int type, dqbuf_t buf, uint blk) 183{ 184 struct mem_dqinfo *info = sb_dqinfo(sb, type); 185 struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf; 186 int err; 187 188 dh->dqdh_next_free = cpu_to_le32(info->u.v2_i.dqi_free_blk); 189 dh->dqdh_prev_free = cpu_to_le32(0); 190 dh->dqdh_entries = cpu_to_le16(0); 191 info->u.v2_i.dqi_free_blk = blk; 192 mark_info_dirty(sb, type); 193 /* Some strange block. We had better leave it... */ 194 if ((err = write_blk(sb, type, blk, buf)) < 0) 195 return err; 196 return 0; 197} 198 199/* Remove given block from the list of blocks with free entries */ 200static int remove_free_dqentry(struct super_block *sb, int type, dqbuf_t buf, uint blk) 201{ 202 dqbuf_t tmpbuf = getdqbuf(); 203 struct mem_dqinfo *info = sb_dqinfo(sb, type); 204 struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf; 205 uint nextblk = le32_to_cpu(dh->dqdh_next_free), prevblk = le32_to_cpu(dh->dqdh_prev_free); 206 int err; 207 208 if (!tmpbuf) 209 return -ENOMEM; 210 if (nextblk) { 211 if ((err = read_blk(sb, type, nextblk, tmpbuf)) < 0) 212 goto out_buf; 213 ((struct v2_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = dh->dqdh_prev_free; 214 if ((err = write_blk(sb, type, nextblk, tmpbuf)) < 0) 215 goto out_buf; 216 } 217 if (prevblk) { 218 if ((err = read_blk(sb, type, prevblk, tmpbuf)) < 0) 219 goto out_buf; 220 ((struct v2_disk_dqdbheader *)tmpbuf)->dqdh_next_free = dh->dqdh_next_free; 221 if ((err = write_blk(sb, type, prevblk, tmpbuf)) < 0) 222 goto out_buf; 223 } 224 else { 225 info->u.v2_i.dqi_free_entry = nextblk; 226 mark_info_dirty(sb, type); 227 } 228 freedqbuf(tmpbuf); 229 dh->dqdh_next_free = dh->dqdh_prev_free = cpu_to_le32(0); 230 /* No matter whether write succeeds block is out of list */ 231 if (write_blk(sb, type, blk, buf) < 0) 232 printk(KERN_ERR "VFS: Can't write block (%u) with free entries.\n", blk); 233 return 0; 234out_buf: 235 freedqbuf(tmpbuf); 236 return err; 237} 238 239/* Insert given block to the beginning of list with free entries */ 240static int insert_free_dqentry(struct super_block *sb, int type, dqbuf_t buf, uint blk) 241{ 242 dqbuf_t tmpbuf = getdqbuf(); 243 struct mem_dqinfo *info = sb_dqinfo(sb, type); 244 struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf; 245 int err; 246 247 if (!tmpbuf) 248 return -ENOMEM; 249 dh->dqdh_next_free = cpu_to_le32(info->u.v2_i.dqi_free_entry); 250 dh->dqdh_prev_free = cpu_to_le32(0); 251 if ((err = write_blk(sb, type, blk, buf)) < 0) 252 goto out_buf; 253 if (info->u.v2_i.dqi_free_entry) { 254 if ((err = read_blk(sb, type, info->u.v2_i.dqi_free_entry, tmpbuf)) < 0) 255 goto out_buf; 256 ((struct v2_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = cpu_to_le32(blk); 257 if ((err = write_blk(sb, type, info->u.v2_i.dqi_free_entry, tmpbuf)) < 0) 258 goto out_buf; 259 } 260 freedqbuf(tmpbuf); 261 info->u.v2_i.dqi_free_entry = blk; 262 mark_info_dirty(sb, type); 263 return 0; 264out_buf: 265 freedqbuf(tmpbuf); 266 return err; 267} 268 269/* Find space for dquot */ 270static uint find_free_dqentry(struct dquot *dquot, int *err) 271{ 272 struct super_block *sb = dquot->dq_sb; 273 struct mem_dqinfo *info = sb_dqopt(sb)->info+dquot->dq_type; 274 uint blk, i; 275 struct v2_disk_dqdbheader *dh; 276 struct v2_disk_dqblk *ddquot; 277 struct v2_disk_dqblk fakedquot; 278 dqbuf_t buf; 279 280 *err = 0; 281 if (!(buf = getdqbuf())) { 282 *err = -ENOMEM; 283 return 0; 284 } 285 dh = (struct v2_disk_dqdbheader *)buf; 286 ddquot = GETENTRIES(buf); 287 if (info->u.v2_i.dqi_free_entry) { 288 blk = info->u.v2_i.dqi_free_entry; 289 if ((*err = read_blk(sb, dquot->dq_type, blk, buf)) < 0) 290 goto out_buf; 291 } 292 else { 293 blk = get_free_dqblk(sb, dquot->dq_type); 294 if ((int)blk < 0) { 295 *err = blk; 296 freedqbuf(buf); 297 return 0; 298 } 299 memset(buf, 0, V2_DQBLKSIZE); 300 /* This is enough as block is already zeroed and entry list is empty... */ 301 info->u.v2_i.dqi_free_entry = blk; 302 mark_info_dirty(sb, dquot->dq_type); 303 } 304 if (le16_to_cpu(dh->dqdh_entries)+1 >= V2_DQSTRINBLK) /* Block will be full? */ 305 if ((*err = remove_free_dqentry(sb, dquot->dq_type, buf, blk)) < 0) { 306 printk(KERN_ERR "VFS: find_free_dqentry(): Can't remove block (%u) from entry free list.\n", blk); 307 goto out_buf; 308 } 309 le16_add_cpu(&dh->dqdh_entries, 1); 310 memset(&fakedquot, 0, sizeof(struct v2_disk_dqblk)); 311 /* Find free structure in block */ 312 for (i = 0; i < V2_DQSTRINBLK && memcmp(&fakedquot, ddquot+i, sizeof(struct v2_disk_dqblk)); i++); 313#ifdef __QUOTA_V2_PARANOIA 314 if (i == V2_DQSTRINBLK) { 315 printk(KERN_ERR "VFS: find_free_dqentry(): Data block full but it shouldn't.\n"); 316 *err = -EIO; 317 goto out_buf; 318 } 319#endif 320 if ((*err = write_blk(sb, dquot->dq_type, blk, buf)) < 0) { 321 printk(KERN_ERR "VFS: find_free_dqentry(): Can't write quota data block %u.\n", blk); 322 goto out_buf; 323 } 324 dquot->dq_off = (blk<<V2_DQBLKSIZE_BITS)+sizeof(struct v2_disk_dqdbheader)+i*sizeof(struct v2_disk_dqblk); 325 freedqbuf(buf); 326 return blk; 327out_buf: 328 freedqbuf(buf); 329 return 0; 330} 331 332/* Insert reference to structure into the trie */ 333static int do_insert_tree(struct dquot *dquot, uint *treeblk, int depth) 334{ 335 struct super_block *sb = dquot->dq_sb; 336 dqbuf_t buf; 337 int ret = 0, newson = 0, newact = 0; 338 __le32 *ref; 339 uint newblk; 340 341 if (!(buf = getdqbuf())) 342 return -ENOMEM; 343 if (!*treeblk) { 344 ret = get_free_dqblk(sb, dquot->dq_type); 345 if (ret < 0) 346 goto out_buf; 347 *treeblk = ret; 348 memset(buf, 0, V2_DQBLKSIZE); 349 newact = 1; 350 } 351 else { 352 if ((ret = read_blk(sb, dquot->dq_type, *treeblk, buf)) < 0) { 353 printk(KERN_ERR "VFS: Can't read tree quota block %u.\n", *treeblk); 354 goto out_buf; 355 } 356 } 357 ref = (__le32 *)buf; 358 newblk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]); 359 if (!newblk) 360 newson = 1; 361 if (depth == V2_DQTREEDEPTH-1) { 362#ifdef __QUOTA_V2_PARANOIA 363 if (newblk) { 364 printk(KERN_ERR "VFS: Inserting already present quota entry (block %u).\n", le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)])); 365 ret = -EIO; 366 goto out_buf; 367 } 368#endif 369 newblk = find_free_dqentry(dquot, &ret); 370 } 371 else 372 ret = do_insert_tree(dquot, &newblk, depth+1); 373 if (newson && ret >= 0) { 374 ref[GETIDINDEX(dquot->dq_id, depth)] = cpu_to_le32(newblk); 375 ret = write_blk(sb, dquot->dq_type, *treeblk, buf); 376 } 377 else if (newact && ret < 0) 378 put_free_dqblk(sb, dquot->dq_type, buf, *treeblk); 379out_buf: 380 freedqbuf(buf); 381 return ret; 382} 383 384/* Wrapper for inserting quota structure into tree */ 385static inline int dq_insert_tree(struct dquot *dquot) 386{ 387 int tmp = V2_DQTREEOFF; 388 return do_insert_tree(dquot, &tmp, 0); 389} 390 391/* 392 * We don't have to be afraid of deadlocks as we never have quotas on quota files... 393 */ 394static int v2_write_dquot(struct dquot *dquot) 395{ 396 int type = dquot->dq_type; 397 ssize_t ret; 398 struct v2_disk_dqblk ddquot, empty; 399 400 /* dq_off is guarded by dqio_mutex */ 401 if (!dquot->dq_off) 402 if ((ret = dq_insert_tree(dquot)) < 0) { 403 printk(KERN_ERR "VFS: Error %zd occurred while creating quota.\n", ret); 404 return ret; 405 } 406 spin_lock(&dq_data_lock); 407 mem2diskdqb(&ddquot, &dquot->dq_dqb, dquot->dq_id); 408 /* Argh... We may need to write structure full of zeroes but that would be 409 * treated as an empty place by the rest of the code. Format change would 410 * be definitely cleaner but the problems probably are not worth it */ 411 memset(&empty, 0, sizeof(struct v2_disk_dqblk)); 412 if (!memcmp(&empty, &ddquot, sizeof(struct v2_disk_dqblk))) 413 ddquot.dqb_itime = cpu_to_le64(1); 414 spin_unlock(&dq_data_lock); 415 ret = dquot->dq_sb->s_op->quota_write(dquot->dq_sb, type, 416 (char *)&ddquot, sizeof(struct v2_disk_dqblk), dquot->dq_off); 417 if (ret != sizeof(struct v2_disk_dqblk)) { 418 printk(KERN_WARNING "VFS: dquota write failed on dev %s\n", dquot->dq_sb->s_id); 419 if (ret >= 0) 420 ret = -ENOSPC; 421 } 422 else 423 ret = 0; 424 dqstats.writes++; 425 426 return ret; 427} 428 429/* Free dquot entry in data block */ 430static int free_dqentry(struct dquot *dquot, uint blk) 431{ 432 struct super_block *sb = dquot->dq_sb; 433 int type = dquot->dq_type; 434 struct v2_disk_dqdbheader *dh; 435 dqbuf_t buf = getdqbuf(); 436 int ret = 0; 437 438 if (!buf) 439 return -ENOMEM; 440 if (dquot->dq_off >> V2_DQBLKSIZE_BITS != blk) { 441 printk(KERN_ERR "VFS: Quota structure has offset to other " 442 "block (%u) than it should (%u).\n", blk, 443 (uint)(dquot->dq_off >> V2_DQBLKSIZE_BITS)); 444 goto out_buf; 445 } 446 if ((ret = read_blk(sb, type, blk, buf)) < 0) { 447 printk(KERN_ERR "VFS: Can't read quota data block %u\n", blk); 448 goto out_buf; 449 } 450 dh = (struct v2_disk_dqdbheader *)buf; 451 le16_add_cpu(&dh->dqdh_entries, -1); 452 if (!le16_to_cpu(dh->dqdh_entries)) { /* Block got free? */ 453 if ((ret = remove_free_dqentry(sb, type, buf, blk)) < 0 || 454 (ret = put_free_dqblk(sb, type, buf, blk)) < 0) { 455 printk(KERN_ERR "VFS: Can't move quota data block (%u) " 456 "to free list.\n", blk); 457 goto out_buf; 458 } 459 } 460 else { 461 memset(buf+(dquot->dq_off & ((1 << V2_DQBLKSIZE_BITS)-1)), 0, 462 sizeof(struct v2_disk_dqblk)); 463 if (le16_to_cpu(dh->dqdh_entries) == V2_DQSTRINBLK-1) { 464 /* Insert will write block itself */ 465 if ((ret = insert_free_dqentry(sb, type, buf, blk)) < 0) { 466 printk(KERN_ERR "VFS: Can't insert quota data block (%u) to free entry list.\n", blk); 467 goto out_buf; 468 } 469 } 470 else 471 if ((ret = write_blk(sb, type, blk, buf)) < 0) { 472 printk(KERN_ERR "VFS: Can't write quota data " 473 "block %u\n", blk); 474 goto out_buf; 475 } 476 } 477 dquot->dq_off = 0; /* Quota is now unattached */ 478out_buf: 479 freedqbuf(buf); 480 return ret; 481} 482 483/* Remove reference to dquot from tree */ 484static int remove_tree(struct dquot *dquot, uint *blk, int depth) 485{ 486 struct super_block *sb = dquot->dq_sb; 487 int type = dquot->dq_type; 488 dqbuf_t buf = getdqbuf(); 489 int ret = 0; 490 uint newblk; 491 __le32 *ref = (__le32 *)buf; 492 493 if (!buf) 494 return -ENOMEM; 495 if ((ret = read_blk(sb, type, *blk, buf)) < 0) { 496 printk(KERN_ERR "VFS: Can't read quota data block %u\n", *blk); 497 goto out_buf; 498 } 499 newblk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]); 500 if (depth == V2_DQTREEDEPTH-1) { 501 ret = free_dqentry(dquot, newblk); 502 newblk = 0; 503 } 504 else 505 ret = remove_tree(dquot, &newblk, depth+1); 506 if (ret >= 0 && !newblk) { 507 int i; 508 ref[GETIDINDEX(dquot->dq_id, depth)] = cpu_to_le32(0); 509 for (i = 0; i < V2_DQBLKSIZE && !buf[i]; i++); /* Block got empty? */ 510 /* Don't put the root block into the free block list */ 511 if (i == V2_DQBLKSIZE && *blk != V2_DQTREEOFF) { 512 put_free_dqblk(sb, type, buf, *blk); 513 *blk = 0; 514 } 515 else 516 if ((ret = write_blk(sb, type, *blk, buf)) < 0) 517 printk(KERN_ERR "VFS: Can't write quota tree " 518 "block %u.\n", *blk); 519 } 520out_buf: 521 freedqbuf(buf); 522 return ret; 523} 524 525/* Delete dquot from tree */ 526static int v2_delete_dquot(struct dquot *dquot) 527{ 528 uint tmp = V2_DQTREEOFF; 529 530 if (!dquot->dq_off) /* Even not allocated? */ 531 return 0; 532 return remove_tree(dquot, &tmp, 0); 533} 534 535/* Find entry in block */ 536static loff_t find_block_dqentry(struct dquot *dquot, uint blk) 537{ 538 dqbuf_t buf = getdqbuf(); 539 loff_t ret = 0; 540 int i; 541 struct v2_disk_dqblk *ddquot = GETENTRIES(buf); 542 543 if (!buf) 544 return -ENOMEM; 545 if ((ret = read_blk(dquot->dq_sb, dquot->dq_type, blk, buf)) < 0) { 546 printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk); 547 goto out_buf; 548 } 549 if (dquot->dq_id) 550 for (i = 0; i < V2_DQSTRINBLK && 551 le32_to_cpu(ddquot[i].dqb_id) != dquot->dq_id; i++); 552 else { /* ID 0 as a bit more complicated searching... */ 553 struct v2_disk_dqblk fakedquot; 554 555 memset(&fakedquot, 0, sizeof(struct v2_disk_dqblk)); 556 for (i = 0; i < V2_DQSTRINBLK; i++) 557 if (!le32_to_cpu(ddquot[i].dqb_id) && 558 memcmp(&fakedquot, ddquot+i, sizeof(struct v2_disk_dqblk))) 559 break; 560 } 561 if (i == V2_DQSTRINBLK) { 562 printk(KERN_ERR "VFS: Quota for id %u referenced " 563 "but not present.\n", dquot->dq_id); 564 ret = -EIO; 565 goto out_buf; 566 } 567 else 568 ret = (blk << V2_DQBLKSIZE_BITS) + sizeof(struct 569 v2_disk_dqdbheader) + i * sizeof(struct v2_disk_dqblk); 570out_buf: 571 freedqbuf(buf); 572 return ret; 573} 574 575/* Find entry for given id in the tree */ 576static loff_t find_tree_dqentry(struct dquot *dquot, uint blk, int depth) 577{ 578 dqbuf_t buf = getdqbuf(); 579 loff_t ret = 0; 580 __le32 *ref = (__le32 *)buf; 581 582 if (!buf) 583 return -ENOMEM; 584 if ((ret = read_blk(dquot->dq_sb, dquot->dq_type, blk, buf)) < 0) { 585 printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk); 586 goto out_buf; 587 } 588 ret = 0; 589 blk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]); 590 if (!blk) /* No reference? */ 591 goto out_buf; 592 if (depth < V2_DQTREEDEPTH-1) 593 ret = find_tree_dqentry(dquot, blk, depth+1); 594 else 595 ret = find_block_dqentry(dquot, blk); 596out_buf: 597 freedqbuf(buf); 598 return ret; 599} 600 601/* Find entry for given id in the tree - wrapper function */ 602static inline loff_t find_dqentry(struct dquot *dquot) 603{ 604 return find_tree_dqentry(dquot, V2_DQTREEOFF, 0); 605} 606 607static int v2_read_dquot(struct dquot *dquot) 608{ 609 int type = dquot->dq_type; 610 loff_t offset; 611 struct v2_disk_dqblk ddquot, empty; 612 int ret = 0; 613 614#ifdef __QUOTA_V2_PARANOIA 615 /* Invalidated quota? */ 616 if (!dquot->dq_sb || !sb_dqopt(dquot->dq_sb)->files[type]) { 617 printk(KERN_ERR "VFS: Quota invalidated while reading!\n"); 618 return -EIO; 619 } 620#endif 621 offset = find_dqentry(dquot); 622 if (offset <= 0) { /* Entry not present? */ 623 if (offset < 0) 624 printk(KERN_ERR "VFS: Can't read quota " 625 "structure for id %u.\n", dquot->dq_id); 626 dquot->dq_off = 0; 627 set_bit(DQ_FAKE_B, &dquot->dq_flags); 628 memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk)); 629 ret = offset; 630 } 631 else { 632 dquot->dq_off = offset; 633 if ((ret = dquot->dq_sb->s_op->quota_read(dquot->dq_sb, type, 634 (char *)&ddquot, sizeof(struct v2_disk_dqblk), offset)) 635 != sizeof(struct v2_disk_dqblk)) { 636 if (ret >= 0) 637 ret = -EIO; 638 printk(KERN_ERR "VFS: Error while reading quota " 639 "structure for id %u.\n", dquot->dq_id); 640 memset(&ddquot, 0, sizeof(struct v2_disk_dqblk)); 641 } 642 else { 643 ret = 0; 644 /* We need to escape back all-zero structure */ 645 memset(&empty, 0, sizeof(struct v2_disk_dqblk)); 646 empty.dqb_itime = cpu_to_le64(1); 647 if (!memcmp(&empty, &ddquot, sizeof(struct v2_disk_dqblk))) 648 ddquot.dqb_itime = 0; 649 } 650 disk2memdqb(&dquot->dq_dqb, &ddquot); 651 if (!dquot->dq_dqb.dqb_bhardlimit && 652 !dquot->dq_dqb.dqb_bsoftlimit && 653 !dquot->dq_dqb.dqb_ihardlimit && 654 !dquot->dq_dqb.dqb_isoftlimit) 655 set_bit(DQ_FAKE_B, &dquot->dq_flags); 656 } 657 dqstats.reads++; 658 659 return ret; 660} 661 662/* Check whether dquot should not be deleted. We know we are 663 * the only one operating on dquot (thanks to dq_lock) */ 664static int v2_release_dquot(struct dquot *dquot) 665{ 666 if (test_bit(DQ_FAKE_B, &dquot->dq_flags) && !(dquot->dq_dqb.dqb_curinodes | dquot->dq_dqb.dqb_curspace)) 667 return v2_delete_dquot(dquot); 668 return 0; 669} 670 671static struct quota_format_ops v2_format_ops = { 672 .check_quota_file = v2_check_quota_file, 673 .read_file_info = v2_read_file_info, 674 .write_file_info = v2_write_file_info, 675 .free_file_info = NULL, 676 .read_dqblk = v2_read_dquot, 677 .commit_dqblk = v2_write_dquot, 678 .release_dqblk = v2_release_dquot, 679}; 680 681static struct quota_format_type v2_quota_format = { 682 .qf_fmt_id = QFMT_VFS_V0, 683 .qf_ops = &v2_format_ops, 684 .qf_owner = THIS_MODULE 685}; 686 687static int __init init_v2_quota_format(void) 688{ 689 return register_quota_format(&v2_quota_format); 690} 691 692static void __exit exit_v2_quota_format(void) 693{ 694 unregister_quota_format(&v2_quota_format); 695} 696 697module_init(init_v2_quota_format); 698module_exit(exit_v2_quota_format);