/*
 * The dce irqs are not acked by the rlc (block in charge of irq management).
 * It seems the rlc block does not have xrbm access (the block in charge of
 * register management).
 * Then those irqs must be acked manually by the CPU.
 * This is called in hard interrupt context, it does not lock the dce.
 */
void dce4_irqs_ack(struct dce4 *dce)
{
	u32 disps[CRTCS_N_MAX];
	u32 grphs[CRTCS_N_MAX];
	unsigned i;
	u32 tmp;

	for (i = 0; i < dce->ddev.crtcs_n; ++i)
		disps[i] = RR32(regs_disp_int_status[i]);

	for (i = 0; i < dce->ddev.crtcs_n; ++i)
		grphs[i] = RR32(regs_crtc_grph_int_status[i]);

	/* XXX: obsolete page flipping */
	for (i = 0; i < dce->ddev.crtcs_n; ++i)
		if (grphs[i] & GRPH_PFLIP_INT_OCCURRED)
			WR32(GRPH_PFLIP_INT_CLR, regs_crtc_grph_int_status[i]);

	for (i = 0; i < dce->ddev.crtcs_n; ++i) {
		if (disps[i] & vals_lb_d_vblank_int[i])
			WR32(VBLANK_ACK, regs_crtc_vblank_status[i]);
		if (disps[i] & vals_lb_d_vline_int[i])
			WR32(VLINE_ACK, regs_crtc_vline_status[i]);
	}

	for (i = 0; i < HPDS_N; ++i)
		if (disps[i] & vals_hpd_int[i]) {
			tmp = RR32(regs_hpd_int_ctl[i]);
			tmp |= HPDx_INT_CTL_INT_ACK;
			WR32(tmp, regs_hpd_int_ctl[i]);
		}
}
void dce4_vga_off(struct dce4 *dce)
{
	unsigned i;

	WR32(VGA_MEM_DIS, VGA_HDP_CTL);
	WR32(RR32(VGA_RENDER_CTL) & VGA_VSTATUS_CTL_CLR, VGA_RENDER_CTL);
	for (i = 0; i < dce->ddev.crtcs_n; ++i)
		WR32(0, regs_vga_ctl[i]);
	
}
Beispiel #3
0
void dce6_vga_off(struct dce6 *dce)
{
	u8 i;

	/* lockout access to vga mem through hdp */
	WR32(VHC_VGA_MEM_DIS, VGA_HDP_CTL);
	WR32(RR32(VGA_RENDER_CTL) & VRC_VGA_VSTATUS_CTL_CLR, VGA_RENDER_CTL);
	for (i = 0; i < dce->ddev.crtcs_n; ++i)
		WR32(0, regs_vga_ctl[i]);
	
}
Beispiel #4
0
nfsstat4 nfs_op_lookupp(struct nfs_cxn *cxn,
		       struct list_head *writes, struct rpc_write **wr)
{
	nfsstat4 status = NFS4_OK;
	struct nfs_inode *ino = NULL;

	if (debugging)
		applog(LOG_INFO, "op LOOKUPP");

	status = dir_curfh(NULL, cxn, &ino, 0);
	if (status != NFS4_OK)
		goto out;

	if (ino->inum == INO_ROOT) {	/* root inode, no parents */
		status = NFS4ERR_NOENT;
		goto out;
	}

	fh_set(&cxn->current_fh, ino->parent);

out:
	WR32(status);
	inode_free(ino);
	return status;
}
Beispiel #5
0
static long dp_off(struct dce6 *dce, u8 i)
{
	long r;

	r = atb_trans_link_off(dce->ddev.atb, i);
	if (r == -ATB_ERR)
		return -DCE6_ERR;

	r = atb_trans_link_pwr(dce->ddev.atb, i, 0);
	if (r == -ATB_ERR)
		return -DCE6_ERR;

	r = atb_enc_video(dce->ddev.atb, i, dce->dps[i].hpd, 0);
	if (r == -ATB_ERR)
		return -DCE6_ERR;

	r = atb_crtc_blank(dce->ddev.atb, i, 1);
	if (r == -ATB_ERR)
		return -DCE6_ERR;

	r = atb_crtc(dce->ddev.atb, i, 0);
	if (r == -ATB_ERR)
		return -DCE6_ERR;

	WR32(0, regs_grph_ena[i]);

	r = atb_crtc_pair_pwr_gate(dce->ddev.atb, i, 1);
	if (r == -ATB_ERR)
		return -DCE6_ERR;
	return 0;
}
Beispiel #6
0
long dp_dpm_off(struct dce6 *dce, u8 i)
{
	long r;

	r = atb_trans_link_off(dce->ddev.atb, i);
	if (r == -ATB_ERR)
		return -DCE6_ERR;

	r = atb_enc_video(dce->ddev.atb, i, dce->dps[i].hpd, 0);
	if (r == -ATB_ERR)
		return -DCE6_ERR;

	if (dce->dps[i].edp) {/* shutdown sink power only for edp */
		r = atb_trans_link_pwr(dce->ddev.atb, i, 0);
		if (r == -ATB_ERR)
			return -DCE6_ERR;
	}

	r = atb_crtc_blank(dce->ddev.atb, i, 1);
	if (r == -ATB_ERR)
		return -DCE6_ERR;

	r = atb_crtc(dce->ddev.atb, i, 0);
	if (r == -ATB_ERR)
		return -DCE6_ERR;

	WR32(0, regs_grph_ena[i]);

	r = atb_crtc_pair_pwr_gate(dce->ddev.atb, i, 1);
	if (r == -ATB_ERR)
		return -DCE6_ERR;
	return 0;
}
Beispiel #7
0
static void encode_acl(const fattr4_acl *acl,
		       struct list_head *writes, struct rpc_write **wr)
{
	struct nfs_buf nb;
	nfsace4 *ace;
	int i;

