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 }