Ejemplo n.º 1
0
// 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);
}
/*
 * 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);
}
Ejemplo n.º 4
0
/* corresponds to hammer_vop_readdir */
int hammerfs_readdir(struct file *file, void *dirent, filldir_t filldir)
{
	struct dentry *de = file->f_dentry;
	struct hammer_transaction trans;
	struct hammer_cursor cursor;
	struct hammer_inode *ip = (struct hammer_inode *)de->d_inode->i_private;
	hammer_base_elm_t base;
	int r = 0;
	int error;
	int dtype;

	printk(KERN_INFO "hammerfs_readdir(file->f_pos=%lld)\n", file->f_pos);

	/*
	* Handle artificial entries
	*/

	if (file->f_pos == 0)
		r = filldir(dirent, ".", 1, file->f_pos++,
				de->d_inode->i_ino, DT_DIR);

	if (!r && file->f_pos == 1) {
		if (de->d_parent->d_inode)
			r = filldir(dirent, "..", 2, file->f_pos++,
					de->d_parent->d_inode->i_ino,
					DT_DIR);
		else
			r = filldir(dirent, "..", 2, file->f_pos++,
					de->d_inode->i_ino,
					DT_DIR);
	}

	if (!r) {
		hammer_simple_transaction(&trans, ip->hmp);

	/*
	* Key range (begin and end inclusive) to scan.  Directory keys
	* directly translate to a 64 bit 'seek' position.
	*/
		hammer_init_cursor(&trans, &cursor, &ip->cache[1], ip);
		cursor.key_beg.localization = ip->obj_localization +
					HAMMER_LOCALIZE_MISC;
		cursor.key_beg.obj_id = ip->obj_id;
		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_beg.key = file->f_pos;

		cursor.key_end = cursor.key_beg;
		cursor.key_end.key = HAMMER_MAX_KEY;
		cursor.asof = ip->obj_asof;
		cursor.flags |= HAMMER_CURSOR_END_INCLUSIVE |
				HAMMER_CURSOR_ASOF;

		error = hammer_ip_first(&cursor);

		while (error == 0) {
			error = hammer_ip_resolve_data(&cursor);
			if (error)
				break;
			base = &cursor.leaf->base;
			KKASSERT(cursor.leaf->data_len > HAMMER_ENTRY_NAME_OFF);

		if (base->obj_id != de->d_inode->i_ino)
			panic("readdir: bad record at %p", cursor.node);


       /*
	* Convert pseudo-filesystems into softlinks
	*/
			dtype = hammerfs_get_itype(cursor.leaf->base.obj_type);
			r = filldir(dirent, (void *)cursor.data->entry.name,
				cursor.leaf->data_len - HAMMER_ENTRY_NAME_OFF,
				file->f_pos, cursor.data->entry.obj_id, dtype);

			if (r)
				break;
			file->f_pos++;
			error = hammer_ip_next(&cursor);
		}

		hammer_done_cursor(&cursor);
	}

/* done: */
    /*hammer_done_transaction(&trans);*/
    /* return(1); */ /* TODO */
/*failed:
    return(1); */

	return 0;
}
Ejemplo n.º 5
0
/* 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;
}
Ejemplo n.º 6
0
// corresponds to hammer_vop_strategy_read
int hammerfs_readpage(struct file *file, struct page *page) 
{
    void *page_addr;
    hammer_mount_t hmp;
    struct buffer_head *bh;
    struct super_block *sb;
    struct hammer_transaction trans;
    struct hammer_cursor cursor;
    struct inode *inode;
    struct hammer_inode *ip;
    hammer_base_elm_t base;
    hammer_off_t disk_offset;
    int64_t rec_offset;
    int64_t file_offset;
    int error = 0;
    int boff;
    int roff;
    int n;
    int i=0;
    int block_num;
    int block_offset;
    int bytes_read;
    int64_t sb_offset;
    hammer_off_t zone2_offset;
    int vol_no;
    hammer_volume_t volume;

    printk ("hammerfs_readpage(page->index=%d)\n", (int) page->index);

    inode = file->f_path.dentry->d_inode;
    ip = (struct hammer_inode *)inode->i_private;
    sb = inode->i_sb;
    hmp = (hammer_mount_t)sb->s_fs_info;
    hammer_simple_transaction(&trans, ip->hmp);
    hammer_init_cursor(&trans, &cursor, &ip->cache[1], ip);
    file_offset = page->index * PAGE_SIZE;

    if (file_offset > inode->i_size) {
        error = -ENOSPC;
        goto done;
    }

    SetPageUptodate (page);
    page_addr = kmap (page);

    if(!page_addr) {
        error = -ENOSPC;
        goto failed;
    }

   /*
    * Key range (begin and end inclusive) to scan.  Note that the key's
    * stored in the actual records represent BASE+LEN, not BASE.  The
    * first record containing bio_offset will have a key > bio_offset.
    */
    cursor.key_beg.localization = ip->obj_localization +
                                  HAMMER_LOCALIZE_MISC;
    cursor.key_beg.obj_id = ip->obj_id;
    cursor.key_beg.create_tid = 0;
    cursor.key_beg.delete_tid = 0;
    cursor.key_beg.obj_type = 0;
    cursor.key_beg.key = file_offset + 1;
    cursor.asof = ip->obj_asof;
    cursor.flags |= HAMMER_CURSOR_ASOF;

    cursor.key_end = cursor.key_beg;
    KKASSERT(ip->ino_data.obj_type == HAMMER_OBJTYPE_REGFILE);

    cursor.key_beg.rec_type = HAMMER_RECTYPE_DATA;
    cursor.key_end.rec_type = HAMMER_RECTYPE_DATA;
    cursor.key_end.key = 0x7FFFFFFFFFFFFFFFLL;
    cursor.flags |= HAMMER_CURSOR_END_INCLUSIVE;

    error = hammer_ip_first(&cursor);
    boff = 0;

    while(error == 0) {
       /*
        * Get the base file offset of the record.  The key for
        * data records is (base + bytes) rather then (base).
        */
        base = &cursor.leaf->base;
        rec_offset = base->key - cursor.leaf->data_len;

       /*
        * Calculate the gap, if any, and zero-fill it.
        *
        * n is the offset of the start of the record verses our
        * current seek offset in the bio.
        */
        n = (int)(rec_offset - (file_offset + boff));
        if (n > 0) {
            if (n > PAGE_SIZE - boff)
                n = PAGE_SIZE - boff;
            bzero((char *)page_addr + boff, n);
            boff += n;
            n = 0;
        }

       /*
        * Calculate the data offset in the record and the number
        * of bytes we can copy.
        *
        * There are two degenerate cases.  First, boff may already
        * be at bp->b_bufsize.  Secondly, the data offset within
        * the record may exceed the record's size.
        */
        roff = -n;
        rec_offset += roff;
        n = cursor.leaf->data_len - roff;
        if (n <= 0) {
            printk("hammerfs_readpage: bad n=%d roff=%d\n", n, roff);
            n = 0;
        } else if (n > PAGE_SIZE - boff) {
            n = PAGE_SIZE - boff;
        }

       /*
        * Deal with cached truncations.  This cool bit of code
        * allows truncate()/ftruncate() to avoid having to sync
        * the file.
        *
        * If the frontend is truncated then all backend records are
        * subject to the frontend's truncation.
        *
        * If the backend is truncated then backend records on-disk
        * (but not in-memory) are subject to the backend's
        * truncation.  In-memory records owned by the backend
        * represent data written after the truncation point on the
        * backend and must not be truncated.
        *
        * Truncate operations deal with frontend buffer cache
        * buffers and frontend-owned in-memory records synchronously.
        */
       if (ip->flags & HAMMER_INODE_TRUNCATED) {
               if (hammer_cursor_ondisk(&cursor) ||
                   cursor.iprec->flush_state == HAMMER_FST_FLUSH) {
                       if (ip->trunc_off <= rec_offset)
                               n = 0;
                       else if (ip->trunc_off < rec_offset + n)
                               n = (int)(ip->trunc_off - rec_offset);
               }
       }
       if (ip->sync_flags & HAMMER_INODE_TRUNCATED) {
               if (hammer_cursor_ondisk(&cursor)) {
                       if (ip->sync_trunc_off <= rec_offset)
                               n = 0;
                       else if (ip->sync_trunc_off < rec_offset + n)
                               n = (int)(ip->sync_trunc_off - rec_offset);
               }
       }

       /*
        * Calculate the data offset in the record and the number
        * of bytes we can copy.
        */
        disk_offset = cursor.leaf->data_offset + roff;

        // move this to hammerfs_direct_io_read
        zone2_offset = hammer_blockmap_lookup(hmp, disk_offset, &error);
        vol_no = HAMMER_VOL_DECODE(zone2_offset);
        volume = hammer_get_volume(hmp, vol_no, &error);

        // n is the number of bytes we should read, sb_offset the
        // offset on disk
        sb_offset = volume->ondisk->vol_buf_beg + (zone2_offset & HAMMER_OFF_SHORT_MASK);

        while(n > 0 && boff != PAGE_SIZE) {
            block_num = sb_offset / BLOCK_SIZE;
            block_offset = sb_offset % BLOCK_SIZE;

            // the minimum between what is available and what we can maximally provide
            bytes_read = min(BLOCK_SIZE - (int )block_offset, PAGE_SIZE - (int )boff);        

            bh = sb_bread(sb, block_num + i);
            if(!bh) {
                error = -ENOMEM;
                goto failed;
            }
            memcpy((char*)page_addr + roff, (char*)bh->b_data + boff + block_offset, bytes_read);
            brelse(bh);

            n -= bytes_read;
            boff += bytes_read;
            roff += bytes_read;
        }

       /*
        * Iterate until we have filled the request.
        */
        if (boff == PAGE_SIZE)
            break;
        error = hammer_ip_next(&cursor);
    }

    hammer_done_cursor(&cursor);
    hammer_done_transaction(&trans);

failed:
    if (PageLocked (page))
        unlock_page (page);
    kunmap (page);
done:
    return error;
}
Ejemplo n.º 7
0
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);
}