	WR32(acl->fattr4_acl_len);

	for (i = 0; i < acl->fattr4_acl_len; i++) {
		ace = &acl->fattr4_acl_val[i];
		WR32(ace->type);
		WR32(ace->flag);
		WR32(ace->access_mask);

		nb.len = ace->who.utf8string_len;
		nb.val = ace->who.utf8string_val;
		WRBUF(&nb);
	}
}
int dce4_init(struct dce4 *dce, u32 dmif_addr_cfg)
{
	int r;

	/* configure the dce memory interface */
	WR32(dmif_addr_cfg, DMIF_ADDR_CFG);

	mutex_init(&dce->mutex);
	spin_lock_init(&dce->irq.lock);

	r = paths_parse(dce);
	if (r != 0)
		goto err;

	dce_dump(dce);

	r = trans_links_init(dce);	
	if (r != 0)
		goto err;

	r = atb_crtc_dcpll(dce->ddev.atb);
	if (r != 0)
		goto err;

	hpds_init(dce);

	dps_used_pf_init(dce);

	r = dps_used_pwr_on(dce);
	if (r != 0)
		goto err;
	
	r = dps_used_dpm_off(dce);
	if (r != 0)
		goto err;

	r = dps_unused_off(dce);
	if (r != 0)
		goto err;

	r = dps_sense(dce);
	if (r != 0)
		goto err;

	r = dps_connected_dpcd_info(dce);
	if (r != 0)
		goto err;

	dps_connected_edid(dce);

err:
	return r;
}
Beispiel #9
0
long dce6_init(struct dce6 *dce, u32 dmif_addr_cfg)
{
	long r;

	lock(dce);

	/* configure the dce memory interface */
	WR32(dmif_addr_cfg, DMIF_ADDR_CFG);
	WR32(dmif_addr_cfg, DMIF_ADDR_CALC);

	crtcs_atb_states_init(dce);

	r = trans_links_init(dce);	
	if (r == -DCE6_ERR)
		return -DCE6_ERR;

	r = atb_crtc_dcpll(dce->ddev.atb);
	if (r == -ATB_ERR)
		return -DCE6_ERR;

	hpds_init(dce);

	r = dps_used_pwr_on(dce);
	if (r == -DCE6_ERR)
		return -DCE6_ERR;
	
	r = dps_used_dpm_off(dce);
	if (r == -DCE6_ERR)
		return -DCE6_ERR;

	r = dps_unused_off(dce);
	if (r == -DCE6_ERR)
		return -DCE6_ERR;

	unlock(dce);
	return 0;
}
Beispiel #10
0
nfsstat4 wr_fattr(const struct nfs_fattr_set *attr, uint64_t *_bitmap_out,
		  struct list_head *writes, struct rpc_write **wr)
{
	uint64_t bitmap = attr->bitmap;
	uint64_t bitmap_out = 0;
	uint32_t *bmap[2];
	uint32_t attr_size;

	WR32(2);		/* bitmap array size */
	bmap[0] = WRSKIP(4);	/* bitmap array[0] */
	bmap[1] = WRSKIP(4);	/* bitmap array[1] */

	attr_size = fattr_size(attr);
	WR32(attr_size);

	if (bitmap & (1ULL << FATTR4_SUPPORTED_ATTRS)) {
		WRMAP(fattr_supported_mask);
		bitmap_out |= (1ULL << FATTR4_SUPPORTED_ATTRS);
	}
	if (bitmap & (1ULL << FATTR4_TYPE)) {
		WR32(attr->type);
		bitmap_out |= (1ULL << FATTR4_TYPE);
	}
	if (bitmap & (1ULL << FATTR4_FH_EXPIRE_TYPE)) {
		WR32(attr->fh_expire_type);
		bitmap_out |= (1ULL << FATTR4_FH_EXPIRE_TYPE);
	}
	if (bitmap & (1ULL << FATTR4_CHANGE)) {
		WR64(attr->change);
		bitmap_out |= (1ULL << FATTR4_CHANGE);
	}
	if (bitmap & (1ULL << FATTR4_SIZE)) {
		WR64(attr->size);
		bitmap_out |= (1ULL << FATTR4_SIZE);
	}
	if (bitmap & (1ULL << FATTR4_LINK_SUPPORT)) {
		WR32(attr->link_support ? 1 : 0);
		bitmap_out |= (1ULL << FATTR4_LINK_SUPPORT);
	}
	if (bitmap & (1ULL << FATTR4_SYMLINK_SUPPORT)) {
		WR32(attr->symlink_support ? 1 : 0);
		bitmap_out |= (1ULL << FATTR4_SYMLINK_SUPPORT);
	}
	if (bitmap & (1ULL << FATTR4_NAMED_ATTR)) {
		WR32(attr->named_attr ? 1 : 0);
		bitmap_out |= (1ULL << FATTR4_NAMED_ATTR);
	}
	if (bitmap & (1ULL << FATTR4_FSID)) {
		WR64(attr->fsid.major);
		WR64(attr->fsid.minor);
		bitmap_out |= (1ULL << FATTR4_FSID);
	}
	if (bitmap & (1ULL << FATTR4_UNIQUE_HANDLES)) {
		WR32(attr->unique_handles ? 1 : 0);
		bitmap_out |= (1ULL << FATTR4_UNIQUE_HANDLES);
	}
	if (bitmap & (1ULL << FATTR4_LEASE_TIME)) {
		WR32(attr->lease_time);
		bitmap_out |= (1ULL << FATTR4_LEASE_TIME);
	}
	if (bitmap & (1ULL << FATTR4_RDATTR_ERROR)) {
		WR32(attr->rdattr_error);
		bitmap_out |= (1ULL << FATTR4_RDATTR_ERROR);
	}

#if 0
	if (bitmap & (1ULL << FATTR4_ACL)) {
		encode_acl(&attr->acl, writes, wr);
		bitmap_out |= (1ULL << FATTR4_ACL);
	}
#endif

