2 * Copyright (c) 2011-2015 The DragonFly Project. All rights reserved.
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 * by Daniel Flores (GSOC 2013 - mentored by Matthew Dillon, compression)
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in
17 * the documentation and/or other materials provided with the
19 * 3. Neither the name of The DragonFly Project nor the names of its
20 * contributors may be used to endorse or promote products derived
21 * from this software without specific, prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
29 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
31 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * Per-node backend for kernel filesystem interface.
39 * This executes a VOP concurrently on multiple nodes, each node via its own
40 * thread, and competes to advance the original request. The original
41 * request is retired the moment all requirements are met, even if the
42 * operation is still in-progress on some nodes.
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/kernel.h>
47 #include <sys/fcntl.h>
50 #include <sys/namei.h>
51 #include <sys/mount.h>
52 #include <sys/vnode.h>
53 #include <sys/mountctl.h>
54 #include <sys/dirent.h>
56 #include <sys/objcache.h>
57 #include <sys/event.h>
59 #include <vfs/fifofs/fifo.h>
64 hammer2_xop_readdir(hammer2_xop_t *arg, int clindex)
66 hammer2_xop_readdir_t *xop = &arg->xop_readdir;
67 hammer2_chain_t *parent;
68 hammer2_chain_t *chain;
69 hammer2_key_t key_next;
74 lkey = xop->head.lkey;
75 if (hammer2_debug & 0x0020)
76 kprintf("xop_readdir %p lkey=%016jx\n", xop, lkey);
79 * The inode's chain is the iterator. If we cannot acquire it our
80 * contribution ends here.
82 parent = hammer2_inode_chain(xop->head.ip, clindex,
83 HAMMER2_RESOLVE_ALWAYS |
84 HAMMER2_RESOLVE_SHARED);
86 kprintf("xop_readdir: NULL parent\n");
91 * Directory scan [re]start and loop.
93 * We feed the share-locked chain back to the frontend and must be
94 * sure not to unlock it in our iteration.
96 chain = hammer2_chain_lookup(&parent, &key_next, lkey, lkey,
97 &cache_index, HAMMER2_LOOKUP_SHARED);
99 chain = hammer2_chain_lookup(&parent, &key_next,
100 lkey, (hammer2_key_t)-1,
102 HAMMER2_LOOKUP_SHARED);
105 error = hammer2_xop_feed(&xop->head, chain, clindex, 0);
108 chain = hammer2_chain_next(&parent, chain, &key_next,
109 key_next, (hammer2_key_t)-1,
111 HAMMER2_LOOKUP_SHARED |
112 HAMMER2_LOOKUP_NOUNLOCK);
115 hammer2_chain_drop(chain);
116 hammer2_chain_unlock(parent);
117 hammer2_chain_drop(parent);
119 hammer2_xop_feed(&xop->head, NULL, clindex, error);
123 hammer2_xop_nresolve(hammer2_xop_t *arg, int clindex)
125 hammer2_xop_nresolve_t *xop = &arg->xop_nresolve;
126 hammer2_chain_t *parent;
127 hammer2_chain_t *chain;
128 const hammer2_inode_data_t *ripdata;
129 hammer2_key_t key_next;
131 int cache_index = -1; /* XXX */
134 parent = hammer2_inode_chain(xop->head.ip, clindex,
135 HAMMER2_RESOLVE_ALWAYS |
136 HAMMER2_RESOLVE_SHARED);
137 if (parent == NULL) {
138 kprintf("xop_nresolve: NULL parent\n");
145 * Lookup the directory entry
147 lhc = hammer2_dirhash(xop->name, xop->name_len);
148 chain = hammer2_chain_lookup(&parent, &key_next,
149 lhc, lhc + HAMMER2_DIRHASH_LOMASK,
151 HAMMER2_LOOKUP_ALWAYS |
152 HAMMER2_LOOKUP_SHARED);
154 ripdata = &chain->data->ipdata;
155 if (chain->bref.type == HAMMER2_BREF_TYPE_INODE &&
156 ripdata->meta.name_len == xop->name_len &&
157 bcmp(ripdata->filename, xop->name, xop->name_len) == 0) {
160 chain = hammer2_chain_next(&parent, chain, &key_next,
162 lhc + HAMMER2_DIRHASH_LOMASK,
164 HAMMER2_LOOKUP_ALWAYS |
165 HAMMER2_LOOKUP_SHARED);
169 * If the entry is a hardlink pointer, resolve it.
173 if (chain->data->ipdata.meta.type == HAMMER2_OBJTYPE_HARDLINK) {
174 error = hammer2_chain_hardlink_find(xop->head.ip,
180 error = hammer2_xop_feed(&xop->head, chain, clindex, error);
182 hammer2_chain_drop(chain);
184 hammer2_chain_unlock(parent);
185 hammer2_chain_drop(parent);
190 * Scan directory collision entries for the specified lhc. Used by
191 * the inode create code to locate an unused lhc.
194 hammer2_inode_xop_scanlhc(hammer2_xop_t *arg, int clindex)
196 hammer2_xop_scanlhc_t *xop = &arg->xop_scanlhc;
197 hammer2_chain_t *parent;
198 hammer2_chain_t *chain;
199 hammer2_key_t key_next;
200 int cache_index = -1; /* XXX */
203 parent = hammer2_inode_chain(xop->head.ip, clindex,
204 HAMMER2_RESOLVE_ALWAYS |
205 HAMMER2_RESOLVE_SHARED);
206 if (parent == NULL) {
207 kprintf("xop_nresolve: NULL parent\n");
214 * Lookup the directory entry
216 chain = hammer2_chain_lookup(&parent, &key_next,
218 xop->lhc + HAMMER2_DIRHASH_LOMASK,
220 HAMMER2_LOOKUP_ALWAYS |
221 HAMMER2_LOOKUP_SHARED);
223 error = hammer2_xop_feed(&xop->head, chain, clindex,
226 hammer2_chain_drop(chain);
227 chain = NULL; /* safety */
230 chain = hammer2_chain_next(&parent, chain, &key_next,
232 xop->lhc + HAMMER2_DIRHASH_LOMASK,
234 HAMMER2_LOOKUP_ALWAYS |
235 HAMMER2_LOOKUP_SHARED);
238 hammer2_xop_feed(&xop->head, NULL, clindex, error);
240 hammer2_chain_unlock(parent);
241 hammer2_chain_drop(parent);
246 * Inode create helper.
248 * Frontend holds the parent directory ip locked exclusively. We
249 * create the inode and feed the exclusively locked chain to the
253 hammer2_inode_xop_create(hammer2_xop_t *arg, int clindex)
255 hammer2_xop_create_t *xop = &arg->xop_create;
256 hammer2_chain_t *parent;
257 hammer2_chain_t *chain;
258 hammer2_key_t key_next;
259 int cache_index = -1;
263 parent = hammer2_inode_chain(xop->head.ip, clindex,
264 HAMMER2_RESOLVE_ALWAYS);
265 if (parent == NULL) {
269 chain = hammer2_chain_lookup(&parent, &key_next,
273 hammer2_chain_unlock(chain);
278 error = hammer2_chain_create(&parent, &chain,
281 HAMMER2_BREF_TYPE_INODE,
285 hammer2_chain_modify(chain, 0);
286 chain->data->ipdata.meta = xop->meta;
287 bcopy(xop->name, chain->data->ipdata.filename,
290 hammer2_chain_unlock(chain);
291 hammer2_chain_lock(chain, HAMMER2_RESOLVE_ALWAYS |
292 HAMMER2_RESOLVE_SHARED);
295 hammer2_chain_unlock(parent);
296 hammer2_chain_drop(parent);
298 error = hammer2_xop_feed(&xop->head, chain, clindex, error);
300 hammer2_chain_drop(chain);
304 * Inode delete helper
307 hammer2_inode_xop_destroy(hammer2_xop_t *arg, int clindex)
309 /*hammer2_xop_inode_t *xop = &arg->xop_inode;*/