diff --git a/sys/vfs/hammer/hammer_object.c b/sys/vfs/hammer/hammer_object.c index aca7a29..ee30f33 100644 --- a/sys/vfs/hammer/hammer_object.c +++ b/sys/vfs/hammer/hammer_object.c @@ -703,7 +703,8 @@ failed: * cursor must be seeked to the directory entry record being deleted. * * The related inode should be share-locked by the caller. The caller is - * on the frontend. + * on the frontend. It could also be NULL indicating that the directory + * entry being removed has no related inode. * * This function can return EDEADLK requiring the caller to terminate * the cursor, any locks, wait on the returned record, and retry. @@ -749,9 +750,18 @@ hammer_ip_del_directory(struct hammer_transaction *trans, record->type = HAMMER_MEM_RECORD_DEL; record->leaf.base = cursor->leaf->base; + /* + * ip may be NULL, indicating the deletion of a directory + * entry which has no related inode. + */ record->target_ip = ip; - record->flush_state = HAMMER_FST_SETUP; - TAILQ_INSERT_TAIL(&ip->target_list, record, target_entry); + if (ip) { + record->flush_state = HAMMER_FST_SETUP; + TAILQ_INSERT_TAIL(&ip->target_list, record, + target_entry); + } else { + record->flush_state = HAMMER_FST_IDLE; + } /* * The inode now has a dependancy and must be taken out of @@ -762,7 +772,7 @@ hammer_ip_del_directory(struct hammer_transaction *trans, * reflush when the dependancies are disposed of if someone * is waiting on the inode. */ - if (ip->flush_state == HAMMER_FST_IDLE) { + if (ip && ip->flush_state == HAMMER_FST_IDLE) { hammer_ref(&ip->lock); ip->flush_state = HAMMER_FST_SETUP; if (ip->flags & HAMMER_INODE_FLUSHW) @@ -786,15 +796,18 @@ hammer_ip_del_directory(struct hammer_transaction *trans, * on-media until we unmount. */ if (error == 0) { - --ip->ino_data.nlinks; + if (ip) + --ip->ino_data.nlinks; /* do before we might block */ dip->ino_data.mtime = trans->time; hammer_modify_inode(dip, HAMMER_INODE_MTIME); - hammer_modify_inode(ip, HAMMER_INODE_DDIRTY); - if (ip->ino_data.nlinks == 0 && - (ip->vp == NULL || (ip->vp->v_flag & VINACTIVE))) { - hammer_done_cursor(cursor); - hammer_inode_unloadable_check(ip, 1); - hammer_flush_inode(ip, 0); + if (ip) { + hammer_modify_inode(ip, HAMMER_INODE_DDIRTY); + if (ip->ino_data.nlinks == 0 && + (ip->vp == NULL || (ip->vp->v_flag & VINACTIVE))) { + hammer_done_cursor(cursor); + hammer_inode_unloadable_check(ip, 1); + hammer_flush_inode(ip, 0); + } } } diff --git a/sys/vfs/hammer/hammer_vnops.c b/sys/vfs/hammer/hammer_vnops.c index c2abe5f..e39a69c 100644 --- a/sys/vfs/hammer/hammer_vnops.c +++ b/sys/vfs/hammer/hammer_vnops.c @@ -1298,6 +1298,10 @@ hammer_vop_readdir(struct vop_readdir_args *ap) /* * Handle artificial entries + * + * It should be noted that the minimum value for a directory + * hash key on-media is 0x0000000100000000, so we can use anything + * less then that to represent our 'special' key space. */ error = 0; if (saveoff == 0) { @@ -2811,15 +2815,17 @@ retry: 0, &error); hammer_lock_sh(&cursor.ip->lock); if (error == ENOENT) { - kprintf("obj_id %016llx\n", cursor.data->entry.obj_id); - Debugger("ENOENT unlinking object that should exist"); + kprintf("HAMMER: Warning: Removing directory entry" + " whos inode does not exist: %016llx\n", + (long long)cursor.data->entry.obj_id); + error = 0; } /* * If isdir >= 0 we validate that the entry is or is not a * directory. If isdir < 0 we don't care. */ - if (error == 0 && isdir >= 0) { + if (error == 0 && isdir >= 0 && ip) { if (isdir && ip->ino_data.obj_type != HAMMER_OBJTYPE_DIRECTORY) { error = ENOTDIR; @@ -2841,8 +2847,8 @@ retry: * If any changes whatsoever have been made to the cursor * set EDEADLK and retry. */ - if (error == 0 && ip->ino_data.obj_type == - HAMMER_OBJTYPE_DIRECTORY) { + if (error == 0 && ip && ip->ino_data.obj_type == + HAMMER_OBJTYPE_DIRECTORY) { hammer_unlock_cursor(&cursor); error = hammer_ip_check_directory_empty(trans, ip); hammer_lock_cursor(&cursor); @@ -2870,7 +2876,7 @@ retry: cache_setunresolved(nch); cache_setvp(nch, NULL); /* XXX locking */ - if (ip->vp) { + if (ip && ip->vp) { hammer_knote(ip->vp, NOTE_DELETE); cache_inval_vp(ip->vp, CINV_DESTROY); }