	if (bitmap & (1ULL << FATTR4_ACLSUPPORT)) {
		WR32(attr->aclsupport);
		bitmap_out |= (1ULL << FATTR4_ACLSUPPORT);
	}
	if (bitmap & (1ULL << FATTR4_ARCHIVE)) {
		WR32(attr->archive ? 1 : 0);
		bitmap_out |= (1ULL << FATTR4_ARCHIVE);
	}
	if (bitmap & (1ULL << FATTR4_CANSETTIME)) {
		WR32(attr->cansettime ? 1 : 0);
		bitmap_out |= (1ULL << FATTR4_CANSETTIME);
	}
	if (bitmap & (1ULL << FATTR4_CASE_INSENSITIVE)) {
		WR32(attr->case_insensitive ? 1 : 0);
		bitmap_out |= (1ULL << FATTR4_CASE_INSENSITIVE);
	}
	if (bitmap & (1ULL << FATTR4_CASE_PRESERVING)) {
		WR32(attr->case_preserving ? 1 : 0);
		bitmap_out |= (1ULL << FATTR4_CASE_PRESERVING);
	}
	if (bitmap & (1ULL << FATTR4_CHOWN_RESTRICTED)) {
		WR32(attr->chown_restricted ? 1 : 0);
		bitmap_out |= (1ULL << FATTR4_CHOWN_RESTRICTED);
	}
	if (bitmap & (1ULL << FATTR4_FILEHANDLE)) {
		WR32(sizeof(struct nfs_fh));
		WR64(attr->filehandle);
		bitmap_out |= (1ULL << FATTR4_FILEHANDLE);
	}
	if (bitmap & (1ULL << FATTR4_FILEID)) {
		WR64(attr->fileid);
		bitmap_out |= (1ULL << FATTR4_FILEID);
	}
	if (bitmap & (1ULL << FATTR4_FILES_AVAIL)) {
		WR64(attr->files_avail);
		bitmap_out |= (1ULL << FATTR4_FILES_AVAIL);
	}
	if (bitmap & (1ULL << FATTR4_FILES_FREE)) {
		WR64(attr->files_free);
		bitmap_out |= (1ULL << FATTR4_FILES_FREE);
	}
	if (bitmap & (1ULL << FATTR4_FILES_TOTAL)) {
		WR64(attr->files_total);
		bitmap_out |= (1ULL << FATTR4_FILES_TOTAL);
	}
	if (bitmap & (1ULL << FATTR4_FS_LOCATIONS)) {
		WR32(1);		/* fs_root len */
		WRSTR("/");		/* fs_root */
		WR32(1);		/* location len */
		WR32(1);		/* location[0].server len */
		WRSTR(my_hostname);	/* location[0].server[0] */
		WR32(1);		/* location[0].rootpath len */
		WRSTR("/");		/* location[0].rootpath */

		bitmap_out |= (1ULL << FATTR4_FS_LOCATIONS);
	}
	if (bitmap & (1ULL << FATTR4_HIDDEN)) {
		WR32(attr->hidden ? 1 : 0);
		bitmap_out |= (1ULL << FATTR4_HIDDEN);
	}
	if (bitmap & (1ULL << FATTR4_HOMOGENEOUS)) {
		WR32(attr->homogeneous ? 1 : 0);
		bitmap_out |= (1ULL << FATTR4_HOMOGENEOUS);
	}
	if (bitmap & (1ULL << FATTR4_MAXFILESIZE)) {
		WR64(attr->maxfilesize);
		bitmap_out |= (1ULL << FATTR4_MAXFILESIZE);
	}
	if (bitmap & (1ULL << FATTR4_MAXLINK)) {
		WR32(attr->maxlink);
		bitmap_out |= (1ULL << FATTR4_MAXLINK);
	}
	if (bitmap & (1ULL << FATTR4_MAXNAME)) {
		WR32(attr->maxname);
		bitmap_out |= (1ULL << FATTR4_MAXNAME);
	}
	if (bitmap & (1ULL << FATTR4_MAXREAD)) {
		WR64(attr->maxread);
		bitmap_out |= (1ULL << FATTR4_MAXREAD);
	}
	if (bitmap & (1ULL << FATTR4_MAXWRITE)) {
		WR64(attr->maxwrite);
		bitmap_out |= (1ULL << FATTR4_MAXWRITE);
	}
	if ((bitmap & (1ULL << FATTR4_MIMETYPE)) && (attr->mimetype.len)) {
		WRBUF(&attr->mimetype);
		bitmap_out |= (1ULL << FATTR4_MIMETYPE);
	}
	if (bitmap & (1ULL << FATTR4_MODE)) {
		WR32(attr->mode);
		bitmap_out |= (1ULL << FATTR4_MODE);
	}
	if (bitmap & (1ULL << FATTR4_NO_TRUNC)) {
		WR32(attr->no_trunc ? 1 : 0);
		bitmap_out |= (1ULL << FATTR4_NO_TRUNC);
	}
	if (bitmap & (1ULL << FATTR4_NUMLINKS)) {
		WR32(attr->numlinks);
		bitmap_out |= (1ULL << FATTR4_NUMLINKS);
	}
	if ((bitmap & (1ULL << FATTR4_OWNER)) && (attr->owner.len)) {
		WRBUF(&attr->owner);
		bitmap_out |= (1ULL << FATTR4_OWNER);
	}
	if ((bitmap & (1ULL << FATTR4_OWNER_GROUP)) && (attr->owner_group.len)){
		WRBUF(&attr->owner_group);
		bitmap_out |= (1ULL << FATTR4_OWNER_GROUP);
	}
	if (bitmap & (1ULL << FATTR4_QUOTA_AVAIL_HARD)) {
		WR64(attr->quota_avail_hard);
		bitmap_out |= (1ULL << FATTR4_QUOTA_AVAIL_HARD);
	}
	if (bitmap & (1ULL << FATTR4_QUOTA_AVAIL_SOFT)) {
		WR64(attr->quota_avail_soft);
		bitmap_out |= (1ULL << FATTR4_QUOTA_AVAIL_SOFT);
	}
	if (bitmap & (1ULL << FATTR4_QUOTA_USED)) {
		WR64(attr->quota_used);
		bitmap_out |= (1ULL << FATTR4_QUOTA_USED);
	}
	if (bitmap & (1ULL << FATTR4_RAWDEV)) {
		/* FIXME: correct order of these two dwords? */
		WR32(attr->rawdev.specdata1);
		WR32(attr->rawdev.specdata2);
		bitmap_out |= (1ULL << FATTR4_RAWDEV);
	}
	if (bitmap & (1ULL << FATTR4_SPACE_AVAIL)) {
		WR64(attr->space_avail);
		bitmap_out |= (1ULL << FATTR4_SPACE_AVAIL);
	}
	if (bitmap & (1ULL << FATTR4_SPACE_FREE)) {
		WR64(attr->space_free);
		bitmap_out |= (1ULL << FATTR4_SPACE_FREE);
	}
	if (bitmap & (1ULL << FATTR4_SPACE_TOTAL)) {
		WR64(attr->space_total);
		bitmap_out |= (1ULL << FATTR4_SPACE_TOTAL);
	}
	if (bitmap & (1ULL << FATTR4_SPACE_USED)) {
		WR64(attr->space_used);
		bitmap_out |= (1ULL << FATTR4_SPACE_USED);
	}
	if (bitmap & (1ULL << FATTR4_SYSTEM)) {
		WR32(attr->system ? 1 : 0);
		bitmap_out |= (1ULL << FATTR4_SYSTEM);
	}
	if (bitmap & (1ULL << FATTR4_TIME_ACCESS)) {
		WR64(attr->time_access.seconds);
		WR32(attr->time_access.nseconds);
		bitmap_out |= (1ULL << FATTR4_TIME_ACCESS);
	}
	if (bitmap & (1ULL << FATTR4_TIME_BACKUP)) {
		WR64(attr->time_backup.seconds);
		WR32(attr->time_backup.nseconds);
		bitmap_out |= (1ULL << FATTR4_TIME_BACKUP);
	}
	if (bitmap & (1ULL << FATTR4_TIME_CREATE)) {
		WR64(attr->time_create.seconds);
		WR32(attr->time_create.nseconds);
		bitmap_out |= (1ULL << FATTR4_TIME_CREATE);
	}
	if (bitmap & (1ULL << FATTR4_TIME_DELTA)) {
		WR64(attr->time_delta.seconds);
		WR32(attr->time_delta.nseconds);
		bitmap_out |= (1ULL << FATTR4_TIME_DELTA);
	}
	if (bitmap & (1ULL << FATTR4_TIME_METADATA)) {
		WR64(attr->time_metadata.seconds);
		WR32(attr->time_metadata.nseconds);
		bitmap_out |= (1ULL << FATTR4_TIME_METADATA);
	}
	if (bitmap & (1ULL << FATTR4_TIME_MODIFY)) {
		WR64(attr->time_modify.seconds);
		WR32(attr->time_modify.nseconds);
		bitmap_out |= (1ULL << FATTR4_TIME_MODIFY);
	}
	if (bitmap & (1ULL << FATTR4_MOUNTED_ON_FILEID)) {
		WR64(attr->mounted_on_fileid);
		bitmap_out |= (1ULL << FATTR4_MOUNTED_ON_FILEID);
	}

