020b50feca0a04f0a37bc8fdf4cdec80d2ac08bd
[dragonfly.git] / sys / vfs / hammer2 / hammer2_subr.c
1 /*
2  * Copyright (c) 2011-2012 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@dragonflybsd.org>
6  * by Venkatesh Srinivas <vsrinivas@dragonflybsd.org>
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in
16  *    the documentation and/or other materials provided with the
17  *    distribution.
18  * 3. Neither the name of The DragonFly Project nor the names of its
19  *    contributors may be used to endorse or promote products derived
20  *    from this software without specific, prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
26  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
28  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
30  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 #include <sys/cdefs.h>
36 #include <sys/cdefs.h>
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/types.h>
40 #include <sys/lock.h>
41 #include <sys/uuid.h>
42
43 #include "hammer2.h"
44
45 /*
46  * HAMMER2 inode locks
47  *
48  * HAMMER2 offers shared locks, update locks, and exclusive locks on inodes.
49  *
50  * Shared locks allow concurrent access to an inode's fields, but exclude
51  * access by concurrent exclusive locks.
52  *
53  * Update locks are interesting -- an update lock will be taken after all
54  * shared locks on an inode are released, but once it is in place, shared
55  * locks may proceed. The update field is signalled by a busy flag in the
56  * inode. Only one update lock may be in place at a given time on an inode.
57  *
58  * Exclusive locks prevent concurrent access to the inode.
59  *
60  * XXX: What do we use each for? How is visibility to the inode controlled?
61  */
62
63 void
64 hammer2_inode_lock_sh(struct hammer2_inode *ip)
65 {
66         lockmgr(&ip->lk, LK_SHARED);
67 }
68
69 void
70 hammer2_inode_lock_up(struct hammer2_inode *ip)
71 {
72         lockmgr(&ip->lk, LK_EXCLUSIVE);
73         ++ip->busy;
74         lockmgr(&ip->lk, LK_DOWNGRADE);
75 }
76
77 void
78 hammer2_inode_lock_ex(struct hammer2_inode *ip)
79 {
80         lockmgr(&ip->lk, LK_EXCLUSIVE);
81 }
82
83 void
84 hammer2_inode_unlock_ex(struct hammer2_inode *ip)
85 {
86         lockmgr(&ip->lk, LK_RELEASE);
87 }
88
89 void
90 hammer2_inode_unlock_up(struct hammer2_inode *ip)
91 {
92         lockmgr(&ip->lk, LK_UPGRADE);
93         --ip->busy;
94         lockmgr(&ip->lk, LK_RELEASE);
95 }
96
97 void
98 hammer2_inode_unlock_sh(struct hammer2_inode *ip)
99 {
100         lockmgr(&ip->lk, LK_RELEASE);
101 }
102
103 /*
104  * Mount-wide locks
105  */
106
107 void
108 hammer2_mount_exlock(struct hammer2_mount *hmp)
109 {
110         lockmgr(&hmp->hm_lk, LK_EXCLUSIVE);
111 }
112
113 void
114 hammer2_mount_shlock(struct hammer2_mount *hmp)
115 {
116         lockmgr(&hmp->hm_lk, LK_SHARED);
117 }
118
119 void
120 hammer2_mount_unlock(struct hammer2_mount *hmp)
121 {
122         lockmgr(&hmp->hm_lk, LK_RELEASE);
123 }
124
125 /*
126  * Inode/vnode subroutines
127  */
128
129 /*
130  * igetv:
131  *
132  *      Get a vnode associated with the given inode. If one exists, return it,
133  *      locked and ref-ed. Otherwise, a new vnode is allocated and associated
134  *      with the vnode.
135  *
136  *      The lock prevents the inode from being reclaimed, I believe (XXX)
137  */
138 struct vnode *
139 igetv(struct hammer2_inode *ip, int *error)
140 {
141         struct vnode *vp;
142         struct hammer2_mount *hmp;
143         int rc;
144
145         hmp = ip->mp;
146         rc = 0;
147
148         kprintf("igetv\n");
149         tsleep(&igetv, 0, "", hz * 10);
150
151         hammer2_inode_lock_ex(ip);
152         do {
153                 /* Reuse existing vnode */
154                 vp = ip->vp;
155                 if (vp) {
156                         /* XXX: Is this necessary? */
157                         vx_lock(vp);
158                         break;
159                 }
160
161                 /* Allocate and initialize a new vnode */
162                 rc = getnewvnode(VT_HAMMER2, H2TOMP(hmp), &vp,
163                                     VLKTIMEOUT, LK_CANRECURSE);
164                 if (rc) {
165                         vp = NULL;
166                         break;
167                 }
168
169                 kprintf("igetv new\n");
170                 switch (ip->type & HAMMER2_INODE_TYPE_MASK) {
171                 case HAMMER2_INODE_TYPE_DIR:
172                         vp->v_type = VDIR;
173                         break;
174                 case HAMMER2_INODE_TYPE_FILE:
175                         vp->v_type = VREG;
176                                 /*XXX: Init w/ true file size; 0*/
177                         vinitvmio(vp, 0, PAGE_SIZE, -1);
178                         break;
179                 default:
180                         break;
181                 }
182
183                 if (ip->type & HAMMER2_INODE_TYPE_ROOT)
184                         vsetflags(vp, VROOT);
185
186                 vp->v_data = ip;
187                 ip->vp = vp;
188         } while (0);
189         hammer2_inode_unlock_ex(ip);
190
191         /*
192          * XXX: Under what conditions can a vnode be reclaimed? How do we want
193          * to interlock against vreclaim calls into hammer2? When do we need to?
194          */
195
196         kprintf("igetv exit\n");
197
198         /* vp is either NULL or a locked, ref-ed vnode referring to inode ip */
199         *error = rc;
200         return (vp);
201 }
202
203 /*
204  * alloci:
205  *
206  *      Allocate an inode in a HAMMER2 mount. The returned inode is locked
207  *      exclusively. The HAMMER2 mountpoint must be locked on entry.
208  */
209 struct hammer2_inode *
210 alloci(struct hammer2_mount *hmp)
211 {
212         struct hammer2_inode *ip;
213
214         kprintf("alloci\n");
215
216         ip = kmalloc(sizeof(struct hammer2_inode), hmp->hm_inodes,
217                      M_WAITOK | M_ZERO);
218         if (!ip) {
219                 /* XXX */
220         }
221
222         ++hmp->hm_ninodes;
223
224         ip->type = 0;
225         ip->mp = hmp;
226         lockinit(&ip->lk, "h2inode", 0, 0);
227         ip->vp = NULL;
228
229         hammer2_inode_lock_ex(ip);
230
231         return (ip);
232 }
233