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