	*_bitmap_out = bitmap_out;

	*bmap[0] = htonl(bitmap_out);
	*bmap[1] = htonl(bitmap_out >> 32);

	return NFS4_OK;
}
Beispiel #11
0
nfsstat4 nfs_op_readdir(struct nfs_cxn *cxn, const READDIR4args *args,
		        struct list_head *writes, struct rpc_write **wr)
{
	nfsstat4 status = NFS4_OK;
	struct nfs_inode *ino = NULL;
	uint32_t dircount, maxcount, *status_p;
	struct readdir_info ri;
	uint64_t cookie, attr_request;
	const verifier4 *cookie_verf;
	DB_TXN *txn = NULL;
	DB *dirent = srv.fsdb.dirent;
	DB_ENV *dbenv = srv.fsdb.env;
	DBT pkey, pval;
	struct fsdb_de_key key;
	int cget_flags;
	DBC *curs = NULL;
	int rc;
	uint64_t dirent_inum, db_de;
	struct fsdb_de_key *rkey;

	cookie = args->cookie;
	cookie_verf = &args->cookieverf;
	dircount = args->dircount;
	maxcount = args->maxcount;
	attr_request = bitmap4_decode(&args->attr_request);

	status_p = WRSKIP(4);

	if (debugging) {
		applog(LOG_INFO, "op READDIR (COOKIE:%Lu DIR:%u MAX:%u MAP:%Lx)",
		       (unsigned long long) cookie,
		       dircount,
		       maxcount,
		       (unsigned long long) attr_request);

		print_fattr_bitmap("op READDIR", attr_request);
	}

