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