A delete_tid of 0 indicates a record which has not yet been deleted and
[dragonfly.git] / sys / vfs / hammer / hammer_inode.c
CommitLineData
427e5fc6
MD
1/*
2 * Copyright (c) 2007 The DragonFly Project. All rights reserved.
3 *
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
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 *
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
16 * distribution.
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.
20 *
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
32 * SUCH DAMAGE.
33 *
34 * $DragonFly: src/sys/vfs/hammer/hammer_inode.c,v 1.1 2007/11/01 20:53:05 dillon Exp $
35 */
36
37#include "hammer.h"
38#include <sys/buf.h>
39#include <sys/buf2.h>
40
41static enum vtype hammer_get_vnode_type(u_int16_t obj_type);
42
43int
44hammer_vop_inactive(struct vop_inactive_args *ap)
45{
46 return(0);
47}
48
49int
50hammer_vop_reclaim(struct vop_reclaim_args *ap)
51{
52 struct hammer_mount *hmp;
53 struct hammer_inode *ip;
54 struct vnode *vp;
55
56 vp = ap->a_vp;
57 hmp = (void *)vp->v_mount->mnt_data;
58 if ((ip = vp->v_data) != NULL) {
59 ip->vp = NULL;
60 vp->v_data = NULL;
61 RB_REMOVE(hammer_ino_rb_tree, &hmp->rb_inos_root, ip);
62 kfree(ip, M_HAMMER);
63 }
64 return(0);
65}
66
67/*
68 * Lookup or create the vnode associated with the specified inode number.
69 * ino_t in DragonFly is 64 bits which matches the 64 bit HAMMER inode
70 * number.
71 */
72int
73hammer_vfs_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
74{
75 struct hammer_mount *hmp = (void *)mp->mnt_data;
76 struct hammer_btree_info binfo;
77 struct hammer_inode_info iinfo;
78 struct hammer_base_elm key;
79 struct hammer_inode *ip;
80 struct vnode *vp;
81 int error;
82
83 /*
84 * Determine if we already have an inode cached. If we do then
85 * we are golden.
86 */
87 iinfo.obj_id = ino;
88 iinfo.obj_asof = 0;
89loop:
90 ip = hammer_ino_rb_tree_RB_LOOKUP_INFO(&hmp->rb_inos_root, &iinfo);
91 if (ip) {
92 vp = ip->vp;
93 if (vget(vp, LK_EXCLUSIVE) != 0)
94 goto loop;
95 ip = hammer_ino_rb_tree_RB_LOOKUP_INFO(&hmp->rb_inos_root,
96 &iinfo);
97 if (ip == NULL || ip->vp != vp) {
98 vput(vp);
99 goto loop;
100 }
101 *vpp = vp;
102 return(0);
103 }
104
105 /*
106 * Lookup failed, instantiate a new vnode and inode in-memory
107 * structure so we don't block in kmalloc later on when holding
108 * locked buffer cached buffers.
109 */
110 error = getnewvnode(VT_HAMMER, mp, vpp, 0, 0);
111 if (error) {
112 *vpp = NULL;
113 return (error);
114 }
115 vp = *vpp;
116 ip = kmalloc(sizeof(*ip), M_HAMMER, M_WAITOK|M_ZERO);
117
118 /*
119 * If we do not have an inode cached search the HAMMER on-disk B-Tree
120 * for it.
121 */
122 hammer_btree_info_init(&binfo, hmp->rootcl);
123 key.obj_id = ino;
124 key.key = 0;
125 key.create_tid = 0;
126 key.delete_tid = 0;
127 key.rec_type = HAMMER_RECTYPE_INODE;
128 key.obj_type = 0;
129
130 error = hammer_btree_lookup(&binfo, &key, HAMMER_BTREE_GET_RECORD |
131 HAMMER_BTREE_GET_DATA);
132
133 /*
134 * On success the B-Tree lookup will hold the appropriate
135 * buffer cache buffers and provide a pointer to the requested
136 * information. Copy the information to the in-memory inode.
137 */
138 if (error == 0) {
139 ip->ino_rec = binfo.rec->inode;
140 ip->ino_data = binfo.data->inode;
141 }
142 hammer_btree_info_done(&binfo);
143
144 /*
145 * On success load the inode's record and data and insert the
146 * inode into the B-Tree. It is possible to race another lookup
147 * insertion of the same inode so deal with that condition too.
148 */
149 if (error == 0) {
150 if (RB_INSERT(hammer_ino_rb_tree, &hmp->rb_inos_root, ip)) {
151 vp->v_type = VBAD;
152 vx_put(vp);
153 kfree(ip, M_HAMMER);
154 goto loop;
155 }
156 ip->vp = vp;
157 vp->v_data = (void *)ip;
158 vp->v_type =
159 hammer_get_vnode_type(ip->ino_rec.base.base.obj_type);
160 *vpp = vp;
161 } else {
162 *vpp = NULL;
163 }
164 return (error);
165}
166
167/*
168 * Convert a HAMMER filesystem object type to a vnode type
169 */
170static
171enum vtype
172hammer_get_vnode_type(u_int16_t obj_type)
173{
174 switch(obj_type) {
175 case HAMMER_OBJTYPE_DIRECTORY:
176 return(VDIR);
177 case HAMMER_OBJTYPE_REGFILE:
178 return(VREG);
179 case HAMMER_OBJTYPE_DBFILE:
180 return(VDATABASE);
181 case HAMMER_OBJTYPE_FIFO:
182 return(VFIFO);
183 case HAMMER_OBJTYPE_CDEV:
184 return(VCHR);
185 case HAMMER_OBJTYPE_BDEV:
186 return(VBLK);
187 case HAMMER_OBJTYPE_SOFTLINK:
188 return(VLNK);
189 default:
190 return(VBAD);
191 }
192 /* not reached */
193}
194
195/*
196 * Access the filesystem buffer containing the cluster-relative byte
197 * offset, validate the buffer type, load *bufferp and return a
198 * pointer to the requested data.
199 *
200 * If buf_type is 0 the buffer is assumed to be a pure-data buffer and
201 * no type or crc check is performed.
202 *
203 * XXX add a flag for the buffer type and check the CRC here XXX
204 */
205void *
206hammer_bread(struct hammer_cluster *cluster, int32_t cloff,
207 u_int64_t buf_type,
208 int *errorp, struct hammer_buffer **bufferp)
209{
210 struct hammer_buffer *buffer;
211 int32_t buf_no;
212 int32_t buf_off;
213
214 /*
215 * Load the correct filesystem buffer, replacing *bufferp.
216 */
217 buf_no = cloff / HAMMER_BUFSIZE;
218 buffer = *bufferp;
219 if (buffer == NULL || buffer->cluster != cluster ||
220 buffer->buf_no != buf_no) {
221 if (buffer)
222 hammer_put_buffer(buffer);
223 buffer = hammer_get_buffer(cluster, buf_no, 0, errorp);
224 *bufferp = buffer;
225 if (buffer == NULL)
226 return(NULL);
227 }
228
229 /*
230 * Validate the buffer type and crc XXX
231 */
232 buf_off = cloff & HAMMER_BUFMASK;
233 if (buf_type) {
234 if (buf_type != buffer->ondisk->head.buf_type) {
235 *errorp = EIO;
236 return(NULL);
237 }
238 if (buf_off < sizeof(buffer->ondisk->head)) {
239 *errorp = EIO;
240 return(NULL);
241 }
242 /* XXX crc */
243 }
244
245 /*
246 * Return a pointer to the buffer data.
247 */
248 *errorp = 0;
249 return((char *)buffer->ondisk + buf_off);
250}
251