	/* traditionally "." and "..", hardcoded */
	if (cookie == 1 || cookie == 2) {
		status = NFS4ERR_BAD_COOKIE;
		goto out;
	}
	/* don't permit request of write-only attrib */
	if (attr_request & fattr_write_only_mask) {
		status = NFS4ERR_INVAL;
		goto out;
	}

	/* FIXME: very, very, very poor verifier */
	if (cookie &&
	    memcmp(cookie_verf, &srv.instance_verf, sizeof(verifier4))) {
		status = NFS4ERR_NOT_SAME;
		goto out;
	}

	/* read inode of directory being read */
	status = dir_curfh(NULL, cxn, &ino, 0);
	if (status != NFS4_OK)
		goto out;
	if (ino->mode == 0) {
		status = NFS4ERR_ACCESS;
		goto out;
	}

	/* subtract READDIR4resok header and footer size */
	if (maxcount < 16) {
		status = NFS4ERR_TOOSMALL;
		goto out;
	}

	maxcount -= (8 + 4 + 4);

	/* verify within server limits */
	if (dircount > SRV_MAX_READ || maxcount > SRV_MAX_READ) {
		status = NFS4ERR_INVAL;
		goto out;
	}

	/* open transaction */
	rc = dbenv->txn_begin(dbenv, NULL, &txn, 0);
	if (rc) {
		status = NFS4ERR_IO;
		dbenv->err(dbenv, rc, "DB_ENV->txn_begin");
		goto out;
	}

	/* set up directory iteration */
	memset(&ri, 0, sizeof(ri));
	ri.cookie = cookie;
	ri.dircount = dircount;
	ri.maxcount = maxcount;
	ri.attr_request = attr_request;
	ri.status = NFS4_OK;
	ri.writes = writes;
	ri.wr = wr;
	ri.dir_pos = 3;
	ri.first_time = true;

	/* if dir is empty, skip directory interation loop completely */
	if (dir_is_empty(txn, ino)) {
		WRMEM(&srv.instance_verf, sizeof(verifier4));	/* cookieverf */

		ri.val_follows = WRSKIP(4);

		if (debugging)
			applog(LOG_DEBUG, "   READDIR: empty directory");

		goto the_finale;
	}

	/* otherwise, loop through each dirent attached to ino->inum */
	rc = dirent->cursor(dirent, txn, &curs, 0);
	if (rc) {
		status = NFS4ERR_IO;
		dirent->err(dirent, rc, "dirent->cursor");
		goto out_abort;
	}

	key.inum = inum_encode(ino->inum);

	memset(&pkey, 0, sizeof(pkey));
	pkey.data = &key;
	pkey.size = sizeof(key);
	pkey.flags = DB_DBT_MALLOC;

	memset(&pval, 0, sizeof(pval));
	pval.data = &db_de;
	pval.ulen = sizeof(db_de);
	pval.flags = DB_DBT_USERMEM;

	cget_flags = DB_SET_RANGE;
	while (1) {
		bool iter_rc;

		rc = curs->get(curs, &pkey, &pval, cget_flags);
		if (rc) {
			if (rc != DB_NOTFOUND)
				dirent->err(dirent, rc, "readdir curs->get");
			break;
		}

		cget_flags = DB_NEXT;

		rkey = pkey.data;
		if (inum_decode(rkey->inum) != ino->inum) {
			free(rkey);
			break;
		}

		dirent_inum = inum_decode(db_de);

		iter_rc = readdir_iter(txn, rkey, pkey.size, dirent_inum, &ri);
		free(rkey);

		if (iter_rc)
			break;
	}

	if (!ri.n_results) {
		if (debugging)
			applog(LOG_INFO, "           zero results, status %s",
			       ri.status <= NFS4ERR_CB_PATH_DOWN ?
			       		status2str(ri.status) : "n/a");

		if (ri.status == NFS4_OK) {
			WRMEM(&srv.instance_verf, sizeof(verifier4));	/* cookieverf */

			ri.val_follows = WRSKIP(4);
		}
	}

	rc = curs->close(curs);
	if (rc) {
		status = NFS4ERR_IO;
		dirent->err(dirent, rc, "dirent->cursor close");
		goto out_abort;
	}

the_finale:

