dabd21448462cc4d8d2f77253ecf8f7ddb8ebe8a
[dragonfly.git] / sys / vfs / hammer2 / hammer2_xops.c
1 /*
2  * Copyright (c) 2011-2015 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  * by Daniel Flores (GSOC 2013 - mentored by Matthew Dillon, compression) 
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
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
18  *    distribution.
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.
22  *
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
34  * SUCH DAMAGE.
35  */
36 /*
37  * Per-node backend for kernel filesystem interface.
38  *
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.
43  */
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/kernel.h>
47 #include <sys/fcntl.h>
48 #include <sys/buf.h>
49 #include <sys/proc.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>
55 #include <sys/uio.h>
56 #include <sys/objcache.h>
57 #include <sys/event.h>
58 #include <sys/file.h>
59 #include <vfs/fifofs/fifo.h>
60
61 #include "hammer2.h"
62
63 void
64 hammer2_xop_readdir(hammer2_xop_t *arg, int clindex)
65 {
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;
70         hammer2_key_t lkey;
71         int cache_index = -1;
72         int error = 0;
73
74         lkey = xop->head.lkey;
75         if (hammer2_debug & 0x0020)
76                 kprintf("xop_readdir %p lkey=%016jx\n", xop, lkey);
77
78         /*
79          * The inode's chain is the iterator.  If we cannot acquire it our
80          * contribution ends here.
81          */
82         parent = hammer2_inode_chain(xop->head.ip, clindex,
83                                      HAMMER2_RESOLVE_ALWAYS |
84                                      HAMMER2_RESOLVE_SHARED);
85         if (parent == NULL) {
86                 kprintf("xop_readdir: NULL parent\n");
87                 goto done;
88         }
89
90         /*
91          * Directory scan [re]start and loop.
92          *
93          * We feed the share-locked chain back to the frontend and must be
94          * sure not to unlock it in our iteration.
95          */
96         chain = hammer2_chain_lookup(&parent, &key_next, lkey, lkey,
97                              &cache_index, HAMMER2_LOOKUP_SHARED);
98         if (chain == NULL) {
99                 chain = hammer2_chain_lookup(&parent, &key_next,
100                                              lkey, (hammer2_key_t)-1,
101                                              &cache_index,
102                                              HAMMER2_LOOKUP_SHARED);
103         }
104         while (chain) {
105                 error = hammer2_xop_feed(&xop->head, chain, clindex, 0);
106                 if (error)
107                         break;
108                 chain = hammer2_chain_next(&parent, chain, &key_next,
109                                            key_next, (hammer2_key_t)-1,
110                                            &cache_index,
111                                            HAMMER2_LOOKUP_SHARED |
112                                            HAMMER2_LOOKUP_NOUNLOCK);
113         }
114         if (chain)
115                 hammer2_chain_drop(chain);
116         hammer2_chain_unlock(parent);
117         hammer2_chain_drop(parent);
118 done:
119         hammer2_xop_feed(&xop->head, NULL, clindex, error);
120 }
121
122 void
123 hammer2_xop_nresolve(hammer2_xop_t *arg, int clindex)
124 {
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;
130         hammer2_key_t lhc;
131         int cache_index = -1;   /* XXX */
132         int error;
133
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");
139                 chain = NULL;
140                 error = EIO;
141                 goto done;
142         }
143
144         /*
145          * Lookup the directory entry
146          */
147         lhc = hammer2_dirhash(xop->name, xop->name_len);
148         chain = hammer2_chain_lookup(&parent, &key_next,
149                                      lhc, lhc + HAMMER2_DIRHASH_LOMASK,
150                                      &cache_index,
151                                      HAMMER2_LOOKUP_ALWAYS |
152                                      HAMMER2_LOOKUP_SHARED);
153         while (chain) {
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) {
158                         break;
159                 }
160                 chain = hammer2_chain_next(&parent, chain, &key_next,
161                                            key_next,
162                                            lhc + HAMMER2_DIRHASH_LOMASK,
163                                            &cache_index,
164                                            HAMMER2_LOOKUP_ALWAYS |
165                                            HAMMER2_LOOKUP_SHARED);
166         }
167
168         /*
169          * If the entry is a hardlink pointer, resolve it.
170          */
171         error = 0;
172         if (chain) {
173                 if (chain->data->ipdata.meta.type == HAMMER2_OBJTYPE_HARDLINK) {
174                         error = hammer2_chain_hardlink_find(xop->head.ip,
175                                                             &parent,
176                                                             &chain);
177                 }
178         }
179 done:
180         error = hammer2_xop_feed(&xop->head, chain, clindex, error);
181         if (chain)
182                 hammer2_chain_drop(chain);
183         if (parent) {
184                 hammer2_chain_unlock(parent);
185                 hammer2_chain_drop(parent);
186         }
187 }
188
189 /*
190  * Scan directory collision entries for the specified lhc.  Used by
191  * the inode create code to locate an unused lhc.
192  */
193 void
194 hammer2_inode_xop_scanlhc(hammer2_xop_t *arg, int clindex)
195 {
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 */
201         int error = 0;
202
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");
208                 chain = NULL;
209                 error = EIO;
210                 goto done;
211         }
212
213         /*
214          * Lookup the directory entry
215          */
216         chain = hammer2_chain_lookup(&parent, &key_next,
217                                      xop->lhc,
218                                      xop->lhc + HAMMER2_DIRHASH_LOMASK,
219                                      &cache_index,
220                                      HAMMER2_LOOKUP_ALWAYS |
221                                      HAMMER2_LOOKUP_SHARED);
222         while (chain) {
223                 error = hammer2_xop_feed(&xop->head, chain, clindex,
224                                          chain->error);
225                 if (error) {
226                         hammer2_chain_drop(chain);
227                         chain = NULL;   /* safety */
228                         break;
229                 }
230                 chain = hammer2_chain_next(&parent, chain, &key_next,
231                                            key_next,
232                                            xop->lhc + HAMMER2_DIRHASH_LOMASK,
233                                            &cache_index,
234                                            HAMMER2_LOOKUP_ALWAYS |
235                                            HAMMER2_LOOKUP_SHARED);
236         }
237 done:
238         hammer2_xop_feed(&xop->head, NULL, clindex, error);
239         if (parent) {
240                 hammer2_chain_unlock(parent);
241                 hammer2_chain_drop(parent);
242         }
243 }
244
245 /*
246  * Inode create helper.
247  *
248  * Frontend holds the parent directory ip locked exclusively.  We
249  * create the inode and feed the exclusively locked chain to the
250  * frontend.
251  */
252 void
253 hammer2_inode_xop_create(hammer2_xop_t *arg, int clindex)
254 {
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;
260         int error;
261
262         chain = NULL;
263         parent = hammer2_inode_chain(xop->head.ip, clindex,
264                                      HAMMER2_RESOLVE_ALWAYS);
265         if (parent == NULL) {
266                 error = EIO;
267                 goto fail;
268         }
269         chain = hammer2_chain_lookup(&parent, &key_next,
270                                      xop->lhc, xop->lhc,
271                                      &cache_index, 0);
272         if (chain) {
273                 hammer2_chain_unlock(chain);
274                 error = EEXIST;
275                 goto fail;
276         }
277
278         error = hammer2_chain_create(&parent, &chain,
279                                      xop->head.ip->pmp,
280                                      xop->lhc, 0,
281                                      HAMMER2_BREF_TYPE_INODE,
282                                      HAMMER2_INODE_BYTES,
283                                      xop->flags);
284         if (error == 0) {
285                 hammer2_chain_modify(chain, 0);
286                 chain->data->ipdata.meta = xop->meta;
287                 bcopy(xop->name, chain->data->ipdata.filename,
288                       xop->name_len);
289         }
290         hammer2_chain_unlock(chain);
291         hammer2_chain_lock(chain, HAMMER2_RESOLVE_ALWAYS |
292                                   HAMMER2_RESOLVE_SHARED);
293 fail:
294         if (parent) {
295                 hammer2_chain_unlock(parent);
296                 hammer2_chain_drop(parent);
297         }
298         error = hammer2_xop_feed(&xop->head, chain, clindex, error);
299         if (chain)
300                 hammer2_chain_drop(chain);
301 }
302
303 /*
304  * Inode delete helper
305  */
306 void
307 hammer2_inode_xop_destroy(hammer2_xop_t *arg, int clindex)
308 {
309         /*hammer2_xop_inode_t *xop = &arg->xop_inode;*/
310 }