6c19f26e4015ead3b5e6942689508b2893661d70
[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 /*
64  * Determine if the specified directory is empty.  Returns 0 on success.
65  *
66  * May return 0, ENOTDIR, or EAGAIN.
67  */
68 static
69 int
70 checkdirempty(hammer2_chain_t *oparent, hammer2_chain_t *ochain, int clindex)
71 {
72         hammer2_chain_t *parent;
73         hammer2_chain_t *chain;
74         hammer2_key_t key_next;
75         hammer2_key_t inum;
76         int cache_index = -1;
77         int error;
78
79         error = 0;
80         chain = hammer2_chain_lookup_init(ochain, 0);
81
82         if (chain->bref.type == HAMMER2_BREF_TYPE_DIRENT) {
83                 if (oparent)
84                         hammer2_chain_unlock(oparent);
85                 inum = chain->bref.embed.dirent.inum;
86                 parent = NULL;
87                 error = hammer2_chain_inode_find(chain->pmp, inum,
88                                                  clindex, 0,
89                                                  &parent, &chain);
90                 if (parent) {
91                         hammer2_chain_unlock(parent);
92                         hammer2_chain_drop(parent);
93                 }
94                 if (oparent) {
95                         hammer2_chain_lock(oparent, HAMMER2_RESOLVE_ALWAYS);
96                         if (ochain->parent != oparent) {
97                                 if (chain) {
98                                         hammer2_chain_unlock(chain);
99                                         hammer2_chain_drop(chain);
100                                 }
101                                 kprintf("H2EAGAIN\n");
102
103                                 return EAGAIN;
104                         }
105                 }
106         }
107
108         /*
109          * Determine if the directory is empty or not by checking its
110          * visible namespace (the area which contains directory entries).
111          */
112         parent = chain;
113         chain = NULL;
114         if (parent) {
115                 chain = hammer2_chain_lookup(&parent, &key_next,
116                                              HAMMER2_DIRHASH_VISIBLE,
117                                              HAMMER2_KEY_MAX,
118                                              &cache_index, 0);
119         }
120         if (chain) {
121                 error = ENOTEMPTY;
122                 hammer2_chain_unlock(chain);
123                 hammer2_chain_drop(chain);
124         } else {
125                 error = 0;
126         }
127         hammer2_chain_lookup_done(parent);
128
129         return error;
130 }
131
132 /*
133  * Backend for hammer2_vfs_root()
134  *
135  * This is called when a newly mounted PFS has not yet synchronized
136  * to the inode_tid and modify_tid.
137  */
138 void
139 hammer2_xop_ipcluster(hammer2_thread_t *thr, hammer2_xop_t *arg)
140 {
141         hammer2_xop_ipcluster_t *xop = &arg->xop_ipcluster;
142         hammer2_chain_t *chain;
143         int error;
144
145         chain = hammer2_inode_chain(xop->head.ip1, thr->clindex,
146                                     HAMMER2_RESOLVE_ALWAYS |
147                                     HAMMER2_RESOLVE_SHARED);
148         if (chain)
149                 error = chain->error;
150         else
151                 error = EIO;
152                 
153         hammer2_xop_feed(&xop->head, chain, thr->clindex, error);
154         if (chain) {
155                 hammer2_chain_unlock(chain);
156                 hammer2_chain_drop(chain);
157         }
158 }
159
160 /*
161  * Backend for hammer2_vop_readdir()
162  */
163 void
164 hammer2_xop_readdir(hammer2_thread_t *thr, hammer2_xop_t *arg)
165 {
166         hammer2_xop_readdir_t *xop = &arg->xop_readdir;
167         hammer2_chain_t *parent;
168         hammer2_chain_t *chain;
169         hammer2_key_t key_next;
170         hammer2_key_t lkey;
171         int cache_index = -1;
172         int error = 0;
173
174         lkey = xop->lkey;
175         if (hammer2_debug & 0x0020)
176                 kprintf("xop_readdir %p lkey=%016jx\n", xop, lkey);
177
178         /*
179          * The inode's chain is the iterator.  If we cannot acquire it our
180          * contribution ends here.
181          */
182         parent = hammer2_inode_chain(xop->head.ip1, thr->clindex,
183                                      HAMMER2_RESOLVE_ALWAYS |
184                                      HAMMER2_RESOLVE_SHARED);
185         if (parent == NULL) {
186                 kprintf("xop_readdir: NULL parent\n");
187                 goto done;
188         }
189
190         /*
191          * Directory scan [re]start and loop, the feed inherits the chain's
192          * lock so do not unlock it on the iteration.
193          */
194         chain = hammer2_chain_lookup(&parent, &key_next, lkey, lkey,
195                                      &cache_index, HAMMER2_LOOKUP_SHARED);
196         if (chain == NULL) {
197                 chain = hammer2_chain_lookup(&parent, &key_next,
198                                              lkey, HAMMER2_KEY_MAX,
199                                              &cache_index,
200                                              HAMMER2_LOOKUP_SHARED);
201         }
202         while (chain) {
203                 error = hammer2_xop_feed(&xop->head, chain, thr->clindex, 0);
204                 if (error)
205                         break;
206                 chain = hammer2_chain_next(&parent, chain, &key_next,
207                                            key_next, HAMMER2_KEY_MAX,
208                                            &cache_index,
209                                            HAMMER2_LOOKUP_SHARED);
210         }
211         if (chain) {
212                 hammer2_chain_unlock(chain);
213                 hammer2_chain_drop(chain);
214         }
215         hammer2_chain_unlock(parent);
216         hammer2_chain_drop(parent);
217 done:
218         hammer2_xop_feed(&xop->head, NULL, thr->clindex, error);
219 }
220
221 /*
222  * Backend for hammer2_vop_nresolve()
223  */
224 void
225 hammer2_xop_nresolve(hammer2_thread_t *thr, hammer2_xop_t *arg)
226 {
227         hammer2_xop_nresolve_t *xop = &arg->xop_nresolve;
228         hammer2_chain_t *parent;
229         hammer2_chain_t *chain;
230         const char *name;
231         size_t name_len;
232         hammer2_key_t key_next;
233         hammer2_key_t lhc;
234         int cache_index = -1;   /* XXX */
235         int error;
236
237         parent = hammer2_inode_chain(xop->head.ip1, thr->clindex,
238                                      HAMMER2_RESOLVE_ALWAYS |
239                                      HAMMER2_RESOLVE_SHARED);
240         if (parent == NULL) {
241                 kprintf("xop_nresolve: NULL parent\n");
242                 chain = NULL;
243                 error = EIO;
244                 goto done;
245         }
246         name = xop->head.name1;
247         name_len = xop->head.name1_len;
248
249         /*
250          * Lookup the directory entry
251          */
252         lhc = hammer2_dirhash(name, name_len);
253         chain = hammer2_chain_lookup(&parent, &key_next,
254                                      lhc, lhc + HAMMER2_DIRHASH_LOMASK,
255                                      &cache_index,
256                                      HAMMER2_LOOKUP_ALWAYS |
257                                      HAMMER2_LOOKUP_SHARED);
258         while (chain) {
259                 if (hammer2_chain_dirent_test(chain, name, name_len))
260                         break;
261                 chain = hammer2_chain_next(&parent, chain, &key_next,
262                                            key_next,
263                                            lhc + HAMMER2_DIRHASH_LOMASK,
264                                            &cache_index,
265                                            HAMMER2_LOOKUP_ALWAYS |
266                                            HAMMER2_LOOKUP_SHARED);
267         }
268
269         /*
270          * If the entry is a hardlink pointer, resolve it.
271          */
272         error = 0;
273         if (chain) {
274                 if (chain->bref.type == HAMMER2_BREF_TYPE_DIRENT) {
275                         lhc = chain->bref.embed.dirent.inum;
276                         error = hammer2_chain_inode_find(chain->pmp,
277                                                          lhc,
278                                                          thr->clindex,
279                                                          HAMMER2_LOOKUP_SHARED,
280                                                          &parent,
281                                                          &chain);
282                 }
283         }
284 done:
285         error = hammer2_xop_feed(&xop->head, chain, thr->clindex, error);
286         if (chain) {
287                 hammer2_chain_unlock(chain);
288                 hammer2_chain_drop(chain);
289         }
290         if (parent) {
291                 hammer2_chain_unlock(parent);
292                 hammer2_chain_drop(parent);
293         }
294 }
295
296 /*
297  * Backend for hammer2_vop_nremove(), hammer2_vop_nrmdir(), and
298  * backend for pfs_delete.
299  *
300  * This function locates and removes a directory entry, and will lookup
301  * and return the underlying inode.  For directory entries the underlying
302  * inode is not removed.  If the directory entry is the actual inode itself,
303  * it may be conditonally removed and returned.
304  *
305  * WARNING!  Any target inode's nlinks may not be synchronized to the
306  *           in-memory inode.  The frontend's hammer2_inode_unlink_finisher()
307  *           is responsible for the final disposition of the actual inode.
308  */
309 void
310 hammer2_xop_unlink(hammer2_thread_t *thr, hammer2_xop_t *arg)
311 {
312         hammer2_xop_unlink_t *xop = &arg->xop_unlink;
313         hammer2_chain_t *parent;
314         hammer2_chain_t *chain;
315         const char *name;
316         size_t name_len;
317         hammer2_key_t key_next;
318         hammer2_key_t lhc;
319         int cache_index = -1;   /* XXX */
320         int error;
321
322 again:
323         /*
324          * Requires exclusive lock
325          */
326         parent = hammer2_inode_chain(xop->head.ip1, thr->clindex,
327                                      HAMMER2_RESOLVE_ALWAYS);
328         chain = NULL;
329         if (parent == NULL) {
330                 kprintf("xop_nresolve: NULL parent\n");
331                 error = EIO;
332                 goto done;
333         }
334         name = xop->head.name1;
335         name_len = xop->head.name1_len;
336
337         /*
338          * Lookup the directory entry
339          */
340         lhc = hammer2_dirhash(name, name_len);
341         chain = hammer2_chain_lookup(&parent, &key_next,
342                                      lhc, lhc + HAMMER2_DIRHASH_LOMASK,
343                                      &cache_index,
344                                      HAMMER2_LOOKUP_ALWAYS);
345         while (chain) {
346                 if (hammer2_chain_dirent_test(chain, name, name_len))
347                         break;
348                 chain = hammer2_chain_next(&parent, chain, &key_next,
349                                            key_next,
350                                            lhc + HAMMER2_DIRHASH_LOMASK,
351                                            &cache_index,
352                                            HAMMER2_LOOKUP_ALWAYS);
353         }
354
355         /*
356          * The directory entry will either be a BREF_TYPE_DIRENT or a
357          * BREF_TYPE_INODE.  We always permanently delete DIRENTs, but
358          * must go by xop->dopermanent for BREF_TYPE_INODE.
359          *
360          * Note that the target chain's nlinks may not be synchronized with
361          * the in-memory hammer2_inode_t structure, so we don't try to do
362          * anything fancy here.  The frontend deals with nlinks
363          * synchronization.
364          */
365         error = 0;
366         if (chain) {
367                 int dopermanent = xop->dopermanent & 1;
368                 int doforce = xop->dopermanent & 2;
369                 uint8_t type;
370
371                 /*
372                  * If the directory entry is the actual inode then use its
373                  * type for the directory typing tests, otherwise if it is
374                  * a directory entry, pull the type field from the entry.
375                  *
376                  * Directory entries are always permanently deleted
377                  * (because they aren't the actual inode).
378                  */
379                 if (chain->bref.type == HAMMER2_BREF_TYPE_DIRENT) {
380                         type = chain->bref.embed.dirent.type;
381                         dopermanent |= HAMMER2_DELETE_PERMANENT;
382                 } else {
383                         type = chain->data->ipdata.meta.type;
384                 }
385
386                 /*
387                  * Check directory typing and delete the entry.  Note that
388                  * nlinks adjustments are made on the real inode by the
389                  * frontend, not here.
390                  *
391                  * Unfortunately, checkdirempty() may have to unlock (parent).
392                  * If it no longer matches chain->parent after re-locking,
393                  * EAGAIN is returned.
394                  */
395                 if (type == HAMMER2_OBJTYPE_DIRECTORY && doforce) {
396                         /*
397                          * If doforce then execute the operation even if
398                          * the directory is not empty.
399                          */
400                         error = chain->error;
401                         hammer2_chain_delete(parent, chain,
402                                              xop->head.mtid, dopermanent);
403                 } else if (type == HAMMER2_OBJTYPE_DIRECTORY &&
404                            (error = checkdirempty(parent, chain, thr->clindex)) != 0) {
405                         /*
406                          * error may be EAGAIN or ENOTEMPTY
407                          */
408                         if (error == EAGAIN) {
409                                 hammer2_chain_unlock(chain);
410                                 hammer2_chain_drop(chain);
411                                 hammer2_chain_unlock(parent);
412                                 hammer2_chain_drop(parent);
413                                 goto again;
414                         }
415                 } else if (type == HAMMER2_OBJTYPE_DIRECTORY &&
416                     xop->isdir == 0) {
417                         error = ENOTDIR;
418                 } else if (type != HAMMER2_OBJTYPE_DIRECTORY &&
419                            xop->isdir >= 1) {
420                         error = EISDIR;
421                 } else {
422                         /*
423                          * Delete the directory entry.  chain might also
424                          * be a directly-embedded inode.
425                          */
426                         error = chain->error;
427                         hammer2_chain_delete(parent, chain,
428                                              xop->head.mtid, dopermanent);
429                 }
430         }
431
432         /*
433          * If chain is a directory entry we must resolve it.  We do not try
434          * to manipulate the contents as it might not be synchronized with
435          * the frontend hammer2_inode_t, nor do we try to lookup the
436          * frontend hammer2_inode_t here (we are the backend!).
437          */
438         if (chain && chain->bref.type == HAMMER2_BREF_TYPE_DIRENT) {
439                 int error2;
440
441                 lhc = chain->bref.embed.dirent.inum;
442
443                 error2 = hammer2_chain_inode_find(chain->pmp, lhc,
444                                                   thr->clindex, 0,
445                                                   &parent, &chain);
446                 if (error2) {
447                         kprintf("inode_find: %016jx %p failed\n",
448                                 lhc, chain);
449                         error2 = 0;     /* silently ignore */
450                 }
451                 if (error == 0)
452                         error = error2;
453         }
454
455         /*
456          * Return the inode target for further action.  Typically used by
457          * hammer2_inode_unlink_finisher().
458          */
459 done:
460         hammer2_xop_feed(&xop->head, chain, thr->clindex, error);
461         if (chain) {
462                 hammer2_chain_unlock(chain);
463                 hammer2_chain_drop(chain);
464                 chain = NULL;
465         }
466         if (parent) {
467                 hammer2_chain_unlock(parent);
468                 hammer2_chain_drop(parent);
469                 parent = NULL;
470         }
471 }
472
473 /*
474  * Backend for hammer2_vop_nrename()
475  *
476  * This handles the backend rename operation.  Typically this renames
477  * directory entries but can also be used to rename embedded inodes.
478  *
479  * NOTE! The frontend is responsible for updating the inode meta-data in
480  *       the file being renamed and for decrementing the target-replaced
481  *       inode's nlinks, if present.
482  */
483 void
484 hammer2_xop_nrename(hammer2_thread_t *thr, hammer2_xop_t *arg)
485 {
486         hammer2_xop_nrename_t *xop = &arg->xop_nrename;
487         hammer2_pfs_t *pmp;
488         hammer2_chain_t *parent;
489         hammer2_chain_t *chain;
490         hammer2_chain_t *tmp;
491         hammer2_inode_t *ip;
492         hammer2_key_t key_next;
493         int cache_index = -1;
494         int error;
495
496         /*
497          * We need the precise parent chain to issue the deletion.
498          *
499          * If this is a directory entry we must locate the underlying
500          * inode.  If it is an embedded inode we can act directly on it.
501          */
502         ip = xop->head.ip2;
503         pmp = ip->pmp;
504         chain = NULL;
505
506         if (xop->ip_key & HAMMER2_DIRHASH_VISIBLE) {
507                 /*
508                  * Find ip's direct parent chain.
509                  */
510                 parent = hammer2_inode_chain(ip, thr->clindex,
511                                              HAMMER2_RESOLVE_ALWAYS);
512                 if (parent)
513                         hammer2_chain_getparent(&parent,
514                                                 HAMMER2_RESOLVE_ALWAYS);
515                 if (parent == NULL) {
516                         error = EIO;
517                         goto done;
518                 }
519                 chain = hammer2_inode_chain(ip, thr->clindex,
520                                             HAMMER2_RESOLVE_ALWAYS);
521                 if (chain == NULL) {
522                         error = EIO;
523                         goto done;
524                 }
525         } else {
526                 /*
527                  * The directory entry for the head.ip1 inode
528                  * is in fdip, do a namespace search.
529                  */
530                 hammer2_key_t lhc;
531                 const char *name;
532                 size_t name_len;
533
534                 parent = hammer2_inode_chain(xop->head.ip1, thr->clindex,
535                                              HAMMER2_RESOLVE_ALWAYS);
536                 if (parent == NULL) {
537                         kprintf("xop_nrename: NULL parent\n");
538                         error = EIO;
539                         goto done;
540                 }
541                 name = xop->head.name1;
542                 name_len = xop->head.name1_len;
543
544                 /*
545                  * Lookup the directory entry
546                  */
547                 lhc = hammer2_dirhash(name, name_len);
548                 chain = hammer2_chain_lookup(&parent, &key_next,
549                                              lhc, lhc + HAMMER2_DIRHASH_LOMASK,
550                                              &cache_index,
551                                              HAMMER2_LOOKUP_ALWAYS);
552                 while (chain) {
553                         if (hammer2_chain_dirent_test(chain, name, name_len))
554                                 break;
555                         chain = hammer2_chain_next(&parent, chain, &key_next,
556                                                    key_next,
557                                                    lhc + HAMMER2_DIRHASH_LOMASK,
558                                                    &cache_index,
559                                                    HAMMER2_LOOKUP_ALWAYS);
560                 }
561         }
562
563         if (chain == NULL) {
564                 /* XXX shouldn't happen, but does under fsstress */
565                 kprintf("hammer2_xop_rename: \"%s\" -> \"%s\"  ENOENT\n",
566                         xop->head.name1,
567                         xop->head.name2);
568                 error = ENOENT;
569                 goto done;
570         }
571
572         /*
573          * Delete it, then create it in the new namespace.
574          */
575         hammer2_chain_delete(parent, chain, xop->head.mtid, 0);
576         hammer2_chain_unlock(parent);
577         hammer2_chain_drop(parent);
578         parent = NULL;          /* safety */
579
580         /*
581          * Adjust fields in the deleted chain appropriate for the rename
582          * operation.
583          *
584          * NOTE! For embedded inodes, the frontend will officially replicate
585          *       the field adjustments, but we also do it here to maintain
586          *       consistency in case of a crash.
587          */
588         if (chain->bref.key != xop->lhc ||
589             xop->head.name1_len != xop->head.name2_len ||
590             bcmp(xop->head.name1, xop->head.name2, xop->head.name1_len) != 0) {
591                 if (chain->bref.type == HAMMER2_BREF_TYPE_INODE) {
592                         hammer2_inode_data_t *wipdata;
593
594                         hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
595                         wipdata = &chain->data->ipdata;
596
597                         bzero(wipdata->filename, sizeof(wipdata->filename));
598                         bcopy(xop->head.name2, wipdata->filename,
599                               xop->head.name2_len);
600                         wipdata->meta.name_key = xop->lhc;
601                         wipdata->meta.name_len = xop->head.name2_len;
602                 }
603                 if (chain->bref.type == HAMMER2_BREF_TYPE_DIRENT) {
604                         if (xop->head.name2_len <= sizeof(chain->bref.check.buf)) {
605                                 /*
606                                  * Remove any related data buffer, we can
607                                  * embed the filename in the bref itself.
608                                  */
609                                 hammer2_chain_resize(chain, xop->head.mtid, 0,
610                                                      0, 0);
611                                 hammer2_chain_modify(chain, xop->head.mtid,
612                                                      0, 0);
613                                 bzero(chain->bref.check.buf,
614                                       sizeof(chain->bref.check.buf));
615                                 bcopy(xop->head.name2, chain->bref.check.buf,
616                                       xop->head.name2_len);
617                         } else {
618                                 /*
619                                  * Associate a data buffer with the bref.
620                                  * Zero it for consistency.  Note that the
621                                  * data buffer is not 64KB so use chain->bytes
622                                  * instead of sizeof().
623                                  */
624                                 hammer2_chain_resize(chain, xop->head.mtid, 0,
625                                      hammer2_getradix(HAMMER2_ALLOC_MIN), 0);
626                                 hammer2_chain_modify(chain, xop->head.mtid,
627                                                      0, 0);
628                                 bzero(chain->data->buf, chain->bytes);
629                                 bcopy(xop->head.name2,
630                                       chain->data->buf,
631                                       xop->head.name2_len);
632                         }
633                         chain->bref.embed.dirent.namlen = xop->head.name2_len;
634                 }
635         }
636
637         /*
638          * The frontend will replicate this operation and is the real final
639          * authority, but adjust the inode's iparent field too if the inode
640          * is embedded in the directory.
641          */
642         if (chain->bref.type == HAMMER2_BREF_TYPE_INODE &&
643             chain->data->ipdata.meta.iparent != xop->head.ip3->meta.inum) {
644                 hammer2_inode_data_t *wipdata;
645
646                 hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
647                 wipdata = &chain->data->ipdata;
648
649                 wipdata->meta.iparent = xop->head.ip3->meta.inum;
650         }
651
652         /*
653          * Destroy any matching target(s) before creating the new entry.
654          * This will result in some ping-ponging of the directory key
655          * iterator but that is ok.
656          */
657         parent = hammer2_inode_chain(xop->head.ip3, thr->clindex,
658                                      HAMMER2_RESOLVE_ALWAYS);
659         if (parent == NULL) {
660                 error = EIO;
661                 goto done;
662         }
663
664         tmp = hammer2_chain_lookup(&parent, &key_next,
665                                    xop->lhc & ~HAMMER2_DIRHASH_LOMASK,
666                                    xop->lhc | HAMMER2_DIRHASH_LOMASK,
667                                    &cache_index,
668                                    HAMMER2_LOOKUP_ALWAYS);
669         while (tmp) {
670                 if (hammer2_chain_dirent_test(tmp, xop->head.name2,
671                                               xop->head.name2_len)) {
672                         hammer2_chain_delete(parent, tmp, xop->head.mtid, 0);
673                 }
674                 tmp = hammer2_chain_next(&parent, tmp, &key_next,
675                                          key_next,
676                                          xop->lhc | HAMMER2_DIRHASH_LOMASK,
677                                          &cache_index,
678                                          HAMMER2_LOOKUP_ALWAYS);
679         }
680
681         /*
682          * A relookup is required before the create to properly position
683          * the parent chain.
684          */
685         tmp = hammer2_chain_lookup(&parent, &key_next,
686                                    xop->lhc, xop->lhc,
687                                    &cache_index, 0);
688         KKASSERT(tmp == NULL);
689         error = hammer2_chain_create(&parent, &chain,
690                                      pmp, HAMMER2_METH_DEFAULT,
691                                      xop->lhc, 0,
692                                      HAMMER2_BREF_TYPE_INODE,
693                                      HAMMER2_INODE_BYTES,
694                                      xop->head.mtid, 0, 0);
695 done:
696         hammer2_xop_feed(&xop->head, NULL, thr->clindex, error);
697         if (parent) {
698                 hammer2_chain_unlock(parent);
699                 hammer2_chain_drop(parent);
700         }
701         if (chain) {
702                 hammer2_chain_unlock(chain);
703                 hammer2_chain_drop(chain);
704         }
705 }
706
707 /*
708  * Directory collision resolver scan helper (backend, threaded).
709  *
710  * Used by the inode create code to locate an unused lhc.
711  */
712 void
713 hammer2_xop_scanlhc(hammer2_thread_t *thr, hammer2_xop_t *arg)
714 {
715         hammer2_xop_scanlhc_t *xop = &arg->xop_scanlhc;
716         hammer2_chain_t *parent;
717         hammer2_chain_t *chain;
718         hammer2_key_t key_next;
719         int cache_index = -1;   /* XXX */
720         int error = 0;
721
722         parent = hammer2_inode_chain(xop->head.ip1, thr->clindex,
723                                      HAMMER2_RESOLVE_ALWAYS |
724                                      HAMMER2_RESOLVE_SHARED);
725         if (parent == NULL) {
726                 kprintf("xop_nresolve: NULL parent\n");
727                 chain = NULL;
728                 error = EIO;
729                 goto done;
730         }
731
732         /*
733          * Lookup all possibly conflicting directory entries, the feed
734          * inherits the chain's lock so do not unlock it on the iteration.
735          */
736         chain = hammer2_chain_lookup(&parent, &key_next,
737                                      xop->lhc,
738                                      xop->lhc + HAMMER2_DIRHASH_LOMASK,
739                                      &cache_index,
740                                      HAMMER2_LOOKUP_ALWAYS |
741                                      HAMMER2_LOOKUP_SHARED);
742         while (chain) {
743                 error = hammer2_xop_feed(&xop->head, chain, thr->clindex,
744                                          chain->error);
745                 if (error) {
746                         hammer2_chain_unlock(chain);
747                         hammer2_chain_drop(chain);
748                         chain = NULL;   /* safety */
749                         break;
750                 }
751                 chain = hammer2_chain_next(&parent, chain, &key_next,
752                                            key_next,
753                                            xop->lhc + HAMMER2_DIRHASH_LOMASK,
754                                            &cache_index,
755                                            HAMMER2_LOOKUP_ALWAYS |
756                                            HAMMER2_LOOKUP_SHARED);
757         }
758 done:
759         hammer2_xop_feed(&xop->head, NULL, thr->clindex, error);
760         if (parent) {
761                 hammer2_chain_unlock(parent);
762                 hammer2_chain_drop(parent);
763         }
764 }
765
766 /*
767  * Generic lookup of a specific key.
768  *
769  * Used by the inode hidden directory code to find the hidden directory.
770  */
771 void
772 hammer2_xop_lookup(hammer2_thread_t *thr, hammer2_xop_t *arg)
773 {
774         hammer2_xop_scanlhc_t *xop = &arg->xop_scanlhc;
775         hammer2_chain_t *parent;
776         hammer2_chain_t *chain;
777         hammer2_key_t key_next;
778         int cache_index = -1;   /* XXX */
779         int error = 0;
780
781         parent = hammer2_inode_chain(xop->head.ip1, thr->clindex,
782                                      HAMMER2_RESOLVE_ALWAYS |
783                                      HAMMER2_RESOLVE_SHARED);
784         chain = NULL;
785         if (parent == NULL) {
786                 error = EIO;
787                 goto done;
788         }
789
790         /*
791          * Lookup all possibly conflicting directory entries, the feed
792          * inherits the chain's lock so do not unlock it on the iteration.
793          */
794         chain = hammer2_chain_lookup(&parent, &key_next,
795                                      xop->lhc, xop->lhc,
796                                      &cache_index,
797                                      HAMMER2_LOOKUP_ALWAYS |
798                                      HAMMER2_LOOKUP_SHARED);
799         if (chain)
800                 hammer2_xop_feed(&xop->head, chain, thr->clindex, chain->error);
801         else
802                 hammer2_xop_feed(&xop->head, NULL, thr->clindex, ENOENT);
803
804 done:
805         if (chain) {
806                 hammer2_chain_unlock(chain);
807                 hammer2_chain_drop(chain);
808         }
809         if (parent) {
810                 hammer2_chain_unlock(parent);
811                 hammer2_chain_drop(parent);
812         }
813 }
814
815 /*
816  * Generic scan
817  *
818  * WARNING! Fed chains must be locked shared so ownership can be transfered
819  *          and to prevent frontend/backend stalls that would occur with an
820  *          exclusive lock.  The shared lock also allows chain->data to be
821  *          retained.
822  */
823 void
824 hammer2_xop_scanall(hammer2_thread_t *thr, hammer2_xop_t *arg)
825 {
826         hammer2_xop_scanall_t *xop = &arg->xop_scanall;
827         hammer2_chain_t *parent;
828         hammer2_chain_t *chain;
829         hammer2_key_t key_next;
830         int cache_index = -1;
831         int error = 0;
832
833         /*
834          * Assert required flags.
835          */
836         KKASSERT(xop->resolve_flags & HAMMER2_RESOLVE_SHARED);
837         KKASSERT(xop->lookup_flags & HAMMER2_LOOKUP_SHARED);
838
839         /*
840          * The inode's chain is the iterator.  If we cannot acquire it our
841          * contribution ends here.
842          */
843         parent = hammer2_inode_chain(xop->head.ip1, thr->clindex,
844                                      xop->resolve_flags);
845         if (parent == NULL) {
846                 kprintf("xop_readdir: NULL parent\n");
847                 goto done;
848         }
849
850         /*
851          * Generic scan of exact records.  Note that indirect blocks are
852          * automatically recursed and will not be returned.
853          */
854         chain = hammer2_chain_lookup(&parent, &key_next,
855                                      xop->key_beg, xop->key_end,
856                                      &cache_index, xop->lookup_flags);
857         while (chain) {
858                 error = hammer2_xop_feed(&xop->head, chain, thr->clindex, 0);
859                 if (error)
860                         break;
861                 chain = hammer2_chain_next(&parent, chain, &key_next,
862                                            key_next, xop->key_end,
863                                            &cache_index, xop->lookup_flags);
864         }
865         if (chain) {
866                 hammer2_chain_unlock(chain);
867                 hammer2_chain_drop(chain);
868         }
869         hammer2_chain_unlock(parent);
870         hammer2_chain_drop(parent);
871 done:
872         hammer2_xop_feed(&xop->head, NULL, thr->clindex, error);
873 }