	/* terminate final entry4.nextentry and dirlist4.entries */
	if (ri.val_follows)
		*ri.val_follows = htonl(0);

	if (ri.cookie_found && !ri.n_results && ri.hit_limit) {
		status = NFS4ERR_TOOSMALL;
		goto out_abort;
	}

	/* close transaction */
	rc = txn->commit(txn, 0);
	if (rc) {
		dbenv->err(dbenv, rc, "DB_ENV->txn_commit");
		status = NFS4ERR_IO;
		goto out;
	}

	WR32(ri.hit_limit ? 0 : 1);		/* reply eof */

out:
	*status_p = htonl(status);
	inode_free(ino);
	return status;

out_abort:
	if (txn->abort(txn))
		dbenv->err(dbenv, rc, "DB_ENV->txn_abort");
	goto out;
}
Beispiel #12
0
nfsstat4 nfs_op_rename(struct nfs_cxn *cxn, const RENAME4args *args,
		       struct list_head *writes, struct rpc_write **wr)
{
	nfsstat4 status = NFS4_OK;
	struct nfs_inode *src_dir = NULL, *target_dir = NULL;
	struct nfs_inode *old_file = NULL, *new_file = NULL;
	struct nfs_buf oldname, newname;
	change_info4 src = { true, 0, 0 };
	change_info4 target = { true, 0, 0 };
	DB_TXN *txn = NULL;
	DB_ENV *dbenv = srv.fsdb.env;
	int rc;
	nfsino_t old_dirent, new_dirent;

	oldname.len = args->oldname.utf8string_len;
	oldname.val = args->oldname.utf8string_val;
	newname.len = args->newname.utf8string_len;
	newname.val = args->newname.utf8string_val;

	if (debugging)
		applog(LOG_INFO, "op RENAME (OLD:%.*s, NEW:%.*s)",
		       oldname.len,
		       oldname.val,
		       newname.len,
		       newname.val);

	/* validate text input */
	if ((!valid_utf8string(&oldname)) ||
	    (!valid_utf8string(&newname))) {
		status = NFS4ERR_INVAL;
		goto out;
	}
	if (has_dots(&oldname) || has_dots(&newname)) {
		status = NFS4ERR_BADNAME;
		goto out;
	}

	rc = dbenv->txn_begin(dbenv, NULL, &txn, 0);
	if (rc) {
		status = NFS4ERR_IO;
		dbenv->err(dbenv, rc, "DB_ENV->txn_begin");
		goto out;
	}

	/* reference source, target directories.
	 * NOTE: src_dir and target_dir may point to the same object
	 */
	src_dir = inode_fhdec(txn, cxn->save_fh, DB_RMW);
	if (fh_equal(cxn->save_fh, cxn->current_fh))
		target_dir = src_dir;
	else
		target_dir = inode_fhdec(txn, cxn->current_fh, DB_RMW);
	if (!src_dir || !target_dir) {
		status = NFS4ERR_NOFILEHANDLE;
		goto out_abort;
	}
	if ((src_dir->type != NF4DIR) || (target_dir->type != NF4DIR)) {
		status = NFS4ERR_NOTDIR;
		goto out_abort;
	}

	/* lookup source, target names */
	status = dir_lookup(txn, src_dir, &oldname, 0, &old_dirent);
	if (status != NFS4_OK)
		goto out_abort;

	old_file = inode_getdec(txn, old_dirent, 0);
	if (!old_file) {
		status = NFS4ERR_NOENT;
		goto out_abort;
	}

	status = dir_lookup(txn, target_dir, &newname, 0, &new_dirent);
	if (status != NFS4_OK && status != NFS4ERR_NOENT)
		goto out_abort;

	/* if target (newname) is present, attempt to remove */
	if (status == NFS4_OK) {
		bool ok_to_remove = false;

		/* read to-be-deleted inode */
		new_file = inode_getdec(txn, new_dirent, DB_RMW);
		if (!new_file) {
			status = NFS4ERR_NOENT;
			goto out_abort;
		}

		/* do oldname and newname refer to same file? */
		if (old_file->inum == new_file->inum) {
			src.after =
			src.before = src_dir->version;
			target.after =
			target.before = target_dir->version;
			goto out_abort;
		}

		if (old_file->type != NF4DIR && new_file->type != NF4DIR)
			ok_to_remove = true;
		else if (old_file->type == NF4DIR &&
			 new_file->type == NF4DIR &&
			 dir_is_empty(txn, new_file))
			ok_to_remove = true;

		if (!ok_to_remove) {
			status = NFS4ERR_EXIST;
			goto out_abort;
		}

		/* remove target inode from directory */
		rc = fsdb_dirent_del(&srv.fsdb, txn, target_dir->inum,
				     &newname, 0);
		if (rc == 0)
			rc = inode_unlink(txn, new_file);

		if (rc) {
			status = NFS4ERR_IO;
			goto out_abort;
		}
	} else
		status = NFS4_OK;

	new_dirent = old_dirent;

	/* delete entry from source directory; add to target directory */
	rc = fsdb_dirent_del(&srv.fsdb, txn, src_dir->inum, &oldname, 0);
	if (rc == 0)
		rc = fsdb_dirent_put(&srv.fsdb, txn, target_dir->inum,
				     &newname, 0, new_dirent);
	if (rc) {
		status = NFS4ERR_IO;
		goto out_abort;
	}

