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