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