1 /*-
2 * Copyright (c) 2010-2012 Semihalf.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/conf.h>
33 #include <sys/kernel.h>
34 #include <sys/lock.h>
35 #include <sys/malloc.h>
36 #include <sys/mount.h>
37 #include <sys/mutex.h>
38 #include <sys/namei.h>
39 #include <sys/sysctl.h>
40 #include <sys/vnode.h>
41 #include <sys/buf.h>
42 #include <sys/bio.h>
43
44 #include <vm/vm.h>
45 #include <vm/vm_param.h>
46 #include <vm/vm_kern.h>
47 #include <vm/vm_page.h>
48
49 #include "nandfs_mount.h"
50 #include "nandfs.h"
51 #include "nandfs_subr.h"
52
53
54 static int
55 nandfs_checkpoint_size(struct nandfs_device *fsdev)
56 {
57
58 return (fsdev->nd_fsdata.f_checkpoint_size);
59 }
60
61 static int
62 nandfs_checkpoint_blk_offset(struct nandfs_device *fsdev, uint64_t cn,
63 uint64_t *blk, uint64_t *offset)
64 {
65 uint64_t off;
66 uint16_t cp_size, cp_per_blk;
67
68 KASSERT((cn), ("checkpoing cannot be zero"));
69
70 cp_size = fsdev->nd_fsdata.f_checkpoint_size;
71 cp_per_blk = fsdev->nd_blocksize / cp_size;
72 off = roundup(sizeof(struct nandfs_cpfile_header), cp_size) / cp_size;
73 off += (cn - 1);
74
75 *blk = off / cp_per_blk;
76 *offset = (off % cp_per_blk) * cp_size;
77
78 return (0);
79 }
80
81 static int
82 nandfs_checkpoint_blk_remaining(struct nandfs_device *fsdev, uint64_t cn,
83 uint64_t blk, uint64_t offset)
84 {
85 uint16_t cp_size, cp_remaining;
86
87 cp_size = fsdev->nd_fsdata.f_checkpoint_size;
88 cp_remaining = (fsdev->nd_blocksize - offset) / cp_size;
89
90 return (cp_remaining);
91 }
92
93 int
94 nandfs_get_checkpoint(struct nandfs_device *fsdev, struct nandfs_node *cp_node,
95 uint64_t cn)
96 {
97 struct buf *bp;
98 uint64_t blk, offset;
99 int error;
100
101 if (cn != fsdev->nd_last_cno && cn != (fsdev->nd_last_cno + 1)) {
102 return (-1);
103 }
104
105 error = nandfs_bread(cp_node, 0, NOCRED, 0, &bp);
106 if (error) {
107 brelse(bp);
108 return (-1);
109 }
110
111 error = nandfs_dirty_buf(bp, 0);
112 if (error)
113 return (-1);
114
115
116 nandfs_checkpoint_blk_offset(fsdev, cn, &blk, &offset);
117
118 if (blk != 0) {
119 if (blk < cp_node->nn_inode.i_blocks)
120 error = nandfs_bread(cp_node, blk, NOCRED, 0, &bp);
121 else
122 error = nandfs_bcreate(cp_node, blk, NOCRED, 0, &bp);
123 if (error) {
124 if (bp)
125 brelse(bp);
126 return (-1);
127 }
128
129 nandfs_dirty_buf(bp, 1);
130 }
131
132 DPRINTF(CPFILE, ("%s: cn:%#jx entry block:%#jx offset:%#jx\n",
133 __func__, (uintmax_t)cn, (uintmax_t)blk, (uintmax_t)offset));
134
135 return (0);
136 }
137
138 int
139 nandfs_set_checkpoint(struct nandfs_device *fsdev, struct nandfs_node *cp_node,
140 uint64_t cn, struct nandfs_inode *ifile_inode, uint64_t nblocks)
141 {
142 struct nandfs_cpfile_header *cnh;
143 struct nandfs_checkpoint *cnp;
144 struct buf *bp;
145 uint64_t blk, offset;
146 int error;
147
148 if (cn != fsdev->nd_last_cno && cn != (fsdev->nd_last_cno + 1)) {
149 nandfs_error("%s: trying to set invalid chekpoint %jx - %jx\n",
150 __func__, cn, fsdev->nd_last_cno);
151 return (-1);
152 }
153
154 error = nandfs_bread(cp_node, 0, NOCRED, 0, &bp);
155 if (error) {
156 brelse(bp);
157 return error;
158 }
159
160 cnh = (struct nandfs_cpfile_header *) bp->b_data;
161 cnh->ch_ncheckpoints++;
162
163 nandfs_checkpoint_blk_offset(fsdev, cn, &blk, &offset);
164
165 if(blk != 0) {
166 brelse(bp);
167 error = nandfs_bread(cp_node, blk, NOCRED, 0, &bp);
168 if (error) {
169 brelse(bp);
170 return error;
171 }
172 }
173
174 cnp = (struct nandfs_checkpoint *)((uint8_t *)bp->b_data + offset);
175 cnp->cp_flags = 0;
176 cnp->cp_checkpoints_count = 1;
177 memset(&cnp->cp_snapshot_list, 0, sizeof(struct nandfs_snapshot_list));
178 cnp->cp_cno = cn;
179 cnp->cp_create = fsdev->nd_ts.tv_sec;
180 cnp->cp_nblk_inc = nblocks;
181 cnp->cp_blocks_count = 0;
182 memcpy (&cnp->cp_ifile_inode, ifile_inode, sizeof(cnp->cp_ifile_inode));
183
184 DPRINTF(CPFILE, ("%s: cn:%#jx ctime:%#jx nblk:%#jx\n",
185 __func__, (uintmax_t)cn, (uintmax_t)cnp->cp_create,
186 (uintmax_t)nblocks));
187
188 brelse(bp);
189 return (0);
190 }
191
192 static int
193 nandfs_cp_mounted(struct nandfs_device *nandfsdev, uint64_t cno)
194 {
195 struct nandfsmount *nmp;
196 int mounted = 0;
197
198 mtx_lock(&nandfsdev->nd_mutex);
199 /* No double-mounting of the same checkpoint */
200 STAILQ_FOREACH(nmp, &nandfsdev->nd_mounts, nm_next_mount) {
201 if (nmp->nm_mount_args.cpno == cno) {
202 mounted = 1;
203 break;
204 }
205 }
206 mtx_unlock(&nandfsdev->nd_mutex);
207
208 return (mounted);
209 }
210
211 static int
212 nandfs_cp_set_snapshot(struct nandfs_node *cp_node, uint64_t cno)
213 {
214 struct nandfs_device *fsdev;
215 struct nandfs_cpfile_header *cnh;
216 struct nandfs_checkpoint *cnp;
217 struct nandfs_snapshot_list *list;
218 struct buf *bp;
219 uint64_t blk, prev_blk, offset;
220 uint64_t curr, prev;
221 int error;
222
223 fsdev = cp_node->nn_nandfsdev;
224
225 /* Get snapshot data */
226 nandfs_checkpoint_blk_offset(fsdev, cno, &blk, &offset);
227 error = nandfs_bread(cp_node, blk, NOCRED, 0, &bp);
228 if (error) {
229 brelse(bp);
230 return (error);
231 }
232 cnp = (struct nandfs_checkpoint *)(bp->b_data + offset);
233 if (cnp->cp_flags & NANDFS_CHECKPOINT_INVALID) {
234 brelse(bp);
235 return (ENOENT);
236 }
237 if ((cnp->cp_flags & NANDFS_CHECKPOINT_SNAPSHOT)) {
238 brelse(bp);
239 return (EINVAL);
240 }
241
242 brelse(bp);
243 /* Get list from header */
244 error = nandfs_bread(cp_node, 0, NOCRED, 0, &bp);
245 if (error) {
246 brelse(bp);
247 return (error);
248 }
249
250 cnh = (struct nandfs_cpfile_header *) bp->b_data;
251 list = &cnh->ch_snapshot_list;
252 prev = list->ssl_prev;
253 brelse(bp);
254 prev_blk = ~(0);
255 curr = 0;
256 while (prev > cno) {
257 curr = prev;
258 nandfs_checkpoint_blk_offset(fsdev, prev, &prev_blk, &offset);
259 error = nandfs_bread(cp_node, prev_blk, NOCRED, 0, &bp);
260 if (error) {
261 brelse(bp);
262 return (error);
263 }
264 cnp = (struct nandfs_checkpoint *)(bp->b_data + offset);
265 list = &cnp->cp_snapshot_list;
266 prev = list->ssl_prev;
267 brelse(bp);
268 }
269
270 if (curr == 0) {
271 nandfs_bread(cp_node, 0, NOCRED, 0, &bp);
272 cnh = (struct nandfs_cpfile_header *) bp->b_data;
273 list = &cnh->ch_snapshot_list;
274 } else {
275 nandfs_checkpoint_blk_offset(fsdev, curr, &blk, &offset);
276 error = nandfs_bread(cp_node, blk, NOCRED, 0, &bp);
277 if (error) {
278 brelse(bp);
279 return (error);
280 }
281 cnp = (struct nandfs_checkpoint *)(bp->b_data + offset);
282 list = &cnp->cp_snapshot_list;
283 }
284
285 list->ssl_prev = cno;
286 error = nandfs_dirty_buf(bp, 0);
287 if (error)
288 return (error);
289
290
291 /* Update snapshot for cno */
292 nandfs_checkpoint_blk_offset(fsdev, cno, &blk, &offset);
293 error = nandfs_bread(cp_node, blk, NOCRED, 0, &bp);
294 if (error) {
295 brelse(bp);
296 return (error);
297 }
298 cnp = (struct nandfs_checkpoint *)(bp->b_data + offset);
299 list = &cnp->cp_snapshot_list;
300 list->ssl_prev = prev;
301 list->ssl_next = curr;
302 cnp->cp_flags |= NANDFS_CHECKPOINT_SNAPSHOT;
303 nandfs_dirty_buf(bp, 1);
304
305 if (prev == 0) {
306 nandfs_bread(cp_node, 0, NOCRED, 0, &bp);
307 cnh = (struct nandfs_cpfile_header *) bp->b_data;
308 list = &cnh->ch_snapshot_list;
309 } else {
310 /* Update snapshot list for prev */
311 nandfs_checkpoint_blk_offset(fsdev, prev, &blk, &offset);
312 error = nandfs_bread(cp_node, blk, NOCRED, 0, &bp);
313 if (error) {
314 brelse(bp);
315 return (error);
316 }
317 cnp = (struct nandfs_checkpoint *)(bp->b_data + offset);
318 list = &cnp->cp_snapshot_list;
319 }
320 list->ssl_next = cno;
321 nandfs_dirty_buf(bp, 1);
322
323 /* Update header */
324 error = nandfs_bread(cp_node, 0, NOCRED, 0, &bp);
325 if (error) {
326 brelse(bp);
327 return (error);
328 }
329 cnh = (struct nandfs_cpfile_header *) bp->b_data;
330 cnh->ch_nsnapshots++;
331 nandfs_dirty_buf(bp, 1);
332
333 return (0);
334 }
335
336 static int
337 nandfs_cp_clr_snapshot(struct nandfs_node *cp_node, uint64_t cno)
338 {
339 struct nandfs_device *fsdev;
340 struct nandfs_cpfile_header *cnh;
341 struct nandfs_checkpoint *cnp;
342 struct nandfs_snapshot_list *list;
343 struct buf *bp;
344 uint64_t blk, offset, snapshot_cnt;
345 uint64_t next, prev;
346 int error;
347
348 fsdev = cp_node->nn_nandfsdev;
349
350 /* Get snapshot data */
351 nandfs_checkpoint_blk_offset(fsdev, cno, &blk, &offset);
352 error = nandfs_bread(cp_node, blk, NOCRED, 0, &bp);
353 if (error) {
354 brelse(bp);
355 return (error);
356 }
357 cnp = (struct nandfs_checkpoint *)(bp->b_data + offset);
358 if (cnp->cp_flags & NANDFS_CHECKPOINT_INVALID) {
359 brelse(bp);
360 return (ENOENT);
361 }
362 if (!(cnp->cp_flags & NANDFS_CHECKPOINT_SNAPSHOT)) {
363 brelse(bp);
364 return (EINVAL);
365 }
366
367 list = &cnp->cp_snapshot_list;
368 next = list->ssl_next;
369 prev = list->ssl_prev;
370 brelse(bp);
371
372 /* Get previous snapshot */
373 if (prev != 0) {
374 nandfs_checkpoint_blk_offset(fsdev, prev, &blk, &offset);
375 error = nandfs_bread(cp_node, blk, NOCRED, 0, &bp);
376 if (error) {
377 brelse(bp);
378 return (error);
379 }
380 cnp = (struct nandfs_checkpoint *)(bp->b_data + offset);
381 list = &cnp->cp_snapshot_list;
382 } else {
383 nandfs_bread(cp_node, 0, NOCRED, 0, &bp);
384 cnh = (struct nandfs_cpfile_header *) bp->b_data;
385 list = &cnh->ch_snapshot_list;
386 }
387
388 list->ssl_next = next;
389 error = nandfs_dirty_buf(bp, 0);
390 if (error)
391 return (error);
392
393 /* Get next snapshot */
394 if (next != 0) {
395 nandfs_checkpoint_blk_offset(fsdev, next, &blk, &offset);
396 error = nandfs_bread(cp_node, blk, NOCRED, 0, &bp);
397 if (error) {
398 brelse(bp);
399 return (error);
400 }
401 cnp = (struct nandfs_checkpoint *)(bp->b_data + offset);
402 list = &cnp->cp_snapshot_list;
403 } else {
404 nandfs_bread(cp_node, 0, NOCRED, 0, &bp);
405 cnh = (struct nandfs_cpfile_header *) bp->b_data;
406 list = &cnh->ch_snapshot_list;
407 }
408 list->ssl_prev = prev;
409 nandfs_dirty_buf(bp, 1);
410
411 /* Update snapshot list for cno */
412 nandfs_checkpoint_blk_offset(fsdev, cno, &blk, &offset);
413 error = nandfs_bread(cp_node, blk, NOCRED, 0, &bp);
414 if (error) {
415 brelse(bp);
416 return (error);
417 }
418 cnp = (struct nandfs_checkpoint *)(bp->b_data + offset);
419 list = &cnp->cp_snapshot_list;
420 list->ssl_prev = 0;
421 list->ssl_next = 0;
422 cnp->cp_flags &= !NANDFS_CHECKPOINT_SNAPSHOT;
423 nandfs_dirty_buf(bp, 1);
424
425 /* Update header */
426 error = nandfs_bread(cp_node, 0, NOCRED, 0, &bp);
427 if (error) {
428 brelse(bp);
429 return (error);
430 }
431 cnh = (struct nandfs_cpfile_header *) bp->b_data;
432 snapshot_cnt = cnh->ch_nsnapshots;
433 snapshot_cnt--;
434 cnh->ch_nsnapshots = snapshot_cnt;
435 nandfs_dirty_buf(bp, 1);
436
437 return (0);
438 }
439
440 int
441 nandfs_chng_cpmode(struct nandfs_node *node, struct nandfs_cpmode *ncpm)
442 {
443 struct nandfs_device *fsdev;
444 uint64_t cno = ncpm->ncpm_cno;
445 int mode = ncpm->ncpm_mode;
446 int ret;
447
448 fsdev = node->nn_nandfsdev;
449 VOP_LOCK(NTOV(node), LK_EXCLUSIVE);
450 switch (mode) {
451 case NANDFS_CHECKPOINT:
452 if (nandfs_cp_mounted(fsdev, cno)) {
453 ret = EBUSY;
454 } else
455 ret = nandfs_cp_clr_snapshot(node, cno);
456 break;
457 case NANDFS_SNAPSHOT:
458 ret = nandfs_cp_set_snapshot(node, cno);
459 break;
460 default:
461 ret = EINVAL;
462 break;
463 }
464 VOP_UNLOCK(NTOV(node), 0);
465
466 return (ret);
467 }
468
469 static void
470 nandfs_cpinfo_fill(struct nandfs_checkpoint *cnp, struct nandfs_cpinfo *nci)
471 {
472
473 nci->nci_flags = cnp->cp_flags;
474 nci->nci_pad = 0;
475 nci->nci_cno = cnp->cp_cno;
476 nci->nci_create = cnp->cp_create;
477 nci->nci_nblk_inc = cnp->cp_nblk_inc;
478 nci->nci_blocks_count = cnp->cp_blocks_count;
479 nci->nci_next = cnp->cp_snapshot_list.ssl_next;
480 DPRINTF(CPFILE, ("%s: cn:%#jx ctime:%#jx\n",
481 __func__, (uintmax_t)cnp->cp_cno,
482 (uintmax_t)cnp->cp_create));
483 }
484
485 static int
486 nandfs_get_cpinfo_cp(struct nandfs_node *node, uint64_t cno,
487 struct nandfs_cpinfo *nci, uint32_t mnmembs, uint32_t *nmembs)
488 {
489 struct nandfs_device *fsdev;
490 struct buf *bp;
491 uint64_t blk, offset, last_cno, i;
492 uint16_t remaining;
493 int error;
494 #ifdef INVARIANTS
495 uint64_t testblk, testoffset;
496 #endif
497
498 if (cno == 0) {
499 return (ENOENT);
500 }
501
502 if (mnmembs < 1) {
503 return (EINVAL);
504 }
505
506 fsdev = node->nn_nandfsdev;
507 last_cno = fsdev->nd_last_cno;
508 DPRINTF(CPFILE, ("%s: cno:%#jx mnmembs: %#jx last:%#jx\n", __func__,
509 (uintmax_t)cno, (uintmax_t)mnmembs,
510 (uintmax_t)fsdev->nd_last_cno));
511
512 /*
513 * do {
514 * get block
515 * read checkpoints until we hit last checkpoint, end of block or
516 * requested number
517 * } while (last read checkpoint <= last checkpoint on fs &&
518 * read checkpoints < request number);
519 */
520 *nmembs = i = 0;
521 do {
522 nandfs_checkpoint_blk_offset(fsdev, cno, &blk, &offset);
523 remaining = nandfs_checkpoint_blk_remaining(fsdev, cno,
524 blk, offset);
525 error = nandfs_bread(node, blk, NOCRED, 0, &bp);
526 if (error) {
527 brelse(bp);
528 return (error);
529 }
530
531 while (cno <= last_cno && i < mnmembs && remaining) {
532 #ifdef INVARIANTS
533 nandfs_checkpoint_blk_offset(fsdev, cno, &testblk,
534 &testoffset);
535 KASSERT(testblk == blk, ("testblk != blk"));
536 KASSERT(testoffset == offset, ("testoffset != offset"));
537 #endif
538 DPRINTF(CPFILE, ("%s: cno %#jx\n", __func__,
539 (uintmax_t)cno));
540
541 nandfs_cpinfo_fill((struct nandfs_checkpoint *)
542 (bp->b_data + offset), nci);
543 offset += nandfs_checkpoint_size(fsdev);
544 i++;
545 nci++;
546 cno++;
547 (*nmembs)++;
548 remaining--;
549 }
550 brelse(bp);
551 } while (cno <= last_cno && i < mnmembs);
552
553 return (0);
554 }
555
556 static int
557 nandfs_get_cpinfo_sp(struct nandfs_node *node, uint64_t cno,
558 struct nandfs_cpinfo *nci, uint32_t mnmembs, uint32_t *nmembs)
559 {
560 struct nandfs_checkpoint *cnp;
561 struct nandfs_cpfile_header *cnh;
562 struct nandfs_device *fsdev;
563 struct buf *bp = NULL;
564 uint64_t curr = 0;
565 uint64_t blk, offset, curr_cno;
566 uint32_t flag;
567 int i, error;
568
569 if (cno == 0 || cno == ~(0))
570 return (ENOENT);
571
572 fsdev = node->nn_nandfsdev;
573 curr_cno = cno;
574
575 if (nmembs)
576 *nmembs = 0;
577 if (curr_cno == 1) {
578 /* Get list from header */
579 error = nandfs_bread(node, 0, NOCRED, 0, &bp);
580 if (error) {
581 brelse(bp);
582 return (error);
583 }
584 cnh = (struct nandfs_cpfile_header *) bp->b_data;
585 curr_cno = cnh->ch_snapshot_list.ssl_next;
586 brelse(bp);
587 bp = NULL;
588
589 /* No snapshots */
590 if (curr_cno == 0)
591 return (0);
592 }
593
594 for (i = 0; i < mnmembs; i++, nci++) {
595 nandfs_checkpoint_blk_offset(fsdev, curr_cno, &blk, &offset);
596 if (i == 0 || curr != blk) {
597 if (bp)
598 brelse(bp);
599 error = nandfs_bread(node, blk, NOCRED, 0, &bp);
600 if (error) {
601 brelse(bp);
602 return (ENOENT);
603 }
604 curr = blk;
605 }
606 cnp = (struct nandfs_checkpoint *)(bp->b_data + offset);
607 flag = cnp->cp_flags;
608 if (!(flag & NANDFS_CHECKPOINT_SNAPSHOT) ||
609 (flag & NANDFS_CHECKPOINT_INVALID))
610 break;
611
612 nci->nci_flags = flag;
613 nci->nci_pad = 0;
614 nci->nci_cno = cnp->cp_cno;
615 nci->nci_create = cnp->cp_create;
616 nci->nci_nblk_inc = cnp->cp_nblk_inc;
617 nci->nci_blocks_count = cnp->cp_blocks_count;
618 nci->nci_next = cnp->cp_snapshot_list.ssl_next;
619 if (nmembs)
620 (*nmembs)++;
621
622 curr_cno = nci->nci_next;
623 if (!curr_cno)
624 break;
625 }
626
627 brelse(bp);
628
629 return (0);
630 }
631
632 int
633 nandfs_get_cpinfo(struct nandfs_node *node, uint64_t cno, uint16_t flags,
634 struct nandfs_cpinfo *nci, uint32_t nmembs, uint32_t *nnmembs)
635 {
636 int error;
637
638 VOP_LOCK(NTOV(node), LK_EXCLUSIVE);
639 switch (flags) {
640 case NANDFS_CHECKPOINT:
641 error = nandfs_get_cpinfo_cp(node, cno, nci, nmembs, nnmembs);
642 break;
643 case NANDFS_SNAPSHOT:
644 error = nandfs_get_cpinfo_sp(node, cno, nci, nmembs, nnmembs);
645 break;
646 default:
647 error = EINVAL;
648 break;
649 }
650 VOP_UNLOCK(NTOV(node), 0);
651
652 return (error);
653 }
654
655 int
656 nandfs_get_cpinfo_ioctl(struct nandfs_node *node, struct nandfs_argv *nargv)
657 {
658 struct nandfs_cpinfo *nci;
659 uint64_t cno = nargv->nv_index;
660 void *buf = (void *)((uintptr_t)nargv->nv_base);
661 uint16_t flags = nargv->nv_flags;
662 uint32_t nmembs = 0;
663 int error;
664
665 if (nargv->nv_nmembs > NANDFS_CPINFO_MAX)
666 return (EINVAL);
667
668 nci = malloc(sizeof(struct nandfs_cpinfo) * nargv->nv_nmembs,
669 M_NANDFSTEMP, M_WAITOK | M_ZERO);
670
671 error = nandfs_get_cpinfo(node, cno, flags, nci, nargv->nv_nmembs, &nmembs);
672
673 if (error == 0) {
674 nargv->nv_nmembs = nmembs;
675 error = copyout(nci, buf,
676 sizeof(struct nandfs_cpinfo) * nmembs);
677 }
678
679 free(nci, M_NANDFSTEMP);
680 return (error);
681 }
682
683 int
684 nandfs_delete_cp(struct nandfs_node *node, uint64_t start, uint64_t end)
685 {
686 struct nandfs_checkpoint *cnp;
687 struct nandfs_device *fsdev;
688 struct buf *bp;
689 uint64_t cno = start, blk, offset;
690 int error;
691
692 DPRINTF(CPFILE, ("%s: delete cno %jx-%jx\n", __func__, start, end));
693 VOP_LOCK(NTOV(node), LK_EXCLUSIVE);
694 fsdev = node->nn_nandfsdev;
695 for (cno = start; cno <= end; cno++) {
696 if (!cno)
697 continue;
698
699 nandfs_checkpoint_blk_offset(fsdev, cno, &blk, &offset);
700 error = nandfs_bread(node, blk, NOCRED, 0, &bp);
701 if (error) {
702 VOP_UNLOCK(NTOV(node), 0);
703 brelse(bp);
704 return (error);
705 }
706
707 cnp = (struct nandfs_checkpoint *)(bp->b_data + offset);
708 if (cnp->cp_flags & NANDFS_CHECKPOINT_SNAPSHOT) {
709 brelse(bp);
710 VOP_UNLOCK(NTOV(node), 0);
711 return (0);
712 }
713
714 cnp->cp_flags |= NANDFS_CHECKPOINT_INVALID;
715
716 error = nandfs_dirty_buf(bp, 0);
717 if (error)
718 return (error);
719 }
720 VOP_UNLOCK(NTOV(node), 0);
721
722 return (0);
723 }
724
725 int
726 nandfs_make_snap(struct nandfs_device *fsdev, uint64_t *cno)
727 {
728 struct nandfs_cpmode cpm;
729 int error;
730
731 *cno = cpm.ncpm_cno = fsdev->nd_last_cno;
732 cpm.ncpm_mode = NANDFS_SNAPSHOT;
733 error = nandfs_chng_cpmode(fsdev->nd_cp_node, &cpm);
734 return (error);
735 }
736
737 int
738 nandfs_delete_snap(struct nandfs_device *fsdev, uint64_t cno)
739 {
740 struct nandfs_cpmode cpm;
741 int error;
742
743 cpm.ncpm_cno = cno;
744 cpm.ncpm_mode = NANDFS_CHECKPOINT;
745 error = nandfs_chng_cpmode(fsdev->nd_cp_node, &cpm);
746 return (error);
747 }
748
749 int nandfs_get_cpstat(struct nandfs_node *cp_node, struct nandfs_cpstat *ncp)
750 {
751 struct nandfs_device *fsdev;
752 struct nandfs_cpfile_header *cnh;
753 struct buf *bp;
754 int error;
755
756 VOP_LOCK(NTOV(cp_node), LK_EXCLUSIVE);
757 fsdev = cp_node->nn_nandfsdev;
758
759 /* Get header */
760 error = nandfs_bread(cp_node, 0, NOCRED, 0, &bp);
761 if (error) {
762 brelse(bp);
763 VOP_UNLOCK(NTOV(cp_node), 0);
764 return (error);
765 }
766 cnh = (struct nandfs_cpfile_header *) bp->b_data;
767 ncp->ncp_cno = fsdev->nd_last_cno;
768 ncp->ncp_ncps = cnh->ch_ncheckpoints;
769 ncp->ncp_nss = cnh->ch_nsnapshots;
770 DPRINTF(CPFILE, ("%s: cno:%#jx ncps:%#jx nss:%#jx\n",
771 __func__, ncp->ncp_cno, ncp->ncp_ncps, ncp->ncp_nss));
772 brelse(bp);
773 VOP_UNLOCK(NTOV(cp_node), 0);
774
775 return (0);
776 }
Cache object: f39dc8587804f5b85f9e1eba924f8fac
|