	/* if renamed file is a directory, ensure its 'parent' is updated */
	if (old_file->type == NF4DIR) {
		old_file->parent = target_dir->inum;
		if (inode_touch(txn, old_file)) {
			status = NFS4ERR_IO;
			goto out_abort;
		}
	}

	/* record directory change info */
	src.before = src_dir->version;
	target.before = target_dir->version;

	/* update last-modified stamps of directory inodes */
	rc = inode_touch(txn, src_dir);
	if (rc == 0 && src_dir != target_dir)
		rc = inode_touch(txn, target_dir);
	if (rc) {
		status = NFS4ERR_IO;
		goto out_abort;
	}

	/* close the transaction */
	rc = txn->commit(txn, 0);
	if (rc) {
		dbenv->err(dbenv, rc, "DB_ENV->txn_commit");
		status = NFS4ERR_IO;
		goto out;
	}

	src.after = src_dir->version;
	target.after = target_dir->version;

out:
	WR32(status);
	if (status == NFS4_OK) {
		WR32(src.atomic ? 1 : 0); /* src cinfo.atomic */
		WR64(src.before);	/* src cinfo.before */
		WR64(src.after);	/* src cinfo.after */
		WR32(target.atomic ? 1 : 0); /* target cinfo.atomic */
		WR64(target.before);	/* target cinfo.before */
		WR64(target.after);	/* target cinfo.after */
	}
	inode_free(src_dir);
	if (src_dir != target_dir)
		inode_free(target_dir);
	inode_free(old_file);
	inode_free(new_file);
	return status;

out_abort:
	if (txn->abort(txn))
		dbenv->err(dbenv, rc, "DB_ENV->txn_abort");
	goto out;
}
Beispiel #13
0
nfsstat4 nfs_op_remove(struct nfs_cxn *cxn, const REMOVE4args *args,
		       struct list_head *writes, struct rpc_write **wr)
{
	nfsstat4 status = NFS4_OK;
	struct nfs_inode *dir_ino = NULL, *target_ino = NULL;
	struct nfs_buf target;
	change_info4 cinfo = { true, 0, 0 };
	DB_TXN *txn = NULL;
	DB_ENV *dbenv = srv.fsdb.env;
	int rc;
	nfsino_t de_inum;

	target.len = args->target.utf8string_len;
	target.val = args->target.utf8string_val;

	if (debugging)
		applog(LOG_INFO, "op REMOVE ('%.*s')",
		       target.len,
		       target.val);

	if (target.len > SRV_MAX_NAME) {
		status = NFS4ERR_NAMETOOLONG;
		goto out;
	}

	if (!valid_utf8string(&target)) {
		status = NFS4ERR_INVAL;
		goto out;
	}
	if (has_dots(&target)) {
		status = NFS4ERR_BADNAME;
		goto out;
	}

	rc = dbenv->txn_begin(dbenv, NULL, &txn, 0);
	if (rc) {
		status = NFS4ERR_IO;
		dbenv->err(dbenv, rc, "DB_ENV->txn_begin");
		goto out;
	}

	/* reference container directory */
	status = dir_curfh(txn, cxn, &dir_ino, DB_RMW);
	if (status != NFS4_OK)
		goto out_abort;

	/* lookup target name in directory */
	status = dir_lookup(txn, dir_ino, &target, 0, &de_inum);
	if (status != NFS4_OK)
		goto out_abort;

	/* reference target inode */
	target_ino = inode_getdec(txn, de_inum, DB_RMW);
	if (!target_ino) {
		status = NFS4ERR_NOENT;
		goto out_abort;
	}

	/* prevent root dir deletion */
	if (target_ino->inum == INO_ROOT) {
		status = NFS4ERR_INVAL;
		goto out_abort;
	}

	/* prevent removal of non-empty dirs */
	if ((target_ino->type == NF4DIR) && !dir_is_empty(txn, target_ino)) {
		status = NFS4ERR_NOTEMPTY;
		goto out_abort;
	}

	/* remove target inode from directory */
	rc = fsdb_dirent_del(&srv.fsdb, txn, dir_ino->inum, &target, 0);
	if (rc) {
		status = NFS4ERR_IO;
		goto out_abort;
	}

	/* record directory change info */
	cinfo.before = dir_ino->version;

	rc = inode_touch(txn, dir_ino);
	if (rc) {
		status = NFS4ERR_IO;
		goto out_abort;
	}

	cinfo.after = dir_ino->version;

	/* remove link, possibly deleting inode */
	rc = inode_unlink(txn, target_ino);
	if (rc) {
		status = NFS4ERR_IO;
		goto out_abort;
	}

	rc = txn->commit(txn, 0);
	if (rc) {
		dbenv->err(dbenv, rc, "DB_ENV->txn_commit");
		status = NFS4ERR_IO;
		goto out;
	}

out:
	WR32(status);
	if (status == NFS4_OK) {
		WR32(cinfo.atomic ? 1 : 0);	/* cinfo.atomic */
		WR64(cinfo.before);		/* cinfo.before */
		WR64(cinfo.after);		/* cinfo.after */
	}
	inode_free(dir_ino);
	inode_free(target_ino);
	return status;

out_abort:
	if (txn->abort(txn))
		dbenv->err(dbenv, rc, "DB_ENV->txn_abort");
	goto out;
}
Beispiel #14
0
nfsstat4 nfs_op_link(struct nfs_cxn *cxn, const LINK4args *args,
		     struct list_head *writes, struct rpc_write **wr)
{
	nfsstat4 status;
	struct nfs_inode *dir_ino = NULL, *src_ino = NULL;
	struct nfs_buf newname;
	uint64_t before = 0, after = 0;
	DB_TXN *txn;
	DB_ENV *dbenv = srv.fsdb.env;
	int rc;

