hammer2 - Refactor frontend part 13/many
[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, the feed inherits the chain's
92          * lock so do not unlock it on the iteration.
93          */
94         chain = hammer2_chain_lookup(&parent, &key_next, lkey, lkey,
95                              &cache_index, HAMMER2_LOOKUP_SHARED);
96         if (chain == NULL) {
97                 chain = hammer2_chain_lookup(&parent, &key_next,
98                                              lkey, (hammer2_key_t)-1,
99                                              &cache_index,
100                                              HAMMER2_LOOKUP_SHARED);
101         }
102         while (chain) {
103                 error = hammer2_xop_feed(&xop->head, chain, clindex, 0);
104                 if (error)
105                         break;
106                 chain = hammer2_chain_next(&parent, chain, &key_next,
107                                            key_next, (hammer2_key_t)-1,
108                                            &cache_index,
109                                            HAMMER2_LOOKUP_SHARED |
110                                            HAMMER2_LOOKUP_NOUNLOCK);
111         }
112         if (chain)
113                 hammer2_chain_drop(chain);
114         hammer2_chain_unlock(parent);
115         hammer2_chain_drop(parent);
116 done:
117         hammer2_xop_feed(&xop->head, NULL, clindex, error);
118 }
119
120 void
121 hammer2_xop_nresolve(hammer2_xop_t *arg, int clindex)
122 {
123         hammer2_xop_nresolve_t *xop = &arg->xop_nresolve;
124         hammer2_chain_t *parent;
125         hammer2_chain_t *chain;
126         const hammer2_inode_data_t *ripdata;
127         const char *name;
128         size_t name_len;
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         name = xop->head.name;
144         name_len = xop->head.name_len;
145
146         /*
147          * Lookup the directory entry
148          */
149         lhc = hammer2_dirhash(name, name_len);
150         chain = hammer2_chain_lookup(&parent, &key_next,
151                                      lhc, lhc + HAMMER2_DIRHASH_LOMASK,
152                                      &cache_index,
153                                      HAMMER2_LOOKUP_ALWAYS |
154                                      HAMMER2_LOOKUP_SHARED);
155         while (chain) {
156                 ripdata = &chain->data->ipdata;
157                 if (chain->bref.type == HAMMER2_BREF_TYPE_INODE &&
158                     ripdata->meta.name_len == name_len &&
159                     bcmp(ripdata->filename, name, name_len) == 0) {
160                         break;
161                 }
162                 chain = hammer2_chain_next(&parent, chain, &key_next,
163                                            key_next,
164                                            lhc + HAMMER2_DIRHASH_LOMASK,
165                                            &cache_index,
166                                            HAMMER2_LOOKUP_ALWAYS |
167                                            HAMMER2_LOOKUP_SHARED);
168         }
169
170         /*
171          * If the entry is a hardlink pointer, resolve it.
172          */
173         error = 0;
174         if (chain) {
175                 if (chain->data->ipdata.meta.type == HAMMER2_OBJTYPE_HARDLINK) {
176                         error = hammer2_chain_hardlink_find(xop->head.ip,
177                                                             &parent,
178                                                             &chain);
179                 }
180         }
181 done:
182         error = hammer2_xop_feed(&xop->head, chain, clindex, error);
183         if (chain)
184                 hammer2_chain_drop(chain);
185         if (parent) {
186                 hammer2_chain_unlock(parent);
187                 hammer2_chain_drop(parent);
188         }
189 }
190
191 /*
192  * Directory collision resolver scan helper (backend, threaded).
193  *
194  * Used by the inode create code to locate an unused lhc.
195  */
196 void
197 hammer2_inode_xop_scanlhc(hammer2_xop_t *arg, int clindex)
198 {
199         hammer2_xop_scanlhc_t *xop = &arg->xop_scanlhc;
200         hammer2_chain_t *parent;
201         hammer2_chain_t *chain;
202         hammer2_key_t key_next;
203         int cache_index = -1;   /* XXX */
204         int error = 0;
205
206         parent = hammer2_inode_chain(xop->head.ip, clindex,
207                                      HAMMER2_RESOLVE_ALWAYS |
208                                      HAMMER2_RESOLVE_SHARED);
209         if (parent == NULL) {
210                 kprintf("xop_nresolve: NULL parent\n");
211                 chain = NULL;
212                 error = EIO;
213                 goto done;
214         }
215
216         /*
217          * Lookup all possibly conflicting directory entries, the feed
218          * inherits the chain's lock so do not unlock it on the iteration.
219          */
220         chain = hammer2_chain_lookup(&parent, &key_next,
221                                      xop->lhc,
222                                      xop->lhc + HAMMER2_DIRHASH_LOMASK,
223                                      &cache_index,
224                                      HAMMER2_LOOKUP_ALWAYS |
225                                      HAMMER2_LOOKUP_SHARED);
226         while (chain) {
227                 error = hammer2_xop_feed(&xop->head, chain, clindex,
228                                          chain->error);
229                 if (error) {
230                         hammer2_chain_drop(chain);
231                         chain = NULL;   /* safety */
232                         break;
233                 }
234                 chain = hammer2_chain_next(&parent, chain, &key_next,
235                                            key_next,
236                                            xop->lhc + HAMMER2_DIRHASH_LOMASK,
237                                            &cache_index,
238                                            HAMMER2_LOOKUP_ALWAYS |
239                                            HAMMER2_LOOKUP_SHARED |
240                                            HAMMER2_LOOKUP_NOUNLOCK);
241         }
242 done:
243         hammer2_xop_feed(&xop->head, NULL, clindex, error);
244         if (parent) {
245                 hammer2_chain_unlock(parent);
246                 hammer2_chain_drop(parent);
247         }
248 }