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