2 * Copyright (c) 2007 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * $DragonFly: src/sys/vfs/hammer/hammer_object.c,v 1.2 2007/11/19 00:53:40 dillon Exp $
39 static int hammer_add_record(hammer_transaction_t trans,
40 hammer_record_t record);
43 * Red-black tree support.
46 hammer_rec_rb_compare(struct hammer_record *rec1, struct hammer_record *rec2)
48 if (rec1->rec.base.base.rec_type < rec2->rec.base.base.rec_type)
50 if (rec1->rec.base.base.rec_type > rec2->rec.base.base.rec_type)
53 if (rec1->rec.base.base.key < rec2->rec.base.base.key)
55 if (rec1->rec.base.base.key > rec2->rec.base.base.key)
58 if (rec1->rec.base.base.create_tid < rec2->rec.base.base.create_tid)
60 if (rec1->rec.base.base.create_tid > rec2->rec.base.base.create_tid)
66 hammer_rec_compare(struct hammer_base_elm *info, struct hammer_record *rec)
69 * A key1->rec_type of 0 matches any record type.
72 if (info->rec_type < rec->rec.base.base.rec_type)
74 if (info->rec_type > rec->rec.base.base.rec_type)
79 * There is no special case for key. 0 means 0.
81 if (info->key < rec->rec.base.base.key)
83 if (info->key > rec->rec.base.base.key)
87 * This test has a number of special cases. create_tid in key1 is
88 * the as-of transction id, and delete_tid in key1 is NOT USED.
90 * A key1->create_tid of 0 matches any record regardles of when
91 * it was created or destroyed. 0xFFFFFFFFFFFFFFFFULL should be
92 * used to search for the most current state of the object.
94 * key2->create_tid is a HAMMER record and will never be
95 * 0. key2->delete_tid is the deletion transaction id or 0 if
96 * the record has not yet been deleted.
98 if (info->create_tid) {
99 if (info->create_tid < rec->rec.base.base.create_tid)
101 if (rec->rec.base.base.delete_tid &&
102 info->create_tid >= rec->rec.base.base.delete_tid) {
109 RB_GENERATE(hammer_rec_rb_tree, hammer_record, rb_node, hammer_rec_rb_compare);
110 RB_GENERATE_XLOOKUP(hammer_rec_rb_tree, INFO, hammer_record, rb_node,
111 hammer_rec_compare, hammer_base_elm_t);
114 * Add a directory entry (dip,ncp) which references inode (ip).
116 * Note that the low 32 bits of the namekey are set temporarily to create
117 * a unique in-memory record, and may be modified a second time when the
118 * record is synchronized to disk. In particular, the low 32 bits cannot be
119 * all 0's when synching to disk, which is not handled here.
122 hammer_add_directory(struct hammer_transaction *trans,
123 struct hammer_inode *dip, struct namecache *ncp,
124 struct hammer_inode *ip)
126 struct hammer_record *record;
130 record = hammer_alloc_ip_record(trans, dip);
132 bytes = ncp->nc_nlen + 1;
134 record->rec.entry.base.base.obj_id = dip->obj_id;
135 record->rec.entry.base.base.key = hammer_directory_namekey(ncp->nc_name, bytes - 1);
136 record->rec.entry.base.base.key += trans->hmp->namekey_iterator++;
137 record->rec.entry.base.base.create_tid = trans->tid;
138 record->rec.entry.base.base.rec_type = HAMMER_RECTYPE_DIRENTRY;
139 record->rec.entry.base.base.obj_type = ip->ino_rec.base.base.obj_type;
140 record->rec.entry.base.base.obj_id = ip->obj_id;
141 if (bytes <= sizeof(record->rec.entry.den_name)) {
142 record->data = (void *)record->rec.entry.den_name;
144 record->data = kmalloc(bytes, M_HAMMER, M_WAITOK);
145 record->flags |= HAMMER_RECF_ALLOCDATA;
146 bcopy(ncp->nc_name, record->data, bytes);
148 record->data_len = bytes;
149 ++dip->ino_rec.ino_nlinks;
150 hammer_modify_inode(trans, dip, HAMMER_INODE_RDIRTY);
151 error = hammer_add_record(trans, record);
156 * Allocate a record for the caller to finish filling in
158 struct hammer_record *
159 hammer_alloc_ip_record(struct hammer_transaction *trans, hammer_inode_t ip)
161 hammer_record_t record;
163 record = kmalloc(sizeof(*record), M_HAMMER, M_WAITOK|M_ZERO);
164 record->last_tid = trans->tid;
170 * Free a record. Clean the structure up even though we are throwing it
171 * away as a sanity check.
174 hammer_free_ip_record(struct hammer_record *record)
176 if (record->flags & HAMMER_RECF_ONRBTREE) {
177 RB_REMOVE(hammer_rec_rb_tree, &record->ip->rec_tree, record);
178 record->flags &= ~HAMMER_RECF_ONRBTREE;
180 if (record->flags & HAMMER_RECF_ALLOCDATA) {
181 kfree(record->data, M_HAMMER);
182 record->flags &= ~HAMMER_RECF_ALLOCDATA;
185 kfree(record, M_HAMMER);
189 * Add the record to the inode's rec_tree. Directory entries
193 hammer_add_record(struct hammer_transaction *trans, hammer_record_t record)
195 while (RB_INSERT(hammer_rec_rb_tree, &record->ip->rec_tree, record)) {
196 if (record->rec.base.base.rec_type != HAMMER_RECTYPE_DIRENTRY){
197 hammer_free_ip_record(record);
200 record->rec.base.base.key &= ~(0xFFFFFFFFLL);
201 record->rec.base.base.key |= trans->hmp->namekey_iterator++;
203 record->flags |= HAMMER_RECF_ONRBTREE;
209 * Delete records belonging to the specified range. Deal with edge and
210 * overlap cases. This function sets the delete tid and breaks adds
211 * up to two records to deal with edge cases, leaving the range as a gap.
212 * The caller will then add records as appropriate.
215 hammer_delete_records(struct hammer_transaction *trans,
216 struct hammer_inode *ip,
217 hammer_base_elm_t ran_beg, hammer_base_elm_t ran_end)