xref: /dflybsd-src/sys/vfs/hammer2/hammer2_xops.c (revision e586f31ca9899b49a4fc156613d9ecd853defcec)
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_thread_t *thr, hammer2_xop_t *arg)
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, thr->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, thr->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_thread_t *thr, hammer2_xop_t *arg)
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, thr->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, thr->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, thr->clindex, error);
213 }
214 
215 /*
216  * Backend for hammer2_vop_nresolve()
217  */
218 void
219 hammer2_xop_nresolve(hammer2_thread_t *thr, hammer2_xop_t *arg)
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, thr->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 							    thr->clindex,
276 							HAMMER2_LOOKUP_SHARED);
277 		}
278 	}
279 done:
280 	error = hammer2_xop_feed(&xop->head, chain, thr->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(), helper
293  * for hammer2_vop_nrename(), and backend for pfs_delete.
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_thread_t *thr, hammer2_xop_t *arg)
311 {
312 	hammer2_xop_unlink_t *xop = &arg->xop_unlink;
313 	hammer2_chain_t *parent;
314 	hammer2_chain_t *chain;
315 	const 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, thr->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 & 1;
370 		int doforce = xop->dopermanent & 2;
371 		uint8_t type;
372 
373 		/*
374 		 * If the directory entry is the actual inode then use its
375 		 * type for the directory typing tests, otherwise if it is
376 		 * a hardlink pointer then use the secondary type field for
377 		 * directory typing tests.
378 		 *
379 		 * Also, hardlink pointers are always permanently deleted
380 		 * (because they aren't the actual inode).
381 		 */
382 		type = chain->data->ipdata.meta.type;
383 		if (type == HAMMER2_OBJTYPE_HARDLINK) {
384 			type = chain->data->ipdata.meta.target_type;
385 			dopermanent |= HAMMER2_DELETE_PERMANENT;
386 		}
387 
388 		/*
389 		 * Check directory typing and delete the entry.  Note that
390 		 * nlinks adjustments are made on the real inode by the
391 		 * frontend, not here.
392 		 *
393 		 * Unfortunately, checkdirempty() may have to unlock (parent).
394 		 * If it no longer matches chain->parent after re-locking,
395 		 * EAGAIN is returned.
396 		 */
397 		if (type == HAMMER2_OBJTYPE_DIRECTORY && doforce) {
398 			/*
399 			 * If doforce then execute the operation even if
400 			 * the directory is not empty.
401 			 */
402 			error = chain->error;
403 			hammer2_chain_delete(parent, chain,
404 					     xop->head.mtid, dopermanent);
405 		} else if (type == HAMMER2_OBJTYPE_DIRECTORY &&
406 			   (error = checkdirempty(parent, chain, thr->clindex)) != 0) {
407 			/*
408 			 * error may be EAGAIN or ENOTEMPTY
409 			 */
410 			if (error == EAGAIN) {
411 				hammer2_chain_unlock(chain);
412 				hammer2_chain_drop(chain);
413 				hammer2_chain_unlock(parent);
414 				hammer2_chain_drop(parent);
415 				goto again;
416 			}
417 		} else if (type == HAMMER2_OBJTYPE_DIRECTORY &&
418 		    xop->isdir == 0) {
419 			error = ENOTDIR;
420 		} else if (type != HAMMER2_OBJTYPE_DIRECTORY &&
421 			   xop->isdir >= 1) {
422 			error = EISDIR;
423 		} else {
424 			/*
425 			 * This deletes the directory entry itself, which is
426 			 * also the inode when nlinks == 1.  Hardlink targets
427 			 * are handled in the next conditional.
428 			 */
429 			error = chain->error;
430 			hammer2_chain_delete(parent, chain,
431 					     xop->head.mtid, dopermanent);
432 		}
433 	}
434 
435 	/*
436 	 * If the entry is a hardlink pointer, resolve it.  We do not try
437 	 * to manipulate the contents of the hardlink target as it might
438 	 * not be synchronized with the front-end hammer2_inode_t.  Nor do
439 	 * we try to lookup the front-end hammer2_inode_t here (we are the
440 	 * backend!).
441 	 */
442 	if (chain &&
443 	    chain->data->ipdata.meta.type == HAMMER2_OBJTYPE_HARDLINK) {
444 		int error2;
445 
446 		lhc = chain->data->ipdata.meta.inum;
447 
448 		error2 = hammer2_chain_hardlink_find(&parent, &chain,
449 						     thr->clindex, 0);
450 		if (error2) {
451 			kprintf("hardlink_find: %016jx %p failed\n",
452 				lhc, chain);
453 			error2 = 0;	/* silently ignore */
454 		}
455 		if (error == 0)
456 			error = error2;
457 	}
458 
459 	/*
460 	 * Return the inode target for further action.  Typically used by
461 	 * hammer2_inode_unlink_finisher().
462 	 */
463 done:
464 	hammer2_xop_feed(&xop->head, chain, thr->clindex, error);
465 	if (chain) {
466 		hammer2_chain_unlock(chain);
467 		hammer2_chain_drop(chain);
468 		chain = NULL;
469 	}
470 	if (parent) {
471 		hammer2_chain_unlock(parent);
472 		hammer2_chain_drop(parent);
473 		parent = NULL;
474 	}
475 }
476 
477 #if 0
478 /*
479  * Backend for hammer2_vop_nlink() and hammer2_vop_nrename()
480  *
481  * ip1 - fdip
482  * ip2 - ip
483  * ip3 - cdip
484  *
485  * If a hardlink pointer:
486  *	The existing hardlink target {fdip,ip} must be moved to another
487  *	directory {cdip,ip}
488  *
489  * If not a hardlink pointer:
490  *	Convert the target {fdip,ip} to a hardlink target {cdip,ip} and
491  *	replace the original namespace {fdip,name} with a hardlink pointer.
492  */
493 void
494 hammer2_xop_nlink(hammer2_thread_t *thr, hammer2_xop_t *arg)
495 {
496 	hammer2_xop_nlink_t *xop = &arg->xop_nlink;
497 	hammer2_pfs_t *pmp;
498 	hammer2_inode_data_t *wipdata;
499 	hammer2_chain_t *parent;
500 	hammer2_chain_t *chain;
501 	hammer2_chain_t *tmp;
502 	hammer2_inode_t *ip;
503 	hammer2_key_t key_dummy;
504 	int cache_index = -1;
505 	int error;
506 	int did_delete = 0;
507 
508 	/*
509 	 * We need the precise parent chain to issue the deletion.
510 	 */
511 	ip = xop->head.ip2;
512 	pmp = ip->pmp;
513 	parent = hammer2_inode_chain(ip, thr->clindex, HAMMER2_RESOLVE_ALWAYS);
514 	if (parent)
515 		hammer2_chain_getparent(&parent, HAMMER2_RESOLVE_ALWAYS);
516 	if (parent == NULL) {
517 		chain = NULL;
518 		error = EIO;
519 		goto done;
520 	}
521 	chain = hammer2_inode_chain(ip, thr->clindex, HAMMER2_RESOLVE_ALWAYS);
522 	if (chain == NULL) {
523 		error = EIO;
524 		goto done;
525 	}
526 	KKASSERT(chain->parent == parent);
527 
528 	if (chain->data->ipdata.meta.name_key & HAMMER2_DIRHASH_VISIBLE) {
529 		/*
530 		 * Delete the original chain and hold onto it for the move
531 		 * to cdir.
532 		 *
533 		 * Replace the namespace with a hardlink pointer if the
534 		 * chain being moved is not already a hardlink target.
535 		 */
536 		hammer2_chain_delete(parent, chain, xop->head.mtid, 0);
537 		did_delete = 1;
538 
539 		tmp = NULL;
540 		error = hammer2_chain_create(&parent, &tmp,
541 					     pmp, HAMMER2_METH_DEFAULT,
542 					     chain->bref.key, 0,
543 					     HAMMER2_BREF_TYPE_INODE,
544 					     HAMMER2_INODE_BYTES,
545 					     xop->head.mtid, 0, 0);
546 		if (error)
547 			goto done;
548 		hammer2_chain_modify(tmp, xop->head.mtid, 0, 0);
549 		wipdata = &tmp->data->ipdata;
550 		bzero(wipdata, sizeof(*wipdata));
551 		wipdata->meta.name_key = chain->data->ipdata.meta.name_key;
552 		wipdata->meta.name_len = chain->data->ipdata.meta.name_len;
553 		bcopy(chain->data->ipdata.filename, wipdata->filename,
554 		      chain->data->ipdata.meta.name_len);
555 		wipdata->meta.target_type = chain->data->ipdata.meta.type;
556 		wipdata->meta.type = HAMMER2_OBJTYPE_HARDLINK;
557 		wipdata->meta.inum = ip->meta.inum;
558 		wipdata->meta.version = HAMMER2_INODE_VERSION_ONE;
559 		wipdata->meta.nlinks = 1;
560 		wipdata->meta.op_flags = HAMMER2_OPFLAG_DIRECTDATA;
561 
562 		hammer2_chain_unlock(tmp);
563 		hammer2_chain_drop(tmp);
564 	} else if (xop->head.ip1 != xop->head.ip3) {
565 		/*
566 		 * Delete the hardlink target so it can be moved
567 		 * to cdir.
568 		 */
569 		hammer2_chain_delete(parent, chain, xop->head.mtid, 0);
570 		did_delete = 1;
571 	} else {
572 		/*
573 		 * Deletion not necessary (just a nlinks update).
574 		 */
575 		did_delete = 0;
576 	}
577 
578 	hammer2_chain_unlock(parent);
579 	hammer2_chain_drop(parent);
580 	parent = NULL;
581 
582 	/*
583 	 * Ok, back to the deleted chain.  We must reconnect this chain
584 	 * as a hardlink target to cdir (ip3).
585 	 *
586 	 * WARNING! Frontend assumes filename length is 18 bytes.
587 	 */
588 	if (did_delete) {
589 		hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
590 		wipdata = &chain->data->ipdata;
591 		ksnprintf(wipdata->filename, sizeof(wipdata->filename),
592 			  "0x%016jx", (intmax_t)ip->meta.inum);
593 		wipdata->meta.name_len = strlen(wipdata->filename);
594 		wipdata->meta.name_key = ip->meta.inum;
595 
596 		/*
597 		 * We must seek parent properly for the create to reattach
598 		 * chain.  XXX just use chain->parent or
599 		 * inode_chain_and_parent() ?
600 		 */
601 		parent = hammer2_inode_chain(xop->head.ip3, thr->clindex,
602 					     HAMMER2_RESOLVE_ALWAYS);
603 		if (parent == NULL) {
604 			error = EIO;
605 			goto done;
606 		}
607 		tmp = hammer2_chain_lookup(&parent, &key_dummy,
608 					   ip->meta.inum, ip->meta.inum,
609 					   &cache_index, 0);
610 		if (tmp) {
611 			hammer2_chain_unlock(tmp);
612 			hammer2_chain_drop(tmp);
613 			error = EEXIST;
614 			goto done;
615 		}
616 		error = hammer2_chain_create(&parent, &chain,
617 					     pmp, HAMMER2_METH_DEFAULT,
618 					     wipdata->meta.name_key, 0,
619 					     HAMMER2_BREF_TYPE_INODE,
620 					     HAMMER2_INODE_BYTES,
621 					     xop->head.mtid, 0, 0);
622 	} else {
623 		error = 0;
624 	}
625 
626 	/*
627 	 * Bump nlinks to synchronize with frontend.
628 	 */
629 	if (xop->nlinks_delta) {
630 		hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
631 		chain->data->ipdata.meta.nlinks += xop->nlinks_delta;
632 	}
633 
634 	/*
635 	 * To avoid having to scan the collision space we can simply
636 	 * reuse the inode's original name_key.  But ip->meta.name_key
637 	 * may have already been updated by the front-end, so use xop->lhc.
638 	 */
639 done:
640 	hammer2_xop_feed(&xop->head, NULL, thr->clindex, error);
641 	if (parent) {
642 		hammer2_chain_unlock(parent);
643 		hammer2_chain_drop(parent);
644 	}
645 	if (chain) {
646 		hammer2_chain_unlock(chain);
647 		hammer2_chain_drop(chain);
648 	}
649 }
650 #endif
651 
652 /*
653  * Backend for hammer2_vop_nrename()
654  *
655  * This handles the final step of renaming, either renaming the
656  * actual inode or renaming the hardlink pointer.
657  */
658 void
659 hammer2_xop_nrename(hammer2_thread_t *thr, hammer2_xop_t *arg)
660 {
661 	hammer2_xop_nrename_t *xop = &arg->xop_nrename;
662 	hammer2_pfs_t *pmp;
663 	hammer2_chain_t *parent;
664 	hammer2_chain_t *chain;
665 	hammer2_chain_t *tmp;
666 	hammer2_inode_t *ip;
667 	hammer2_key_t key_dummy;
668 	int cache_index = -1;
669 	int error;
670 
671 	/*
672 	 * We need the precise parent chain to issue the deletion.
673 	 *
674 	 * If this is not a hardlink target we can act on the inode,
675 	 * otherwise we have to locate the hardlink pointer.
676 	 */
677 	ip = xop->head.ip2;
678 	pmp = ip->pmp;
679 	chain = NULL;
680 
681 	if (xop->ip_key & HAMMER2_DIRHASH_VISIBLE) {
682 		/*
683 		 * Find ip's direct parent chain.
684 		 */
685 		parent = hammer2_inode_chain(ip, thr->clindex,
686 					     HAMMER2_RESOLVE_ALWAYS);
687 		if (parent)
688 			hammer2_chain_getparent(&parent,
689 						HAMMER2_RESOLVE_ALWAYS);
690 		if (parent == NULL) {
691 			error = EIO;
692 			goto done;
693 		}
694 		chain = hammer2_inode_chain(ip, thr->clindex,
695 					    HAMMER2_RESOLVE_ALWAYS);
696 		if (chain == NULL) {
697 			error = EIO;
698 			goto done;
699 		}
700 	} else {
701 		/*
702 		 * The hardlink pointer for the head.ip1 hardlink target
703 		 * is in fdip, do a namespace search.
704 		 */
705 		const hammer2_inode_data_t *ripdata;
706 		hammer2_key_t lhc;
707 		hammer2_key_t key_next;
708 		const char *name;
709 		size_t name_len;
710 
711 		parent = hammer2_inode_chain(xop->head.ip1, thr->clindex,
712 					     HAMMER2_RESOLVE_ALWAYS);
713 		if (parent == NULL) {
714 			kprintf("xop_nrename: NULL parent\n");
715 			error = EIO;
716 			goto done;
717 		}
718 		name = xop->head.name1;
719 		name_len = xop->head.name1_len;
720 
721 		/*
722 		 * Lookup the directory entry
723 		 */
724 		lhc = hammer2_dirhash(name, name_len);
725 		chain = hammer2_chain_lookup(&parent, &key_next,
726 					     lhc, lhc + HAMMER2_DIRHASH_LOMASK,
727 					     &cache_index,
728 					     HAMMER2_LOOKUP_ALWAYS);
729 		while (chain) {
730 			ripdata = &chain->data->ipdata;
731 			if (chain->bref.type == HAMMER2_BREF_TYPE_INODE &&
732 			    ripdata->meta.name_len == name_len &&
733 			    bcmp(ripdata->filename, name, name_len) == 0) {
734 				break;
735 			}
736 			chain = hammer2_chain_next(&parent, chain, &key_next,
737 						   key_next,
738 						   lhc + HAMMER2_DIRHASH_LOMASK,
739 						   &cache_index,
740 						   HAMMER2_LOOKUP_ALWAYS);
741 		}
742 	}
743 
744 	if (chain == NULL) {
745 		/* XXX shouldn't happen, but does under fsstress */
746 		kprintf("hammer2_xop_rename: \"%s\" -> \"%s\"  ENOENT\n",
747 			xop->head.name1,
748 			xop->head.name2);
749 		error = ENOENT;
750 		goto done;
751 	}
752 
753 	/*
754 	 * Delete it, then create it in the new namespace.
755 	 */
756 	hammer2_chain_delete(parent, chain, xop->head.mtid, 0);
757 	hammer2_chain_unlock(parent);
758 	hammer2_chain_drop(parent);
759 	parent = NULL;		/* safety */
760 
761 	/*
762 	 * Ok, back to the deleted chain.  We must reconnect this chain
763 	 * to tdir (ip3).  The chain (a real inode or a hardlink pointer)
764 	 * is not otherwise modified.
765 	 *
766 	 * Frontend is expected to replicate the same inode meta data
767 	 * modifications.
768 	 *
769 	 * NOTE!  This chain may not represent the actual inode, it
770 	 *	  can be a hardlink pointer.
771 	 *
772 	 * XXX in-inode parent directory specification?
773 	 */
774 	if (chain->data->ipdata.meta.name_key != xop->lhc ||
775 	    xop->head.name1_len != xop->head.name2_len ||
776 	    bcmp(xop->head.name1, xop->head.name2, xop->head.name1_len) != 0) {
777 		hammer2_inode_data_t *wipdata;
778 
779 		hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
780 		wipdata = &chain->data->ipdata;
781 
782 		bzero(wipdata->filename, sizeof(wipdata->filename));
783 		bcopy(xop->head.name2, wipdata->filename, xop->head.name2_len);
784 		wipdata->meta.name_key = xop->lhc;
785 		wipdata->meta.name_len = xop->head.name2_len;
786 	}
787 	if (chain->data->ipdata.meta.iparent != xop->head.ip3->meta.inum) {
788 		hammer2_inode_data_t *wipdata;
789 
790 		hammer2_chain_modify(chain, xop->head.mtid, 0, 0);
791 		wipdata = &chain->data->ipdata;
792 
793 		wipdata->meta.iparent = xop->head.ip3->meta.inum;
794 	}
795 
796 	/*
797 	 * We must seek parent properly for the create.
798 	 */
799 	parent = hammer2_inode_chain(xop->head.ip3, thr->clindex,
800 				     HAMMER2_RESOLVE_ALWAYS);
801 	if (parent == NULL) {
802 		error = EIO;
803 		goto done;
804 	}
805 	tmp = hammer2_chain_lookup(&parent, &key_dummy,
806 				   xop->lhc, xop->lhc,
807 				   &cache_index, 0);
808 	if (tmp) {
809 		hammer2_chain_unlock(tmp);
810 		hammer2_chain_drop(tmp);
811 		error = EEXIST;
812 		goto done;
813 	}
814 
815 	error = hammer2_chain_create(&parent, &chain,
816 				     pmp, HAMMER2_METH_DEFAULT,
817 				     xop->lhc, 0,
818 				     HAMMER2_BREF_TYPE_INODE,
819 				     HAMMER2_INODE_BYTES,
820 				     xop->head.mtid, 0, 0);
821 done:
822 	hammer2_xop_feed(&xop->head, NULL, thr->clindex, error);
823 	if (parent) {
824 		hammer2_chain_unlock(parent);
825 		hammer2_chain_drop(parent);
826 	}
827 	if (chain) {
828 		hammer2_chain_unlock(chain);
829 		hammer2_chain_drop(chain);
830 	}
831 }
832 
833 /*
834  * Directory collision resolver scan helper (backend, threaded).
835  *
836  * Used by the inode create code to locate an unused lhc.
837  */
838 void
839 hammer2_xop_scanlhc(hammer2_thread_t *thr, hammer2_xop_t *arg)
840 {
841 	hammer2_xop_scanlhc_t *xop = &arg->xop_scanlhc;
842 	hammer2_chain_t *parent;
843 	hammer2_chain_t *chain;
844 	hammer2_key_t key_next;
845 	int cache_index = -1;	/* XXX */
846 	int error = 0;
847 
848 	parent = hammer2_inode_chain(xop->head.ip1, thr->clindex,
849 				     HAMMER2_RESOLVE_ALWAYS |
850 				     HAMMER2_RESOLVE_SHARED);
851 	if (parent == NULL) {
852 		kprintf("xop_nresolve: NULL parent\n");
853 		chain = NULL;
854 		error = EIO;
855 		goto done;
856 	}
857 
858 	/*
859 	 * Lookup all possibly conflicting directory entries, the feed
860 	 * inherits the chain's lock so do not unlock it on the iteration.
861 	 */
862 	chain = hammer2_chain_lookup(&parent, &key_next,
863 				     xop->lhc,
864 				     xop->lhc + HAMMER2_DIRHASH_LOMASK,
865 				     &cache_index,
866 				     HAMMER2_LOOKUP_ALWAYS |
867 				     HAMMER2_LOOKUP_SHARED);
868 	while (chain) {
869 		error = hammer2_xop_feed(&xop->head, chain, thr->clindex,
870 					 chain->error);
871 		if (error) {
872 			hammer2_chain_unlock(chain);
873 			hammer2_chain_drop(chain);
874 			chain = NULL;	/* safety */
875 			break;
876 		}
877 		chain = hammer2_chain_next(&parent, chain, &key_next,
878 					   key_next,
879 					   xop->lhc + HAMMER2_DIRHASH_LOMASK,
880 					   &cache_index,
881 					   HAMMER2_LOOKUP_ALWAYS |
882 					   HAMMER2_LOOKUP_SHARED);
883 	}
884 done:
885 	hammer2_xop_feed(&xop->head, NULL, thr->clindex, error);
886 	if (parent) {
887 		hammer2_chain_unlock(parent);
888 		hammer2_chain_drop(parent);
889 	}
890 }
891 
892 /*
893  * Generic lookup of a specific key.
894  *
895  * Used by the inode hidden directory code to find the hidden directory.
896  */
897 void
898 hammer2_xop_lookup(hammer2_thread_t *thr, hammer2_xop_t *arg)
899 {
900 	hammer2_xop_scanlhc_t *xop = &arg->xop_scanlhc;
901 	hammer2_chain_t *parent;
902 	hammer2_chain_t *chain;
903 	hammer2_key_t key_next;
904 	int cache_index = -1;	/* XXX */
905 	int error = 0;
906 
907 	parent = hammer2_inode_chain(xop->head.ip1, thr->clindex,
908 				     HAMMER2_RESOLVE_ALWAYS |
909 				     HAMMER2_RESOLVE_SHARED);
910 	chain = NULL;
911 	if (parent == NULL) {
912 		error = EIO;
913 		goto done;
914 	}
915 
916 	/*
917 	 * Lookup all possibly conflicting directory entries, the feed
918 	 * inherits the chain's lock so do not unlock it on the iteration.
919 	 */
920 	chain = hammer2_chain_lookup(&parent, &key_next,
921 				     xop->lhc, xop->lhc,
922 				     &cache_index,
923 				     HAMMER2_LOOKUP_ALWAYS |
924 				     HAMMER2_LOOKUP_SHARED);
925 	if (chain)
926 		hammer2_xop_feed(&xop->head, chain, thr->clindex, chain->error);
927 	else
928 		hammer2_xop_feed(&xop->head, NULL, thr->clindex, ENOENT);
929 
930 done:
931 	if (chain) {
932 		hammer2_chain_unlock(chain);
933 		hammer2_chain_drop(chain);
934 	}
935 	if (parent) {
936 		hammer2_chain_unlock(parent);
937 		hammer2_chain_drop(parent);
938 	}
939 }
940 
941 /*
942  * Generic scan
943  *
944  * WARNING! Fed chains must be locked shared so ownership can be transfered
945  *	    and to prevent frontend/backend stalls that would occur with an
946  *	    exclusive lock.  The shared lock also allows chain->data to be
947  *	    retained.
948  */
949 void
950 hammer2_xop_scanall(hammer2_thread_t *thr, hammer2_xop_t *arg)
951 {
952 	hammer2_xop_scanall_t *xop = &arg->xop_scanall;
953 	hammer2_chain_t *parent;
954 	hammer2_chain_t *chain;
955 	hammer2_key_t key_next;
956 	int cache_index = -1;
957 	int error = 0;
958 
959 	/*
960 	 * Assert required flags.
961 	 */
962 	KKASSERT(xop->resolve_flags & HAMMER2_RESOLVE_SHARED);
963 	KKASSERT(xop->lookup_flags & HAMMER2_LOOKUP_SHARED);
964 
965 	/*
966 	 * The inode's chain is the iterator.  If we cannot acquire it our
967 	 * contribution ends here.
968 	 */
969 	parent = hammer2_inode_chain(xop->head.ip1, thr->clindex,
970 				     xop->resolve_flags);
971 	if (parent == NULL) {
972 		kprintf("xop_readdir: NULL parent\n");
973 		goto done;
974 	}
975 
976 	/*
977 	 * Generic scan of exact records.  Note that indirect blocks are
978 	 * automatically recursed and will not be returned.
979 	 */
980 	chain = hammer2_chain_lookup(&parent, &key_next,
981 				     xop->key_beg, xop->key_end,
982 				     &cache_index, xop->lookup_flags);
983 	while (chain) {
984 		error = hammer2_xop_feed(&xop->head, chain, thr->clindex, 0);
985 		if (error)
986 			break;
987 		chain = hammer2_chain_next(&parent, chain, &key_next,
988 					   key_next, xop->key_end,
989 					   &cache_index, xop->lookup_flags);
990 	}
991 	if (chain) {
992 		hammer2_chain_unlock(chain);
993 		hammer2_chain_drop(chain);
994 	}
995 	hammer2_chain_unlock(parent);
996 	hammer2_chain_drop(parent);
997 done:
998 	hammer2_xop_feed(&xop->head, NULL, thr->clindex, error);
999 }
1000