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