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