A delete_tid of 0 indicates a record which has not yet been deleted and
[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.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
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         return(0);
47 }
48
49 int
50 hammer_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  */
72 int
73 hammer_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;
89 loop:
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  */
170 static
171 enum vtype
172 hammer_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  */
205 void *
206 hammer_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