The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/quota_v2.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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 
   19 typedef 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 */
   25 static 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 */
   48 static 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                         kdevname(f->f_dentry->d_sb->s_dev));
   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 */
   76 static 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                         kdevname(f->f_dentry->d_sb->s_dev));
   99                 return -1;
  100         }
  101         return 0;
  102 }
  103 
  104 static 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 
  116 static 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 
  129 static 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 
  137 static inline void freedqbuf(dqbuf_t buf)
  138 {
  139         kfree(buf);
  140 }
  141 
  142 static 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 
  156 static 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 */
  171 static 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;
  193 out_buf:
  194         freedqbuf(buf);
  195         return ret;
  196 }
  197 
  198 /* Insert empty block to the list */
  199 static 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 */
  215 static 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;
  247 out_buf:
  248         freedqbuf(tmpbuf);
  249         return err;
  250 }
  251 
  252 /* Insert given block to the beginning of list with free entries */
  253 static 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;
  276 out_buf:
  277         freedqbuf(tmpbuf);
  278         return err;
  279 }
  280 
  281 /* Find space for dquot */
  282 static 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;
  337 out_buf:
  338         freedqbuf(buf);
  339         return 0;
  340 }
  341 
  342 /* Insert reference to structure into the trie */
  343 static 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);
  390 out_buf:
  391         freedqbuf(buf);
  392         return ret;
  393 }
  394 
  395 /* Wrapper for inserting quota structure into tree */
  396 static 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  */
  405 static 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 %d 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", kdevname(dquot->dq_dev));
  428                 if (ret >= 0)
  429                         ret = -ENOSPC;
  430         }
  431         else
  432                 ret = 0;
  433         dqstats.writes++;
  434         return ret;
  435 }
  436 
  437 /* Free dquot entry in data block */
  438 static int free_dqentry(struct dquot *dquot, uint blk)
  439 {
  440         struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type];
  441         struct mem_dqinfo *info = sb_dqopt(dquot->dq_sb)->info + dquot->dq_type;
  442         struct v2_disk_dqdbheader *dh;
  443         dqbuf_t buf = getdqbuf();
  444         int ret = 0;
  445 
  446         if (!buf)
  447                 return -ENOMEM;
  448         if (dquot->dq_off >> V2_DQBLKSIZE_BITS != blk) {
  449                 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));
  450                 goto out_buf;
  451         }
  452         if ((ret = read_blk(filp, blk, buf)) < 0) {
  453                 printk(KERN_ERR "VFS: Can't read quota data block %u\n", blk);
  454                 goto out_buf;
  455         }
  456         dh = (struct v2_disk_dqdbheader *)buf;
  457         dh->dqdh_entries = cpu_to_le16(le16_to_cpu(dh->dqdh_entries)-1);
  458         if (!le16_to_cpu(dh->dqdh_entries)) {   /* Block got free? */
  459                 if ((ret = remove_free_dqentry(filp, info, buf, blk)) < 0 ||
  460                     (ret = put_free_dqblk(filp, info, buf, blk)) < 0) {
  461                         printk(KERN_ERR "VFS: Can't move quota data block (%u) to free list.\n", blk);
  462                         goto out_buf;
  463                 }
  464         }
  465         else {
  466                 memset(buf+(dquot->dq_off & ((1 << V2_DQBLKSIZE_BITS)-1)), 0, sizeof(struct v2_disk_dqblk));
  467                 if (le16_to_cpu(dh->dqdh_entries) == V2_DQSTRINBLK-1) {
  468                         /* Insert will write block itself */
  469                         if ((ret = insert_free_dqentry(filp, info, buf, blk)) < 0) {
  470                                 printk(KERN_ERR "VFS: Can't insert quota data block (%u) to free entry list.\n", blk);
  471                                 goto out_buf;
  472                         }
  473                 }
  474                 else
  475                         if ((ret = write_blk(filp, blk, buf)) < 0) {
  476                                 printk(KERN_ERR "VFS: Can't write quota data block %u\n", blk);
  477                                 goto out_buf;
  478                         }
  479         }
  480         dquot->dq_off = 0;      /* Quota is now unattached */
  481 out_buf:
  482         freedqbuf(buf);
  483         return ret;
  484 }
  485 
  486 /* Remove reference to dquot from tree */
  487 static int remove_tree(struct dquot *dquot, uint *blk, int depth)
  488 {
  489         struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type];
  490         struct mem_dqinfo *info = sb_dqopt(dquot->dq_sb)->info + dquot->dq_type;
  491         dqbuf_t buf = getdqbuf();
  492         int ret = 0;
  493         uint newblk;
  494         u32 *ref = (u32 *)buf;
  495         
  496         if (!buf)
  497                 return -ENOMEM;
  498         if ((ret = read_blk(filp, *blk, buf)) < 0) {
  499                 printk(KERN_ERR "VFS: Can't read quota data block %u\n", *blk);
  500                 goto out_buf;
  501         }
  502         newblk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]);
  503         if (depth == V2_DQTREEDEPTH-1) {
  504                 ret = free_dqentry(dquot, newblk);
  505                 newblk = 0;
  506         }
  507         else
  508                 ret = remove_tree(dquot, &newblk, depth+1);
  509         if (ret >= 0 && !newblk) {
  510                 int i;
  511                 ref[GETIDINDEX(dquot->dq_id, depth)] = cpu_to_le32(0);
  512                 for (i = 0; i < V2_DQBLKSIZE && !buf[i]; i++);  /* Block got empty? */
  513                 if (i == V2_DQBLKSIZE) {
  514                         put_free_dqblk(filp, info, buf, *blk);
  515                         *blk = 0;
  516                 }
  517                 else
  518                         if ((ret = write_blk(filp, *blk, buf)) < 0)
  519                                 printk(KERN_ERR "VFS: Can't write quota tree block %u.\n", *blk);
  520         }
  521 out_buf:
  522         freedqbuf(buf);
  523         return ret;     
  524 }
  525 
  526 /* Delete dquot from tree */
  527 static 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 */
  537 static loff_t find_block_dqentry(struct dquot *dquot, uint blk)
  538 {
  539         struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type];
  540         dqbuf_t buf = getdqbuf();
  541         loff_t ret = 0;
  542         int i;
  543         struct v2_disk_dqblk *ddquot = GETENTRIES(buf);
  544 
  545         if (!buf)
  546                 return -ENOMEM;
  547         if ((ret = read_blk(filp, blk, buf)) < 0) {
  548                 printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
  549                 goto out_buf;
  550         }
  551         if (dquot->dq_id)
  552                 for (i = 0; i < V2_DQSTRINBLK && 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) && memcmp(&fakedquot, ddquot+i, sizeof(struct v2_disk_dqblk)))
  559                                 break;
  560         }
  561         if (i == V2_DQSTRINBLK) {
  562                 printk(KERN_ERR "VFS: Quota for id %u referenced but not present.\n", dquot->dq_id);
  563                 ret = -EIO;
  564                 goto out_buf;
  565         }
  566         else
  567                 ret = (blk << V2_DQBLKSIZE_BITS) + sizeof(struct v2_disk_dqdbheader) + i * sizeof(struct v2_disk_dqblk);
  568 out_buf:
  569         freedqbuf(buf);
  570         return ret;
  571 }
  572 
  573 /* Find entry for given id in the tree */
  574 static loff_t find_tree_dqentry(struct dquot *dquot, uint blk, int depth)
  575 {
  576         struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type];
  577         dqbuf_t buf = getdqbuf();
  578         loff_t ret = 0;
  579         u32 *ref = (u32 *)buf;
  580 
  581         if (!buf)
  582                 return -ENOMEM;
  583         if ((ret = read_blk(filp, blk, buf)) < 0) {
  584                 printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
  585                 goto out_buf;
  586         }
  587         ret = 0;
  588         blk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]);
  589         if (!blk)       /* No reference? */
  590                 goto out_buf;
  591         if (depth < V2_DQTREEDEPTH-1)
  592                 ret = find_tree_dqentry(dquot, blk, depth+1);
  593         else
  594                 ret = find_block_dqentry(dquot, blk);
  595 out_buf:
  596         freedqbuf(buf);
  597         return ret;
  598 }
  599 
  600 /* Find entry for given id in the tree - wrapper function */
  601 static inline loff_t find_dqentry(struct dquot *dquot)
  602 {
  603         return find_tree_dqentry(dquot, V2_DQTREEOFF, 0);
  604 }
  605 
  606 static int v2_read_dquot(struct dquot *dquot)
  607 {
  608         int type = dquot->dq_type;
  609         struct file *filp;
  610         mm_segment_t fs;
  611         loff_t offset;
  612         struct v2_disk_dqblk ddquot;
  613         int ret = 0;
  614 
  615         filp = sb_dqopt(dquot->dq_sb)->files[type];
  616 
  617 #ifdef __QUOTA_V2_PARANOIA
  618         if (!filp || !dquot->dq_sb) {   /* Invalidated quota? */
  619                 printk(KERN_ERR "VFS: Quota invalidated while reading!\n");
  620                 return -EIO;
  621         }
  622 #endif
  623         offset = find_dqentry(dquot);
  624         if (offset <= 0) {      /* Entry not present? */
  625                 if (offset < 0)
  626                         printk(KERN_ERR "VFS: Can't read quota structure for id %u.\n", dquot->dq_id);
  627                 dquot->dq_off = 0;
  628                 dquot->dq_flags |= DQ_FAKE;
  629                 memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk));
  630                 ret = offset;
  631         }
  632         else {
  633                 dquot->dq_off = offset;
  634                 fs = get_fs();
  635                 set_fs(KERNEL_DS);
  636                 if ((ret = filp->f_op->read(filp, (char *)&ddquot, sizeof(struct v2_disk_dqblk), &offset)) != sizeof(struct v2_disk_dqblk)) {
  637                         if (ret >= 0)
  638                                 ret = -EIO;
  639                         printk(KERN_ERR "VFS: Error while reading quota structure for id %u.\n", dquot->dq_id);
  640                         memset(&ddquot, 0, sizeof(struct v2_disk_dqblk));
  641                 }
  642                 else
  643                         ret = 0;
  644                 set_fs(fs);
  645                 disk2memdqb(&dquot->dq_dqb, &ddquot);
  646         }
  647         dqstats.reads++;
  648         return ret;
  649 }
  650 
  651 /* Commit changes of dquot to disk - it might also mean deleting it when quota became fake one and user has no blocks... */
  652 static int v2_commit_dquot(struct dquot *dquot)
  653 {
  654         /* We clear the flag everytime so we don't loop when there was an IO error... */
  655         dquot->dq_flags &= ~DQ_MOD;
  656         if (dquot->dq_flags & DQ_FAKE && !(dquot->dq_dqb.dqb_curinodes | dquot->dq_dqb.dqb_curspace))
  657                 return v2_delete_dquot(dquot);
  658         else
  659                 return v2_write_dquot(dquot);
  660 }
  661 
  662 static struct quota_format_ops v2_format_ops = {
  663         check_quota_file:       v2_check_quota_file,
  664         read_file_info:         v2_read_file_info,
  665         write_file_info:        v2_write_file_info,
  666         free_file_info:         NULL,
  667         read_dqblk:             v2_read_dquot,
  668         commit_dqblk:           v2_commit_dquot,
  669 };
  670 
  671 static struct quota_format_type v2_quota_format = {
  672         qf_fmt_id:      QFMT_VFS_V0,
  673         qf_ops:         &v2_format_ops,
  674         qf_owner:       THIS_MODULE
  675 };
  676 
  677 static int __init init_v2_quota_format(void)
  678 {
  679         return register_quota_format(&v2_quota_format);
  680 }
  681 
  682 static void __exit exit_v2_quota_format(void)
  683 {
  684         unregister_quota_format(&v2_quota_format);
  685 }
  686 
  687 EXPORT_NO_SYMBOLS;
  688 
  689 module_init(init_v2_quota_format);
  690 module_exit(exit_v2_quota_format);

Cache object: 8883c3e3ec5fea443d1458b4c46cbe0e


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.