| 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 | |