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