/* * Dangling inodes can occur if processes are holding open descriptors on * deleted files as-of when a machine crashes. When we find one simply * acquire the inode and release it. The inode handling code will then * do the right thing. */ static void prune_check_nlinks(hammer_cursor_t cursor, hammer_btree_leaf_elm_t elm) { hammer_inode_t ip; int error; if (elm->base.rec_type != HAMMER_RECTYPE_INODE) return; if (elm->base.delete_tid != 0) return; if (hammer_btree_extract(cursor, HAMMER_CURSOR_GET_DATA)) return; if (cursor->data->inode.nlinks) return; hammer_cursor_downgrade(cursor); ip = hammer_get_inode(cursor->trans, NULL, elm->base.obj_id, HAMMER_MAX_TID, elm->base.localization & HAMMER_LOCALIZE_PSEUDOFS_MASK, 0, &error); if (ip) { if (hammer_debug_general & 0x0001) { kprintf("pruning disconnected inode %016llx\n", (long long)elm->base.obj_id); } hammer_rel_inode(ip, 0); hammer_inode_waitreclaims(cursor->trans); } else { kprintf("unable to prune disconnected inode %016llx\n", (long long)elm->base.obj_id); } }
// corresponds to hammer_vfs_vget struct inode *hammerfs_iget(struct super_block *sb, ino_t ino) { struct hammer_transaction trans; struct hammer_mount *hmp = (void*)sb->s_fs_info; struct hammer_inode *ip; struct inode *inode; int error = 0; hammer_simple_transaction(&trans, hmp); /* * Lookup the requested HAMMER inode. The structure must be * left unlocked while we manipulate the related vnode to avoid * a deadlock. */ ip = hammer_get_inode(&trans, NULL, ino, hmp->asof, HAMMER_DEF_LOCALIZATION, 0, &error); if (ip == NULL) { hammer_done_transaction(&trans); goto failed; } error = hammerfs_get_inode(sb, ip, &inode); // hammer_rel_inode(ip, 0); hammer_done_transaction(&trans); return inode; failed: iget_failed(inode); return ERR_PTR(error); }
/* * Iterate PFS ondisk data. * This function essentially does the same as hammer_load_pseudofs() * except that this function only retrieves PFS data without touching * hammer_pfs_rb_tree at all. * * NOTE: The ip used for ioctl is not necessarily related to the PFS * since this ioctl only requires PFS id (or upper 16 bits of ip localization). * * NOTE: The API was changed in DragonFly 4.7, due to design issues * this ioctl and libhammer (which is the only caller of this ioctl * within DragonFly source, but no longer maintained by anyone) had. */ int hammer_ioc_scan_pseudofs(hammer_transaction_t trans, hammer_inode_t ip, struct hammer_ioc_pseudofs_rw *pfs) { struct hammer_cursor cursor; hammer_inode_t dip; uint32_t localization; int error; if ((error = hammer_pfs_autodetect(pfs, ip)) != 0) return(error); localization = pfs_to_lo(pfs->pfs_id); pfs->bytes = sizeof(struct hammer_pseudofs_data); pfs->version = HAMMER_IOC_PSEUDOFS_VERSION; dip = hammer_get_inode(trans, NULL, HAMMER_OBJID_ROOT, HAMMER_MAX_TID, HAMMER_DEF_LOCALIZATION, 0, &error); error = hammer_init_cursor(trans, &cursor, (dip ? &dip->cache[1] : NULL), dip); if (error) goto fail; cursor.key_beg.localization = HAMMER_DEF_LOCALIZATION | HAMMER_LOCALIZE_MISC; cursor.key_beg.obj_id = HAMMER_OBJID_ROOT; cursor.key_beg.create_tid = 0; cursor.key_beg.delete_tid = 0; cursor.key_beg.rec_type = HAMMER_RECTYPE_PFS; cursor.key_beg.obj_type = 0; cursor.key_beg.key = localization; cursor.asof = HAMMER_MAX_TID; cursor.flags |= HAMMER_CURSOR_ASOF; error = hammer_ip_lookup(&cursor); if (error == 0) { error = hammer_ip_resolve_data(&cursor); if (error == 0) { if (pfs->ondisk) copyout(cursor.data, pfs->ondisk, cursor.leaf->data_len); localization = cursor.leaf->base.key; pfs->pfs_id = lo_to_pfs(localization); } } hammer_done_cursor(&cursor); fail: if (dip) hammer_rel_inode(dip, 0); return(error); }
/* * Obtain a vnode for the specified inode number. An exclusively locked * vnode is returned. */ int hammer_vfs_vget(struct mount *mp, struct vnode *dvp, ino_t ino, struct vnode **vpp) { struct hammer_transaction trans; struct hammer_mount *hmp = (void *)mp->mnt_data; struct hammer_inode *ip; int error; u_int32_t localization; lwkt_gettoken(&hmp->fs_token); hammer_simple_transaction(&trans, hmp); /* * If a directory vnode is supplied (mainly NFS) then we can acquire * the PFS domain from it. Otherwise we would only be able to vget * inodes in the root PFS. */ if (dvp) { localization = HAMMER_DEF_LOCALIZATION + VTOI(dvp)->obj_localization; } else { localization = HAMMER_DEF_LOCALIZATION; } /* * Lookup the requested HAMMER inode. The structure must be * left unlocked while we manipulate the related vnode to avoid * a deadlock. */ ip = hammer_get_inode(&trans, NULL, ino, hmp->asof, localization, 0, &error); if (ip == NULL) { *vpp = NULL; } else { error = hammer_get_vnode(ip, vpp); hammer_rel_inode(ip, 0); } hammer_done_transaction(&trans); lwkt_reltoken(&hmp->fs_token); return (error); }
/* * Convert a file handle back to a vnode. * * Use rootvp to enforce PFS isolation when a PFS is exported via a * null mount. */ static int hammer_vfs_fhtovp(struct mount *mp, struct vnode *rootvp, struct fid *fhp, struct vnode **vpp) { hammer_mount_t hmp = (void *)mp->mnt_data; struct hammer_transaction trans; struct hammer_inode *ip; struct hammer_inode_info info; int error; u_int32_t localization; bcopy(fhp->fid_data + 0, &info.obj_id, sizeof(info.obj_id)); bcopy(fhp->fid_data + 8, &info.obj_asof, sizeof(info.obj_asof)); if (rootvp) localization = VTOI(rootvp)->obj_localization; else localization = (u_int32_t)fhp->fid_ext << 16; lwkt_gettoken(&hmp->fs_token); hammer_simple_transaction(&trans, hmp); /* * Get/allocate the hammer_inode structure. The structure must be * unlocked while we manipulate the related vnode to avoid a * deadlock. */ ip = hammer_get_inode(&trans, NULL, info.obj_id, info.obj_asof, localization, 0, &error); if (ip) { error = hammer_get_vnode(ip, vpp); hammer_rel_inode(ip, 0); } else { *vpp = NULL; } hammer_done_transaction(&trans); lwkt_reltoken(&hmp->fs_token); return (error); }
/* corresponds to hammer_vop_nresolve */ struct dentry *hammerfs_inode_lookup(struct inode *parent_inode, struct dentry *dentry, struct nameidata *nameidata) { struct hammer_transaction trans; struct super_block *sb; struct inode *inode; hammer_inode_t dip; hammer_inode_t ip; hammer_tid_t asof; struct hammer_cursor cursor; int64_t namekey; u_int32_t max_iterations; int64_t obj_id; int nlen; int flags; int error; u_int32_t localization; printk(KERN_INFO "hammerfs_inode_lookup(parent_inode->i_ino=%lu, dentry->d_name.name=%s)\n", parent_inode->i_ino, dentry->d_name.name); sb = parent_inode->i_sb; dip = (hammer_inode_t)parent_inode->i_private; asof = dip->obj_asof; localization = dip->obj_localization; /* for code consistency */ nlen = dentry->d_name.len; flags = dip->flags & HAMMER_INODE_RO; hammer_simple_transaction(&trans, dip->hmp); /* * Calculate the namekey and setup the key range for the scan. This * works kinda like a chained hash table where the lower 32 bits * of the namekey synthesize the chain. * * The key range is inclusive of both key_beg and key_end. */ namekey = hammer_directory_namekey(dip, dentry->d_name.name, nlen, &max_iterations); error = hammer_init_cursor(&trans, &cursor, &dip->cache[1], dip); cursor.key_beg.localization = dip->obj_localization + HAMMER_LOCALIZE_MISC; cursor.key_beg.obj_id = dip->obj_id; cursor.key_beg.key = namekey; cursor.key_beg.create_tid = 0; cursor.key_beg.delete_tid = 0; cursor.key_beg.rec_type = HAMMER_RECTYPE_DIRENTRY; cursor.key_beg.obj_type = 0; cursor.key_end = cursor.key_beg; cursor.key_end.key += max_iterations; cursor.asof = asof; cursor.flags |= HAMMER_CURSOR_END_INCLUSIVE | HAMMER_CURSOR_ASOF; /* * Scan all matching records (the chain), locate the one matching * the requested path component. * * The hammer_ip_*() functions merge in-memory records with on-disk * records for the purposes of the search. */ obj_id = 0; localization = HAMMER_DEF_LOCALIZATION; if (error == 0) { error = hammer_ip_first(&cursor); while (error == 0) { error = hammer_ip_resolve_data(&cursor); if (error) break; if (nlen == cursor.leaf->data_len - HAMMER_ENTRY_NAME_OFF && bcmp(dentry->d_name.name, cursor.data->entry.name, nlen) == 0) { obj_id = cursor.data->entry.obj_id; localization = cursor.data->entry.localization; break; } error = hammer_ip_next(&cursor); } } hammer_done_cursor(&cursor); if (error == 0) { ip = hammer_get_inode(&trans, dip, obj_id, asof, localization, flags, &error); if (error == 0) error = hammerfs_get_inode(sb, ip, &inode); /* hammer_rel_inode(ip, 0); */ else ip = NULL; if (error == 0) d_add(dentry, inode); goto done; } done: /*hammer_done_transaction(&trans);*/ return NULL; }
static inline int _vnode_validate(hammer_dedup_cache_t dcp, void *data, int *errorp) { struct hammer_transaction trans; hammer_inode_t ip; struct vnode *vp; struct buf *bp; /* off_t dooffset; */ int result, error; result = error = 0; *errorp = 0; hammer_simple_transaction(&trans, dcp->hmp); ip = hammer_get_inode(&trans, NULL, dcp->obj_id, HAMMER_MAX_TID, dcp->localization, 0, &error); if (ip == NULL) { kprintf("dedup: unable to find objid %016llx:%08x\n", (long long)dcp->obj_id, dcp->localization); *errorp = 1; goto failed2; } error = hammer_get_vnode(ip, &vp); if (error) { kprintf("dedup: unable to acquire vnode for %016llx:%08x\n", (long long)dcp->obj_id, dcp->localization); *errorp = 2; goto failed; } if ((bp = findblk(ip->vp, dcp->file_offset, FINDBLK_NBLOCK)) != NULL) { dfly_brelse(bp); /* bremfree(bp) */ /* XXX if (mapped to userspace) goto done, *errorp = 4 */ if ((bp->b_flags & B_CACHE) == 0 || bp->b_flags & B_DIRTY) { *errorp = 5; goto done; } /* XXX if (bp->b_bio2.bio_offset != dcp->data_offset) { error = VOP_BMAP(ip->vp, dcp->file_offset, &dooffset, NULL, NULL, BUF_CMD_READ); if (error) { *errorp = 6; goto done; } if (dooffset != dcp->data_offset) { *errorp = 7; goto done; } hammer_live_dedup_bmap_saves++; } */ if (bcmp(data, bp->b_data, dcp->bytes) == 0) result = 1; done: dfly_brelse(bp); /* XX free to buffer not kfree ... bqrelse(bp);*/ } else { *errorp = 3; } vput(vp); failed: hammer_rel_inode(ip, 0); failed2: hammer_done_transaction(&trans); return (result); }