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