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/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 
   18 MODULE_AUTHOR("Jan Kara");
   19 MODULE_DESCRIPTION("Quota format v2 support");
   20 MODULE_LICENSE("GPL");
   21 
   22 #define __QUOTA_V2_PARANOIA
   23 
   24 typedef 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 */
   30 static 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 */
   50 static 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 */
   76 static 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 
  101 static 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 
  113 static 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 
  126 static 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 
  134 static inline void freedqbuf(dqbuf_t buf)
  135 {
  136         kfree(buf);
  137 }
  138 
  139 static 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 
  146 static 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 */
  153 static 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;
  177 out_buf:
  178         freedqbuf(buf);
  179         return ret;
  180 }
  181 
  182 /* Insert empty block to the list */
  183 static 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 */
  201 static 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;
  235 out_buf:
  236         freedqbuf(tmpbuf);
  237         return err;
  238 }
  239 
  240 /* Insert given block to the beginning of list with free entries */
  241 static 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;
  265 out_buf:
  266         freedqbuf(tmpbuf);
  267         return err;
  268 }
  269 
  270 /* Find space for dquot */
  271 static 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;
  328 out_buf:
  329         freedqbuf(buf);
  330         return 0;
  331 }
  332 
  333 /* Insert reference to structure into the trie */
  334 static 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);
  380 out_buf:
  381         freedqbuf(buf);
  382         return ret;
  383 }
  384 
  385 /* Wrapper for inserting quota structure into tree */
  386 static 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  */
  395 static 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 */
  431 static 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 */
  479 out_buf:
  480         freedqbuf(buf);
  481         return ret;
  482 }
  483 
  484 /* Remove reference to dquot from tree */
  485 static 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         }
  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         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);
  571 out_buf:
  572         freedqbuf(buf);
  573         return ret;
  574 }
  575 
  576 /* Find entry for given id in the tree */
  577 static 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);
  597 out_buf:
  598         freedqbuf(buf);
  599         return ret;
  600 }
  601 
  602 /* Find entry for given id in the tree - wrapper function */
  603 static inline loff_t find_dqentry(struct dquot *dquot)
  604 {
  605         return find_tree_dqentry(dquot, V2_DQTREEOFF, 0);
  606 }
  607 
  608 static 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) */
  665 static 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 
  672 static 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 
  682 static 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 
  688 static int __init init_v2_quota_format(void)
  689 {
  690         return register_quota_format(&v2_quota_format);
  691 }
  692 
  693 static void __exit exit_v2_quota_format(void)
  694 {
  695         unregister_quota_format(&v2_quota_format);
  696 }
  697 
  698 module_init(init_v2_quota_format);
  699 module_exit(exit_v2_quota_format);

Cache object: 82c86123bca0518386a037bc64f94f7d


[ 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.