	newname.len = args->newname.utf8string_len;
	newname.val = args->newname.utf8string_val;

	if (debugging)
		applog(LOG_INFO, "op LINK (%.*s)",
		       newname.len,
		       newname.val);

	/* verify input parameters */
	if (!valid_fh(cxn->current_fh) || !valid_fh(cxn->save_fh)) {
		status = NFS4ERR_NOFILEHANDLE;
		goto out;
	}
	if (newname.len > SRV_MAX_NAME) {
		status = NFS4ERR_NAMETOOLONG;
		goto out;
	}

	/* open transaction */
	rc = dbenv->txn_begin(dbenv, NULL, &txn, 0);
	if (rc) {
		status = NFS4ERR_IO;
		dbenv->err(dbenv, rc, "DB_ENV->txn_begin");
		goto out;
	}

	/* read source inode's directory inode */
	dir_ino = inode_fhdec(txn, cxn->current_fh, 0);
	if (!dir_ino) {
		status = NFS4ERR_NOFILEHANDLE;
		goto out_abort;
	}

	/* make sure target is a directory */
	if (dir_ino->type != NF4DIR) {
		status = NFS4ERR_NOTDIR;
		goto out_abort;
	}

	/* read source inode */
	src_ino = inode_fhdec(txn, cxn->save_fh, 0);
	if (!src_ino) {
		status = NFS4ERR_NOFILEHANDLE;
		goto out_abort;
	}

	/* make sure source is a not a directory */
	if (src_ino->type == NF4DIR) {
		status = NFS4ERR_ISDIR;
		goto out_abort;
	}

	before = dir_ino->version;

	/* add directory entry */
	status = dir_add(txn, dir_ino, &newname, src_ino);
	if (status != NFS4_OK)
		goto out_abort;

	after = dir_ino->version;

	/* update source inode */
	src_ino->n_link++;
	if (inode_touch(txn, src_ino)) {
		status = NFS4ERR_IO;
		goto out_abort;
	}

	/* close transaction */
	rc = txn->commit(txn, 0);
	if (rc) {
		dbenv->err(dbenv, rc, "DB_ENV->txn_commit");
		status = NFS4ERR_IO;
		goto out;
	}

out:
	WR32(status);
	if (status == NFS4_OK) {
		WR32(1);		/* cinfo.atomic */
		WR64(before);		/* cinfo.before */
		WR64(after);		/* cinfo.after */
	}
	inode_free(src_ino);
	inode_free(dir_ino);
	return status;

out_abort:
	if (txn->abort(txn))
		dbenv->err(dbenv, rc, "DB_ENV->txn_abort");
	goto out;
}
Beispiel #15
0
nfsstat4 nfs_op_lookup(struct nfs_cxn *cxn, const LOOKUP4args *args,
		       struct list_head *writes, struct rpc_write **wr)
{
	nfsstat4 status = NFS4_OK;
	struct nfs_inode *ino = NULL;
	bool printed = false;
	struct nfs_buf objname;
	nfsino_t inum;
	DB_TXN *txn = NULL;
	DB_ENV *dbenv = srv.fsdb.env;
	int rc;

	objname.len = args->objname.utf8string_len;
	objname.val = args->objname.utf8string_val;

	if (!objname.len) {
		status = NFS4ERR_INVAL;
		goto out;
	}
	if (!objname.val) {
		status = NFS4ERR_BADXDR;
		goto out;
	}

	if (objname.len > SRV_MAX_NAME) {
		status = NFS4ERR_NAMETOOLONG;
		goto out;
	}

	rc = dbenv->txn_begin(dbenv, NULL, &txn, 0);
	if (rc) {
		status = NFS4ERR_IO;
		dbenv->err(dbenv, rc, "DB_ENV->txn_begin");
		goto out;
	}

	status = dir_curfh(txn, cxn, &ino, 0);
	if (status != NFS4_OK) {
		if ((status == NFS4ERR_NOTDIR) &&
		    (ino->type == NF4LNK))
			status = NFS4ERR_SYMLINK;
		goto out_abort;
	}

	status = dir_lookup(txn, ino, &objname, 0, &inum);
	if (status != NFS4_OK)
		goto out_abort;

	rc = txn->commit(txn, 0);
	if (rc) {
		dbenv->err(dbenv, rc, "DB_ENV->txn_commit");
		status = NFS4ERR_IO;
		goto out;
	}

	fh_set(&cxn->current_fh, inum);

	if (debugging) {
		applog(LOG_INFO, "op LOOKUP ('%.*s') -> %016llX",
		       objname.len,
		       objname.val,
		       (unsigned long long) cxn->current_fh.inum);
		printed = true;
	}

out:
	if (!printed) {
		if (debugging)
			applog(LOG_INFO, "op LOOKUP ('%.*s')",
			       objname.len,
			       objname.val);
	}

	WR32(status);
	inode_free(ino);
	return status;

out_abort:
	if (txn->abort(txn))
		dbenv->err(dbenv, rc, "DB_ENV->txn_abort");
	goto out;
}