1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 2012 STRATO AG. All rights reserved.
23 */
24 #include <sys/zfs_context.h>
25 #include <sys/errno.h>
26 #include <sys/far_impl.h>
27
28 static void
29 far_count_value_free(mod_hash_val_t val)
30 {
31 far_count_elem_t *fce = val;
32 kmem_free(fce, sizeof (*fce));
33 }
34
35 static void
36 far_count_key_free(mod_hash_key_t key)
37 {
38 kmem_free(key, sizeof (uint64_t));
39 }
40
41 static int
42 far_count_cmp(const void *aa, const void *bb)
43 {
44 const far_count_elem_t *a = aa;
45 const far_count_elem_t *b = bb;
46
47 if (a->fce_ino < b->fce_ino)
48 return -1;
49 if (a->fce_ino > b->fce_ino)
50 return 1;
51 return 0;
52 }
53
54 int
55 far_add_count(far_counter_t *fc, uint64_t ino, uint64_t inc,
56 uint64_t aux, uint64_t *new_count, uint64_t *old_aux)
57 {
58 far_count_elem_t *fce;
59 far_count_elem_t e = { .fce_ino = ino };
60 avl_index_t where;
61
62 fce = avl_find(&fc->fc_avl, &e, &where);
63
64 if (!fce) {
65 fce = kmem_alloc(sizeof (*fce), KM_SLEEP);
66 fce->fce_count = 0;
67 fce->fce_aux = 0;
68 fce->fce_ino = ino;
69 avl_insert(&fc->fc_avl, fce, where);
70 }
71
72 if (old_aux) {
73 *old_aux = fce->fce_aux;
74 fce->fce_aux = aux;
75 }
76 fce->fce_count += inc;
77
78 if (new_count)
79 *new_count = fce->fce_count;
80
81 return (0);
82 }
83
84 int
85 far_get_count(far_counter_t *fc, uint64_t ino, uint64_t *count, uint64_t *aux)
86 {
87 far_count_elem_t *fce;
88 far_count_elem_t e = { .fce_ino = ino };
89
90 fce = avl_find(&fc->fc_avl, &e, NULL);
91 if (!fce) {
92 if (count)
93 *count = 0;
94 if (aux)
95 *aux = 0;
96 return (ENOENT);
97 } else {
98 if (count)
99 *count = fce->fce_count;
100 if (aux)
101 *aux = fce->fce_aux;
102 return (0);
103 }
104 }
105
106 void
107 far_free_count(far_counter_t *fc, uint64_t ino)
108 {
109 far_count_elem_t *fce;
110 far_count_elem_t e = { .fce_ino = ino };
111
112 fce = avl_find(&fc->fc_avl, &e, NULL);
113 if (!fce)
114 return;
115 avl_remove(&fc->fc_avl, fce);
116 kmem_free(fce, sizeof (*fce));
117 }
118
119 int
120 far_count_init(far_counter_t *fc, char *name)
121 {
122 avl_create(&fc->fc_avl, far_count_cmp, sizeof (far_count_elem_t),
123 offsetof(far_count_elem_t, fce_avl_node));
124 fc->fc_name = name;
125
126 return 0;
127 }
128
129 int
130 far_count_fini(far_counter_t *fc)
131 {
132 far_count_elem_t *fce;
133 int ret = 0;
134
135 while ((fce = avl_first(&fc->fc_avl))) {
136 /*
137 * a count of zero might be left over if a file had > 1 links
138 * and be replaced by a file with > 1 link. see test 041.034
139 */
140 if (fce->fce_count != 0) {
141 cmn_err(CE_NOTE, "far_assert_count_empty: %s ino %"
142 PRIu64 " count %" PRIu64"\n", fc->fc_name,
143 fce->fce_ino, fce->fce_count);
144 ++ret;
145 }
146 avl_remove(&fc->fc_avl, fce);
147 kmem_free(fce, sizeof (*fce));
148 }
149 avl_destroy(&fc->fc_avl);
150
151 return (ret);
152 }