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