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

TOMOYO Linux Cross Reference
Linux/fs/nilfs2/cpfile.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  * cpfile.c - NILFS checkpoint file.
  3  *
  4  * Copyright (C) 2006-2008 Nippon Telegraph and Telephone Corporation.
  5  *
  6  * This program is free software; you can redistribute it and/or modify
  7  * it under the terms of the GNU General Public License as published by
  8  * the Free Software Foundation; either version 2 of the License, or
  9  * (at your option) any later version.
 10  *
 11  * This program is distributed in the hope that it will be useful,
 12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 14  * GNU General Public License for more details.
 15  *
 16  * Written by Koji Sato.
 17  */
 18 
 19 #include <linux/kernel.h>
 20 #include <linux/fs.h>
 21 #include <linux/string.h>
 22 #include <linux/buffer_head.h>
 23 #include <linux/errno.h>
 24 #include "mdt.h"
 25 #include "cpfile.h"
 26 
 27 
 28 static inline unsigned long
 29 nilfs_cpfile_checkpoints_per_block(const struct inode *cpfile)
 30 {
 31         return NILFS_MDT(cpfile)->mi_entries_per_block;
 32 }
 33 
 34 /* block number from the beginning of the file */
 35 static unsigned long
 36 nilfs_cpfile_get_blkoff(const struct inode *cpfile, __u64 cno)
 37 {
 38         __u64 tcno = cno + NILFS_MDT(cpfile)->mi_first_entry_offset - 1;
 39 
 40         do_div(tcno, nilfs_cpfile_checkpoints_per_block(cpfile));
 41         return (unsigned long)tcno;
 42 }
 43 
 44 /* offset in block */
 45 static unsigned long
 46 nilfs_cpfile_get_offset(const struct inode *cpfile, __u64 cno)
 47 {
 48         __u64 tcno = cno + NILFS_MDT(cpfile)->mi_first_entry_offset - 1;
 49 
 50         return do_div(tcno, nilfs_cpfile_checkpoints_per_block(cpfile));
 51 }
 52 
 53 static __u64 nilfs_cpfile_first_checkpoint_in_block(const struct inode *cpfile,
 54                                                     unsigned long blkoff)
 55 {
 56         return (__u64)nilfs_cpfile_checkpoints_per_block(cpfile) * blkoff
 57                 + 1 - NILFS_MDT(cpfile)->mi_first_entry_offset;
 58 }
 59 
 60 static unsigned long
 61 nilfs_cpfile_checkpoints_in_block(const struct inode *cpfile,
 62                                   __u64 curr,
 63                                   __u64 max)
 64 {
 65         return min_t(__u64,
 66                      nilfs_cpfile_checkpoints_per_block(cpfile) -
 67                      nilfs_cpfile_get_offset(cpfile, curr),
 68                      max - curr);
 69 }
 70 
 71 static inline int nilfs_cpfile_is_in_first(const struct inode *cpfile,
 72                                            __u64 cno)
 73 {
 74         return nilfs_cpfile_get_blkoff(cpfile, cno) == 0;
 75 }
 76 
 77 static unsigned int
 78 nilfs_cpfile_block_add_valid_checkpoints(const struct inode *cpfile,
 79                                          struct buffer_head *bh,
 80                                          void *kaddr,
 81                                          unsigned int n)
 82 {
 83         struct nilfs_checkpoint *cp = kaddr + bh_offset(bh);
 84         unsigned int count;
 85 
 86         count = le32_to_cpu(cp->cp_checkpoints_count) + n;
 87         cp->cp_checkpoints_count = cpu_to_le32(count);
 88         return count;
 89 }
 90 
 91 static unsigned int
 92 nilfs_cpfile_block_sub_valid_checkpoints(const struct inode *cpfile,
 93                                          struct buffer_head *bh,
 94                                          void *kaddr,
 95                                          unsigned int n)
 96 {
 97         struct nilfs_checkpoint *cp = kaddr + bh_offset(bh);
 98         unsigned int count;
 99 
100         WARN_ON(le32_to_cpu(cp->cp_checkpoints_count) < n);
101         count = le32_to_cpu(cp->cp_checkpoints_count) - n;
102         cp->cp_checkpoints_count = cpu_to_le32(count);
103         return count;
104 }
105 
106 static inline struct nilfs_cpfile_header *
107 nilfs_cpfile_block_get_header(const struct inode *cpfile,
108                               struct buffer_head *bh,
109                               void *kaddr)
110 {
111         return kaddr + bh_offset(bh);
112 }
113 
114 static struct nilfs_checkpoint *
115 nilfs_cpfile_block_get_checkpoint(const struct inode *cpfile, __u64 cno,
116                                   struct buffer_head *bh,
117                                   void *kaddr)
118 {
119         return kaddr + bh_offset(bh) + nilfs_cpfile_get_offset(cpfile, cno) *
120                 NILFS_MDT(cpfile)->mi_entry_size;
121 }
122 
123 static void nilfs_cpfile_block_init(struct inode *cpfile,
124                                     struct buffer_head *bh,
125                                     void *kaddr)
126 {
127         struct nilfs_checkpoint *cp = kaddr + bh_offset(bh);
128         size_t cpsz = NILFS_MDT(cpfile)->mi_entry_size;
129         int n = nilfs_cpfile_checkpoints_per_block(cpfile);
130 
131         while (n-- > 0) {
132                 nilfs_checkpoint_set_invalid(cp);
133                 cp = (void *)cp + cpsz;
134         }
135 }
136 
137 static inline int nilfs_cpfile_get_header_block(struct inode *cpfile,
138                                                 struct buffer_head **bhp)
139 {
140         return nilfs_mdt_get_block(cpfile, 0, 0, NULL, bhp);
141 }
142 
143 static inline int nilfs_cpfile_get_checkpoint_block(struct inode *cpfile,
144                                                     __u64 cno,
145                                                     int create,
146                                                     struct buffer_head **bhp)
147 {
148         return nilfs_mdt_get_block(cpfile,
149                                    nilfs_cpfile_get_blkoff(cpfile, cno),
150                                    create, nilfs_cpfile_block_init, bhp);
151 }
152 
153 /**
154  * nilfs_cpfile_find_checkpoint_block - find and get a buffer on cpfile
155  * @cpfile: inode of cpfile
156  * @start_cno: start checkpoint number (inclusive)
157  * @end_cno: end checkpoint number (inclusive)
158  * @cnop: place to store the next checkpoint number
159  * @bhp: place to store a pointer to buffer_head struct
160  *
161  * Return Value: On success, it returns 0. On error, the following negative
162  * error code is returned.
163  *
164  * %-ENOMEM - Insufficient memory available.
165  *
166  * %-EIO - I/O error
167  *
168  * %-ENOENT - no block exists in the range.
169  */
170 static int nilfs_cpfile_find_checkpoint_block(struct inode *cpfile,
171                                               __u64 start_cno, __u64 end_cno,
172                                               __u64 *cnop,
173                                               struct buffer_head **bhp)
174 {
175         unsigned long start, end, blkoff;
176         int ret;
177 
178         if (unlikely(start_cno > end_cno))
179                 return -ENOENT;
180 
181         start = nilfs_cpfile_get_blkoff(cpfile, start_cno);
182         end = nilfs_cpfile_get_blkoff(cpfile, end_cno);
183 
184         ret = nilfs_mdt_find_block(cpfile, start, end, &blkoff, bhp);
185         if (!ret)
186                 *cnop = (blkoff == start) ? start_cno :
187                         nilfs_cpfile_first_checkpoint_in_block(cpfile, blkoff);
188         return ret;
189 }
190 
191 static inline int nilfs_cpfile_delete_checkpoint_block(struct inode *cpfile,
192                                                        __u64 cno)
193 {
194         return nilfs_mdt_delete_block(cpfile,
195                                       nilfs_cpfile_get_blkoff(cpfile, cno));
196 }
197 
198 /**
199  * nilfs_cpfile_get_checkpoint - get a checkpoint
200  * @cpfile: inode of checkpoint file
201  * @cno: checkpoint number
202  * @create: create flag
203  * @cpp: pointer to a checkpoint
204  * @bhp: pointer to a buffer head
205  *
206  * Description: nilfs_cpfile_get_checkpoint() acquires the checkpoint
207  * specified by @cno. A new checkpoint will be created if @cno is the current
208  * checkpoint number and @create is nonzero.
209  *
210  * Return Value: On success, 0 is returned, and the checkpoint and the
211  * buffer head of the buffer on which the checkpoint is located are stored in
212  * the place pointed by @cpp and @bhp, respectively. On error, one of the
213  * following negative error codes is returned.
214  *
215  * %-EIO - I/O error.
216  *
217  * %-ENOMEM - Insufficient amount of memory available.
218  *
219  * %-ENOENT - No such checkpoint.
220  *
221  * %-EINVAL - invalid checkpoint.
222  */
223 int nilfs_cpfile_get_checkpoint(struct inode *cpfile,
224                                 __u64 cno,
225                                 int create,
226                                 struct nilfs_checkpoint **cpp,
227                                 struct buffer_head **bhp)
228 {
229         struct buffer_head *header_bh, *cp_bh;
230         struct nilfs_cpfile_header *header;
231         struct nilfs_checkpoint *cp;
232         void *kaddr;
233         int ret;
234 
235         if (unlikely(cno < 1 || cno > nilfs_mdt_cno(cpfile) ||
236                      (cno < nilfs_mdt_cno(cpfile) && create)))
237                 return -EINVAL;
238 
239         down_write(&NILFS_MDT(cpfile)->mi_sem);
240 
241         ret = nilfs_cpfile_get_header_block(cpfile, &header_bh);
242         if (ret < 0)
243                 goto out_sem;
244         ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, create, &cp_bh);
245         if (ret < 0)
246                 goto out_header;
247         kaddr = kmap(cp_bh->b_page);
248         cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, cp_bh, kaddr);
249         if (nilfs_checkpoint_invalid(cp)) {
250                 if (!create) {
251                         kunmap(cp_bh->b_page);
252                         brelse(cp_bh);
253                         ret = -ENOENT;
254                         goto out_header;
255                 }
256                 /* a newly-created checkpoint */
257                 nilfs_checkpoint_clear_invalid(cp);
258                 if (!nilfs_cpfile_is_in_first(cpfile, cno))
259                         nilfs_cpfile_block_add_valid_checkpoints(cpfile, cp_bh,
260                                                                  kaddr, 1);
261                 mark_buffer_dirty(cp_bh);
262 
263                 kaddr = kmap_atomic(header_bh->b_page);
264                 header = nilfs_cpfile_block_get_header(cpfile, header_bh,
265                                                        kaddr);
266                 le64_add_cpu(&header->ch_ncheckpoints, 1);
267                 kunmap_atomic(kaddr);
268                 mark_buffer_dirty(header_bh);
269                 nilfs_mdt_mark_dirty(cpfile);
270         }
271 
272         if (cpp != NULL)
273                 *cpp = cp;
274         *bhp = cp_bh;
275 
276  out_header:
277         brelse(header_bh);
278 
279  out_sem:
280         up_write(&NILFS_MDT(cpfile)->mi_sem);
281         return ret;
282 }
283 
284 /**
285  * nilfs_cpfile_put_checkpoint - put a checkpoint
286  * @cpfile: inode of checkpoint file
287  * @cno: checkpoint number
288  * @bh: buffer head
289  *
290  * Description: nilfs_cpfile_put_checkpoint() releases the checkpoint
291  * specified by @cno. @bh must be the buffer head which has been returned by
292  * a previous call to nilfs_cpfile_get_checkpoint() with @cno.
293  */
294 void nilfs_cpfile_put_checkpoint(struct inode *cpfile, __u64 cno,
295                                  struct buffer_head *bh)
296 {
297         kunmap(bh->b_page);
298         brelse(bh);
299 }
300 
301 /**
302  * nilfs_cpfile_delete_checkpoints - delete checkpoints
303  * @cpfile: inode of checkpoint file
304  * @start: start checkpoint number
305  * @end: end checkpoint numer
306  *
307  * Description: nilfs_cpfile_delete_checkpoints() deletes the checkpoints in
308  * the period from @start to @end, excluding @end itself. The checkpoints
309  * which have been already deleted are ignored.
310  *
311  * Return Value: On success, 0 is returned. On error, one of the following
312  * negative error codes is returned.
313  *
314  * %-EIO - I/O error.
315  *
316  * %-ENOMEM - Insufficient amount of memory available.
317  *
318  * %-EINVAL - invalid checkpoints.
319  */
320 int nilfs_cpfile_delete_checkpoints(struct inode *cpfile,
321                                     __u64 start,
322                                     __u64 end)
323 {
324         struct buffer_head *header_bh, *cp_bh;
325         struct nilfs_cpfile_header *header;
326         struct nilfs_checkpoint *cp;
327         size_t cpsz = NILFS_MDT(cpfile)->mi_entry_size;
328         __u64 cno;
329         void *kaddr;
330         unsigned long tnicps;
331         int ret, ncps, nicps, nss, count, i;
332 
333         if (unlikely(start == 0 || start > end)) {
334                 nilfs_msg(cpfile->i_sb, KERN_ERR,
335                           "cannot delete checkpoints: invalid range [%llu, %llu)",
336                           (unsigned long long)start, (unsigned long long)end);
337                 return -EINVAL;
338         }
339 
340         down_write(&NILFS_MDT(cpfile)->mi_sem);
341 
342         ret = nilfs_cpfile_get_header_block(cpfile, &header_bh);
343         if (ret < 0)
344                 goto out_sem;
345         tnicps = 0;
346         nss = 0;
347 
348         for (cno = start; cno < end; cno += ncps) {
349                 ncps = nilfs_cpfile_checkpoints_in_block(cpfile, cno, end);
350                 ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &cp_bh);
351                 if (ret < 0) {
352                         if (ret != -ENOENT)
353                                 break;
354                         /* skip hole */
355                         ret = 0;
356                         continue;
357                 }
358 
359                 kaddr = kmap_atomic(cp_bh->b_page);
360                 cp = nilfs_cpfile_block_get_checkpoint(
361                         cpfile, cno, cp_bh, kaddr);
362                 nicps = 0;
363                 for (i = 0; i < ncps; i++, cp = (void *)cp + cpsz) {
364                         if (nilfs_checkpoint_snapshot(cp)) {
365                                 nss++;
366                         } else if (!nilfs_checkpoint_invalid(cp)) {
367                                 nilfs_checkpoint_set_invalid(cp);
368                                 nicps++;
369                         }
370                 }
371                 if (nicps > 0) {
372                         tnicps += nicps;
373                         mark_buffer_dirty(cp_bh);
374                         nilfs_mdt_mark_dirty(cpfile);
375                         if (!nilfs_cpfile_is_in_first(cpfile, cno)) {
376                                 count =
377                                   nilfs_cpfile_block_sub_valid_checkpoints(
378                                                 cpfile, cp_bh, kaddr, nicps);
379                                 if (count == 0) {
380                                         /* make hole */
381                                         kunmap_atomic(kaddr);
382                                         brelse(cp_bh);
383                                         ret =
384                                           nilfs_cpfile_delete_checkpoint_block(
385                                                                    cpfile, cno);
386                                         if (ret == 0)
387                                                 continue;
388                                         nilfs_msg(cpfile->i_sb, KERN_ERR,
389                                                   "error %d deleting checkpoint block",
390                                                   ret);
391                                         break;
392                                 }
393                         }
394                 }
395 
396                 kunmap_atomic(kaddr);
397                 brelse(cp_bh);
398         }
399 
400         if (tnicps > 0) {
401                 kaddr = kmap_atomic(header_bh->b_page);
402                 header = nilfs_cpfile_block_get_header(cpfile, header_bh,
403                                                        kaddr);
404                 le64_add_cpu(&header->ch_ncheckpoints, -(u64)tnicps);
405                 mark_buffer_dirty(header_bh);
406                 nilfs_mdt_mark_dirty(cpfile);
407                 kunmap_atomic(kaddr);
408         }
409 
410         brelse(header_bh);
411         if (nss > 0)
412                 ret = -EBUSY;
413 
414  out_sem:
415         up_write(&NILFS_MDT(cpfile)->mi_sem);
416         return ret;
417 }
418 
419 static void nilfs_cpfile_checkpoint_to_cpinfo(struct inode *cpfile,
420                                               struct nilfs_checkpoint *cp,
421                                               struct nilfs_cpinfo *ci)
422 {
423         ci->ci_flags = le32_to_cpu(cp->cp_flags);
424         ci->ci_cno = le64_to_cpu(cp->cp_cno);
425         ci->ci_create = le64_to_cpu(cp->cp_create);
426         ci->ci_nblk_inc = le64_to_cpu(cp->cp_nblk_inc);
427         ci->ci_inodes_count = le64_to_cpu(cp->cp_inodes_count);
428         ci->ci_blocks_count = le64_to_cpu(cp->cp_blocks_count);
429         ci->ci_next = le64_to_cpu(cp->cp_snapshot_list.ssl_next);
430 }
431 
432 static ssize_t nilfs_cpfile_do_get_cpinfo(struct inode *cpfile, __u64 *cnop,
433                                           void *buf, unsigned int cisz,
434                                           size_t nci)
435 {
436         struct nilfs_checkpoint *cp;
437         struct nilfs_cpinfo *ci = buf;
438         struct buffer_head *bh;
439         size_t cpsz = NILFS_MDT(cpfile)->mi_entry_size;
440         __u64 cur_cno = nilfs_mdt_cno(cpfile), cno = *cnop;
441         void *kaddr;
442         int n, ret;
443         int ncps, i;
444 
445         if (cno == 0)
446                 return -ENOENT; /* checkpoint number 0 is invalid */
447         down_read(&NILFS_MDT(cpfile)->mi_sem);
448 
449         for (n = 0; n < nci; cno += ncps) {
450                 ret = nilfs_cpfile_find_checkpoint_block(
451                         cpfile, cno, cur_cno - 1, &cno, &bh);
452                 if (ret < 0) {
453                         if (likely(ret == -ENOENT))
454                                 break;
455                         goto out;
456                 }
457                 ncps = nilfs_cpfile_checkpoints_in_block(cpfile, cno, cur_cno);
458 
459                 kaddr = kmap_atomic(bh->b_page);
460                 cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, bh, kaddr);
461                 for (i = 0; i < ncps && n < nci; i++, cp = (void *)cp + cpsz) {
462                         if (!nilfs_checkpoint_invalid(cp)) {
463                                 nilfs_cpfile_checkpoint_to_cpinfo(cpfile, cp,
464                                                                   ci);
465                                 ci = (void *)ci + cisz;
466                                 n++;
467                         }
468                 }
469                 kunmap_atomic(kaddr);
470                 brelse(bh);
471         }
472 
473         ret = n;
474         if (n > 0) {
475                 ci = (void *)ci - cisz;
476                 *cnop = ci->ci_cno + 1;
477         }
478 
479  out:
480         up_read(&NILFS_MDT(cpfile)->mi_sem);
481         return ret;
482 }
483 
484 static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode *cpfile, __u64 *cnop,
485                                           void *buf, unsigned int cisz,
486                                           size_t nci)
487 {
488         struct buffer_head *bh;
489         struct nilfs_cpfile_header *header;
490         struct nilfs_checkpoint *cp;
491         struct nilfs_cpinfo *ci = buf;
492         __u64 curr = *cnop, next;
493         unsigned long curr_blkoff, next_blkoff;
494         void *kaddr;
495         int n = 0, ret;
496 
497         down_read(&NILFS_MDT(cpfile)->mi_sem);
498 
499         if (curr == 0) {
500                 ret = nilfs_cpfile_get_header_block(cpfile, &bh);
501                 if (ret < 0)
502                         goto out;
503                 kaddr = kmap_atomic(bh->b_page);
504                 header = nilfs_cpfile_block_get_header(cpfile, bh, kaddr);
505                 curr = le64_to_cpu(header->ch_snapshot_list.ssl_next);
506                 kunmap_atomic(kaddr);
507                 brelse(bh);
508                 if (curr == 0) {
509                         ret = 0;
510                         goto out;
511                 }
512         } else if (unlikely(curr == ~(__u64)0)) {
513                 ret = 0;
514                 goto out;
515         }
516 
517         curr_blkoff = nilfs_cpfile_get_blkoff(cpfile, curr);
518         ret = nilfs_cpfile_get_checkpoint_block(cpfile, curr, 0, &bh);
519         if (unlikely(ret < 0)) {
520                 if (ret == -ENOENT)
521                         ret = 0; /* No snapshots (started from a hole block) */
522                 goto out;
523         }
524         kaddr = kmap_atomic(bh->b_page);
525         while (n < nci) {
526                 cp = nilfs_cpfile_block_get_checkpoint(cpfile, curr, bh, kaddr);
527                 curr = ~(__u64)0; /* Terminator */
528                 if (unlikely(nilfs_checkpoint_invalid(cp) ||
529                              !nilfs_checkpoint_snapshot(cp)))
530                         break;
531                 nilfs_cpfile_checkpoint_to_cpinfo(cpfile, cp, ci);
532                 ci = (void *)ci + cisz;
533                 n++;
534                 next = le64_to_cpu(cp->cp_snapshot_list.ssl_next);
535                 if (next == 0)
536                         break; /* reach end of the snapshot list */
537 
538                 next_blkoff = nilfs_cpfile_get_blkoff(cpfile, next);
539                 if (curr_blkoff != next_blkoff) {
540                         kunmap_atomic(kaddr);
541                         brelse(bh);
542                         ret = nilfs_cpfile_get_checkpoint_block(cpfile, next,
543                                                                 0, &bh);
544                         if (unlikely(ret < 0)) {
545                                 WARN_ON(ret == -ENOENT);
546                                 goto out;
547                         }
548                         kaddr = kmap_atomic(bh->b_page);
549                 }
550                 curr = next;
551                 curr_blkoff = next_blkoff;
552         }
553         kunmap_atomic(kaddr);
554         brelse(bh);
555         *cnop = curr;
556         ret = n;
557 
558  out:
559         up_read(&NILFS_MDT(cpfile)->mi_sem);
560         return ret;
561 }
562 
563 /**
564  * nilfs_cpfile_get_cpinfo -
565  * @cpfile:
566  * @cno:
567  * @ci:
568  * @nci:
569  */
570 
571 ssize_t nilfs_cpfile_get_cpinfo(struct inode *cpfile, __u64 *cnop, int mode,
572                                 void *buf, unsigned int cisz, size_t nci)
573 {
574         switch (mode) {
575         case NILFS_CHECKPOINT:
576                 return nilfs_cpfile_do_get_cpinfo(cpfile, cnop, buf, cisz, nci);
577         case NILFS_SNAPSHOT:
578                 return nilfs_cpfile_do_get_ssinfo(cpfile, cnop, buf, cisz, nci);
579         default:
580                 return -EINVAL;
581         }
582 }
583 
584 /**
585  * nilfs_cpfile_delete_checkpoint -
586  * @cpfile:
587  * @cno:
588  */
589 int nilfs_cpfile_delete_checkpoint(struct inode *cpfile, __u64 cno)
590 {
591         struct nilfs_cpinfo ci;
592         __u64 tcno = cno;
593         ssize_t nci;
594 
595         nci = nilfs_cpfile_do_get_cpinfo(cpfile, &tcno, &ci, sizeof(ci), 1);
596         if (nci < 0)
597                 return nci;
598         else if (nci == 0 || ci.ci_cno != cno)
599                 return -ENOENT;
600         else if (nilfs_cpinfo_snapshot(&ci))
601                 return -EBUSY;
602 
603         return nilfs_cpfile_delete_checkpoints(cpfile, cno, cno + 1);
604 }
605 
606 static struct nilfs_snapshot_list *
607 nilfs_cpfile_block_get_snapshot_list(const struct inode *cpfile,
608                                      __u64 cno,
609                                      struct buffer_head *bh,
610                                      void *kaddr)
611 {
612         struct nilfs_cpfile_header *header;
613         struct nilfs_checkpoint *cp;
614         struct nilfs_snapshot_list *list;
615 
616         if (cno != 0) {
617                 cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, bh, kaddr);
618                 list = &cp->cp_snapshot_list;
619         } else {
620                 header = nilfs_cpfile_block_get_header(cpfile, bh, kaddr);
621                 list = &header->ch_snapshot_list;
622         }
623         return list;
624 }
625 
626 static int nilfs_cpfile_set_snapshot(struct inode *cpfile, __u64 cno)
627 {
628         struct buffer_head *header_bh, *curr_bh, *prev_bh, *cp_bh;
629         struct nilfs_cpfile_header *header;
630         struct nilfs_checkpoint *cp;
631         struct nilfs_snapshot_list *list;
632         __u64 curr, prev;
633         unsigned long curr_blkoff, prev_blkoff;
634         void *kaddr;
635         int ret;
636 
637         if (cno == 0)
638                 return -ENOENT; /* checkpoint number 0 is invalid */
639         down_write(&NILFS_MDT(cpfile)->mi_sem);
640 
641         ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &cp_bh);
642         if (ret < 0)
643                 goto out_sem;
644         kaddr = kmap_atomic(cp_bh->b_page);
645         cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, cp_bh, kaddr);
646         if (nilfs_checkpoint_invalid(cp)) {
647                 ret = -ENOENT;
648                 kunmap_atomic(kaddr);
649                 goto out_cp;
650         }
651         if (nilfs_checkpoint_snapshot(cp)) {
652                 ret = 0;
653                 kunmap_atomic(kaddr);
654                 goto out_cp;
655         }
656         kunmap_atomic(kaddr);
657 
658         ret = nilfs_cpfile_get_header_block(cpfile, &header_bh);
659         if (ret < 0)
660                 goto out_cp;
661         kaddr = kmap_atomic(header_bh->b_page);
662         header = nilfs_cpfile_block_get_header(cpfile, header_bh, kaddr);
663         list = &header->ch_snapshot_list;
664         curr_bh = header_bh;
665         get_bh(curr_bh);
666         curr = 0;
667         curr_blkoff = 0;
668         prev = le64_to_cpu(list->ssl_prev);
669         while (prev > cno) {
670                 prev_blkoff = nilfs_cpfile_get_blkoff(cpfile, prev);
671                 curr = prev;
672                 if (curr_blkoff != prev_blkoff) {
673                         kunmap_atomic(kaddr);
674                         brelse(curr_bh);
675                         ret = nilfs_cpfile_get_checkpoint_block(cpfile, curr,
676                                                                 0, &curr_bh);
677                         if (ret < 0)
678                                 goto out_header;
679                         kaddr = kmap_atomic(curr_bh->b_page);
680                 }
681                 curr_blkoff = prev_blkoff;
682                 cp = nilfs_cpfile_block_get_checkpoint(
683                         cpfile, curr, curr_bh, kaddr);
684                 list = &cp->cp_snapshot_list;
685                 prev = le64_to_cpu(list->ssl_prev);
686         }
687         kunmap_atomic(kaddr);
688 
689         if (prev != 0) {
690                 ret = nilfs_cpfile_get_checkpoint_block(cpfile, prev, 0,
691                                                         &prev_bh);
692                 if (ret < 0)
693                         goto out_curr;
694         } else {
695                 prev_bh = header_bh;
696                 get_bh(prev_bh);
697         }
698 
699         kaddr = kmap_atomic(curr_bh->b_page);
700         list = nilfs_cpfile_block_get_snapshot_list(
701                 cpfile, curr, curr_bh, kaddr);
702         list->ssl_prev = cpu_to_le64(cno);
703         kunmap_atomic(kaddr);
704 
705         kaddr = kmap_atomic(cp_bh->b_page);
706         cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, cp_bh, kaddr);
707         cp->cp_snapshot_list.ssl_next = cpu_to_le64(curr);
708         cp->cp_snapshot_list.ssl_prev = cpu_to_le64(prev);
709         nilfs_checkpoint_set_snapshot(cp);
710         kunmap_atomic(kaddr);
711 
712         kaddr = kmap_atomic(prev_bh->b_page);
713         list = nilfs_cpfile_block_get_snapshot_list(
714                 cpfile, prev, prev_bh, kaddr);
715         list->ssl_next = cpu_to_le64(cno);
716         kunmap_atomic(kaddr);
717 
718         kaddr = kmap_atomic(header_bh->b_page);
719         header = nilfs_cpfile_block_get_header(cpfile, header_bh, kaddr);
720         le64_add_cpu(&header->ch_nsnapshots, 1);
721         kunmap_atomic(kaddr);
722 
723         mark_buffer_dirty(prev_bh);
724         mark_buffer_dirty(curr_bh);
725         mark_buffer_dirty(cp_bh);
726         mark_buffer_dirty(header_bh);
727         nilfs_mdt_mark_dirty(cpfile);
728 
729         brelse(prev_bh);
730 
731  out_curr:
732         brelse(curr_bh);
733 
734  out_header:
735         brelse(header_bh);
736 
737  out_cp:
738         brelse(cp_bh);
739 
740  out_sem:
741         up_write(&NILFS_MDT(cpfile)->mi_sem);
742         return ret;
743 }
744 
745 static int nilfs_cpfile_clear_snapshot(struct inode *cpfile, __u64 cno)
746 {
747         struct buffer_head *header_bh, *next_bh, *prev_bh, *cp_bh;
748         struct nilfs_cpfile_header *header;
749         struct nilfs_checkpoint *cp;
750         struct nilfs_snapshot_list *list;
751         __u64 next, prev;
752         void *kaddr;
753         int ret;
754 
755         if (cno == 0)
756                 return -ENOENT; /* checkpoint number 0 is invalid */
757         down_write(&NILFS_MDT(cpfile)->mi_sem);
758 
759         ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &cp_bh);
760         if (ret < 0)
761                 goto out_sem;
762         kaddr = kmap_atomic(cp_bh->b_page);
763         cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, cp_bh, kaddr);
764         if (nilfs_checkpoint_invalid(cp)) {
765                 ret = -ENOENT;
766                 kunmap_atomic(kaddr);
767                 goto out_cp;
768         }
769         if (!nilfs_checkpoint_snapshot(cp)) {
770                 ret = 0;
771                 kunmap_atomic(kaddr);
772                 goto out_cp;
773         }
774 
775         list = &cp->cp_snapshot_list;
776         next = le64_to_cpu(list->ssl_next);
777         prev = le64_to_cpu(list->ssl_prev);
778         kunmap_atomic(kaddr);
779 
780         ret = nilfs_cpfile_get_header_block(cpfile, &header_bh);
781         if (ret < 0)
782                 goto out_cp;
783         if (next != 0) {
784                 ret = nilfs_cpfile_get_checkpoint_block(cpfile, next, 0,
785                                                         &next_bh);
786                 if (ret < 0)
787                         goto out_header;
788         } else {
789                 next_bh = header_bh;
790                 get_bh(next_bh);
791         }
792         if (prev != 0) {
793                 ret = nilfs_cpfile_get_checkpoint_block(cpfile, prev, 0,
794                                                         &prev_bh);
795                 if (ret < 0)
796                         goto out_next;
797         } else {
798                 prev_bh = header_bh;
799                 get_bh(prev_bh);
800         }
801 
802         kaddr = kmap_atomic(next_bh->b_page);
803         list = nilfs_cpfile_block_get_snapshot_list(
804                 cpfile, next, next_bh, kaddr);
805         list->ssl_prev = cpu_to_le64(prev);
806         kunmap_atomic(kaddr);
807 
808         kaddr = kmap_atomic(prev_bh->b_page);
809         list = nilfs_cpfile_block_get_snapshot_list(
810                 cpfile, prev, prev_bh, kaddr);
811         list->ssl_next = cpu_to_le64(next);
812         kunmap_atomic(kaddr);
813 
814         kaddr = kmap_atomic(cp_bh->b_page);
815         cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, cp_bh, kaddr);
816         cp->cp_snapshot_list.ssl_next = cpu_to_le64(0);
817         cp->cp_snapshot_list.ssl_prev = cpu_to_le64(0);
818         nilfs_checkpoint_clear_snapshot(cp);
819         kunmap_atomic(kaddr);
820 
821         kaddr = kmap_atomic(header_bh->b_page);
822         header = nilfs_cpfile_block_get_header(cpfile, header_bh, kaddr);
823         le64_add_cpu(&header->ch_nsnapshots, -1);
824         kunmap_atomic(kaddr);
825 
826         mark_buffer_dirty(next_bh);
827         mark_buffer_dirty(prev_bh);
828         mark_buffer_dirty(cp_bh);
829         mark_buffer_dirty(header_bh);
830         nilfs_mdt_mark_dirty(cpfile);
831 
832         brelse(prev_bh);
833 
834  out_next:
835         brelse(next_bh);
836 
837  out_header:
838         brelse(header_bh);
839 
840  out_cp:
841         brelse(cp_bh);
842 
843  out_sem:
844         up_write(&NILFS_MDT(cpfile)->mi_sem);
845         return ret;
846 }
847 
848 /**
849  * nilfs_cpfile_is_snapshot -
850  * @cpfile: inode of checkpoint file
851  * @cno: checkpoint number
852  *
853  * Description:
854  *
855  * Return Value: On success, 1 is returned if the checkpoint specified by
856  * @cno is a snapshot, or 0 if not. On error, one of the following negative
857  * error codes is returned.
858  *
859  * %-EIO - I/O error.
860  *
861  * %-ENOMEM - Insufficient amount of memory available.
862  *
863  * %-ENOENT - No such checkpoint.
864  */
865 int nilfs_cpfile_is_snapshot(struct inode *cpfile, __u64 cno)
866 {
867         struct buffer_head *bh;
868         struct nilfs_checkpoint *cp;
869         void *kaddr;
870         int ret;
871 
872         /*
873          * CP number is invalid if it's zero or larger than the
874          * largest existing one.
875          */
876         if (cno == 0 || cno >= nilfs_mdt_cno(cpfile))
877                 return -ENOENT;
878         down_read(&NILFS_MDT(cpfile)->mi_sem);
879 
880         ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &bh);
881         if (ret < 0)
882                 goto out;
883         kaddr = kmap_atomic(bh->b_page);
884         cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, bh, kaddr);
885         if (nilfs_checkpoint_invalid(cp))
886                 ret = -ENOENT;
887         else
888                 ret = nilfs_checkpoint_snapshot(cp);
889         kunmap_atomic(kaddr);
890         brelse(bh);
891 
892  out:
893         up_read(&NILFS_MDT(cpfile)->mi_sem);
894         return ret;
895 }
896 
897 /**
898  * nilfs_cpfile_change_cpmode - change checkpoint mode
899  * @cpfile: inode of checkpoint file
900  * @cno: checkpoint number
901  * @status: mode of checkpoint
902  *
903  * Description: nilfs_change_cpmode() changes the mode of the checkpoint
904  * specified by @cno. The mode @mode is NILFS_CHECKPOINT or NILFS_SNAPSHOT.
905  *
906  * Return Value: On success, 0 is returned. On error, one of the following
907  * negative error codes is returned.
908  *
909  * %-EIO - I/O error.
910  *
911  * %-ENOMEM - Insufficient amount of memory available.
912  *
913  * %-ENOENT - No such checkpoint.
914  */
915 int nilfs_cpfile_change_cpmode(struct inode *cpfile, __u64 cno, int mode)
916 {
917         int ret;
918 
919         switch (mode) {
920         case NILFS_CHECKPOINT:
921                 if (nilfs_checkpoint_is_mounted(cpfile->i_sb, cno))
922                         /*
923                          * Current implementation does not have to protect
924                          * plain read-only mounts since they are exclusive
925                          * with a read/write mount and are protected from the
926                          * cleaner.
927                          */
928                         ret = -EBUSY;
929                 else
930                         ret = nilfs_cpfile_clear_snapshot(cpfile, cno);
931                 return ret;
932         case NILFS_SNAPSHOT:
933                 return nilfs_cpfile_set_snapshot(cpfile, cno);
934         default:
935                 return -EINVAL;
936         }
937 }
938 
939 /**
940  * nilfs_cpfile_get_stat - get checkpoint statistics
941  * @cpfile: inode of checkpoint file
942  * @stat: pointer to a structure of checkpoint statistics
943  *
944  * Description: nilfs_cpfile_get_stat() returns information about checkpoints.
945  *
946  * Return Value: On success, 0 is returned, and checkpoints information is
947  * stored in the place pointed by @stat. On error, one of the following
948  * negative error codes is returned.
949  *
950  * %-EIO - I/O error.
951  *
952  * %-ENOMEM - Insufficient amount of memory available.
953  */
954 int nilfs_cpfile_get_stat(struct inode *cpfile, struct nilfs_cpstat *cpstat)
955 {
956         struct buffer_head *bh;
957         struct nilfs_cpfile_header *header;
958         void *kaddr;
959         int ret;
960 
961         down_read(&NILFS_MDT(cpfile)->mi_sem);
962 
963         ret = nilfs_cpfile_get_header_block(cpfile, &bh);
964         if (ret < 0)
965                 goto out_sem;
966         kaddr = kmap_atomic(bh->b_page);
967         header = nilfs_cpfile_block_get_header(cpfile, bh, kaddr);
968         cpstat->cs_cno = nilfs_mdt_cno(cpfile);
969         cpstat->cs_ncps = le64_to_cpu(header->ch_ncheckpoints);
970         cpstat->cs_nsss = le64_to_cpu(header->ch_nsnapshots);
971         kunmap_atomic(kaddr);
972         brelse(bh);
973 
974  out_sem:
975         up_read(&NILFS_MDT(cpfile)->mi_sem);
976         return ret;
977 }
978 
979 /**
980  * nilfs_cpfile_read - read or get cpfile inode
981  * @sb: super block instance
982  * @cpsize: size of a checkpoint entry
983  * @raw_inode: on-disk cpfile inode
984  * @inodep: buffer to store the inode
985  */
986 int nilfs_cpfile_read(struct super_block *sb, size_t cpsize,
987                       struct nilfs_inode *raw_inode, struct inode **inodep)
988 {
989         struct inode *cpfile;
990         int err;
991 
992         if (cpsize > sb->s_blocksize) {
993                 nilfs_msg(sb, KERN_ERR,
994                           "too large checkpoint size: %zu bytes", cpsize);
995                 return -EINVAL;
996         } else if (cpsize < NILFS_MIN_CHECKPOINT_SIZE) {
997                 nilfs_msg(sb, KERN_ERR,
998                           "too small checkpoint size: %zu bytes", cpsize);
999                 return -EINVAL;
1000         }
1001 
1002         cpfile = nilfs_iget_locked(sb, NULL, NILFS_CPFILE_INO);
1003         if (unlikely(!cpfile))
1004                 return -ENOMEM;
1005         if (!(cpfile->i_state & I_NEW))
1006                 goto out;
1007 
1008         err = nilfs_mdt_init(cpfile, NILFS_MDT_GFP, 0);
1009         if (err)
1010                 goto failed;
1011 
1012         nilfs_mdt_set_entry_size(cpfile, cpsize,
1013                                  sizeof(struct nilfs_cpfile_header));
1014 
1015         err = nilfs_read_inode_common(cpfile, raw_inode);
1016         if (err)
1017                 goto failed;
1018 
1019         unlock_new_inode(cpfile);
1020  out:
1021         *inodep = cpfile;
1022         return 0;
1023  failed:
1024         iget_failed(cpfile);
1025         return err;
1026 }
1027 

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