~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/quota_v2.c

Version: ~ [ linux-5.10-rc1 ] ~ [ linux-5.9.1 ] ~ [ linux-5.8.16 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.72 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.152 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.202 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.240 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.240 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.85 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp