Example #1
0
File: btree.c Project: taysom/tau
static int join_branch (
	tree_s		*tree,
	branch_s	*parent,
	branch_s	*child,
	int		k)
{
	branch_s	*sibling;

	sibling = bget(tree->t_dev, parent->br_key[k+1].k_block);
	if (!sibling) {
		return qERR_NOT_FOUND;
	}
	if (child->br_num+sibling->br_num < KEYS_PER_BRANCH-1) {
FN;
		child->br_key[child->br_num].k_key = parent->br_key[k+1].k_key;
		child->br_key[child->br_num].k_block = sibling->br_first;
		++child->br_num;
		memmove( &child->br_key[child->br_num], sibling->br_key,
			sibling->br_num * sizeof(sibling->br_key[0]));
		child->br_num += sibling->br_num;
		bdirty(child);

		memmove( &parent->br_key[k+1], &parent->br_key[k+2],
			sizeof(parent->br_key[0]) * (parent->br_num - (k+2)));
		--parent->br_num;
		bdirty(parent);
	}
	bput(sibling);	// Sibling should be freed.
	return 0;
}
Example #2
0
/* Find a free entity in the bitmap starting at block BMAP-START on device
   DEV which contains BMAP-LEN bits. Sets the free bit it finds then returns
   the bit number, or NO_FREE_BLOCK if an error or all bits are set. */
blkno
bmap_alloc(struct fs_device *dev, blkno bmap_start, u_long bmap_len)
{
    blkno bmap_blk = bmap_start;
    while(bmap_len > 0)
    {
	int len, bit;
	struct buf_head *buf = bread(dev, bmap_blk);
	if(buf == NULL)
	    return -1;
	len = min(bmap_len, FS_BLKSIZ * 8);
	FORBID();
	bit = find_zero_bit(buf->buf.bmap, len);
	if(bit != -1)
	{
	    set_bit(buf->buf.bmap, bit);
	    PERMIT();
	    bdirty(buf, TRUE);
	    brelse(buf);
	    return ((bmap_blk - bmap_start) * FS_BLKSIZ * 8) + bit;
	}
	PERMIT();
	brelse(buf);
	bmap_len -= len;
	bmap_blk++;
    }
    ERRNO = E_NOSPC;
    return NO_FREE_BLOCK;
}
Example #3
0
File: btree.c Project: taysom/tau
bool split_leaf (void *self, branch_s *parent, int k, unint len)
{
	leaf_s	*child = self;
	leaf_s	*sibling;
	int	upper;
	u64	upper_key;
FN;
	if (!leaf_is_full(child, len)) {
		return FALSE;
	}
	sibling = new_leaf(bdev(parent));

	upper = (child->l_num + 1) / 2;
	upper_key = child->l_rec[upper].r_key;

	copy_recs(sibling, child, upper);

	child->l_num = upper;
	child->l_total += (BLK_SIZE - sizeof(leaf_s)) - sibling->l_total;
	bdirty(child);
	bput(child);

	insert_sibling(parent, sibling, k, upper_key);
	bput(sibling);
	return TRUE;
}
Example #4
0
/*
 * ino_dirty()
 *	Purge a directory entry back to the fs
 * 
 * Whenever we have completed a series of modifications to some inode
 * data we need to write them back to the disk in the directory.
 */
void
ino_dirty(struct inode *i)
{
	struct dirent *d;
	void *handle;
	
	/*
	 * First off grab the directory info off the disk
	 */
	handle = bget(i->i_dirblk);
	if (handle == NULL ) {
		perror("bfs ino_dirty");
		exit(1);
	}
	d = (struct dirent *)((char *)bdata(handle) + i->i_diroff);

	/*
	 * Then write the new information into the buffer
	 */
	memcpy(d->d_name, i->i_name, BFSNAMELEN);
	d->d_inum = i->i_num;
	d->d_start = i->i_start;
	d->d_len = i->i_fsize;

	/*
	 * Then mark the buffer dirty and free the space
	 */
	bdirty(handle);
	bfree(handle);
}
Example #5
0
File: btree.c Project: taysom/tau
bool split_branch (void *self, branch_s *parent, int k)
{
	branch_s	*child  = self;
	branch_s	*sibling;
	int		upper;
	int		midpoint;
	u64		midpoint_key;
FN;
	if (!branch_is_full(child)) return FALSE;

	sibling = new_branch(bdev(child));

	midpoint = child->br_num / 2;
	upper = midpoint + 1;

	sibling->br_first = child->br_key[midpoint].k_block;
	midpoint_key      = child->br_key[midpoint].k_key;

	memmove(sibling->br_key, &child->br_key[upper],
		sizeof(key_s) * (child->br_num - upper));
	sibling->br_num = child->br_num - upper;

	child->br_num = midpoint;
	bdirty(child);
	bput(child);

	insert_sibling(parent, sibling, k, midpoint_key);
	bput(sibling);
	return TRUE;
}
Example #6
0
File: btree.c Project: taysom/tau
static int join_leaf (
	tree_s 		*tree,
	branch_s	*parent,
	leaf_s		*child,
	int		k)
{
	leaf_s	*sibling;

	sibling = bget(tree->t_dev, parent->br_key[k+1].k_block);
	if (!sibling) return qERR_NOT_FOUND;

	if (child->l_total + sibling->l_total > MAX_FREE) {
FN;
		compact(child);
		compact(sibling);
		copy_recs(child, sibling, 0);
		memmove( &parent->br_key[k+1], &parent->br_key[k+2],
			sizeof(parent->br_key[0]) * (parent->br_num - (k+2)));
		--parent->br_num;
		bdirty(parent);
	}
	//verify_leaf(child, WHERE);
	bput(sibling);	// Should free sibling
	return 0;
}
Example #7
0
File: inode.c Project: taysom/tau
buf_s *alloc_block (dev_s *dev)
{
    super_s	*super;
    buf_s	*buf;
    u64	blkno;
    FN;
    buf = bget(dev, SUPER_BLOCK);
    super = buf->b_data;

    if (super->sp_magic != SUPER_MAGIC) {
        eprintf("no super block");
    }
    blkno = super->sp_next++;
    PRd(blkno);
    bdirty(buf);
    bput(buf);

    buf = bnew(dev, blkno);
    bdirty(buf);
    return buf;
}
Example #8
0
/*
 * blk_alloc()
 *	Request an existing file have its allocation increased
 *
 * Returns 0 on success, 1 on failure.
 */
int
blk_alloc(struct inode *i, uint newsize)
{
	/*
	 * If the start is 0, it's "truncated" or new, so we update
	 * it to the current place our free blocks start, and put it into
	 * the block allocation list.
	 */
	if (i->i_start == 0) {
		ASSERT_DEBUG(i->i_fsize == 0, "blk_alloc: trunc with length");
		i->i_start = spc_inode->i_start 
				+ BLOCKS(spc_inode->i_fsize);
		ino_addblklist(i);
	}

	/*
	 * We now decide what alterations need to be made to the block
	 * allocations within the inode.  First we check that we have enough
	 * space available to allocate the required data
	 */
	if (BLOCKS(newsize) > i->i_blocks) {
		/*
		 * We really ought to be far more intelligent about what
		 * we do here - my ideas so far are to first try and
		 * grab some space from a near neighbour - if one has some.
		 * Next we try moving the file (or if a neighbour's smaller
		 * and freeing the space will be enough we move the
		 * neighbour) to the largest free slot available (if that's
		 * big enough) and finally if all else fails we'll compact
		 * the whole fs down!
		 */
		return 1;
	}

	/*
	 * OK, so there's enough space to allocate the required blocks.
	 * Now we juggle the block details within the inode to reflect the
	 * changes
	 */
	i->i_fsize = newsize;

	/*
	 * Mark the inode dirty.  Superblock probably also dirty; mark it so.
	 */
	ino_dirty(i);
	bdirty(shandle);

	return 0;
}
Example #9
0
File: btree.c Project: taysom/tau
void delete_leaf (leaf_s *leaf, u64 key)
{
	rec_s	*r;
FN;
	r = find_rec(leaf, key);
	if (r) {
		leaf->l_total += sizeof(rec_s) + r->r_len;
		memmove(r, r + 1,
			(char *)&leaf->l_rec[--leaf->l_num] - (char *)r);
		bdirty(leaf);
		return;
	}
	printf("Key not found %llu\n", key);
	exit(2);
}
Example #10
0
File: btree.c Project: taysom/tau
void insert_sibling (branch_s *parent, void *sibling, int k, u64 key)
{
	int		slot;
FN;
	/* make a hole -- only if not at end */
	slot = k + 1;
	if (slot < parent->br_num) {
		memmove( &parent->br_key[slot+1],
			 &parent->br_key[slot],
			 sizeof(key_s) * (parent->br_num - slot));
	}
	parent->br_key[slot].k_key   = key;
	parent->br_key[slot].k_block = bblkno(sibling);
	++parent->br_num;
	bdirty(parent);
}
Example #11
0
File: twins.c Project: wtaysom/tau
static void init_super_block (tree_s *tree)
{
	super_s	*super;
	buf_s	*buf;

	buf = bget(tree->t_dev, SUPER_BLOCK);
	super = buf->b_data;
	if (super->sp_magic != SUPER_MAGIC) {
		super->sp_magic = SUPER_MAGIC;
		super->sp_root  = 0;
		super->sp_next  = SUPER_BLOCK + 1;

		bdirty(buf);
	}
	bput(buf);
}
Example #12
0
File: twins.c Project: wtaysom/tau
int change_root_string (tree_s *tree, buf_s *root)
{
	super_s	*super;
	buf_s	*buf;
FN;
	buf = bget(tree->t_dev, SUPER_BLOCK);
	if (!buf) {
		eprintf("change_root_string: no super block");
		return qERR_NOT_FOUND;
	}
	super = buf->b_data;
	super->sp_root = root->b_blknum;
	bdirty(buf);
	bput(buf);
	return 0;
}
Example #13
0
File: btree.c Project: taysom/tau
void compact (leaf_s *leaf)
{
	static char	block[BLK_SIZE];
	leaf_s		*p;
FN;
	// Need a spin lock here
	p = (leaf_s *)block;
	bzero(p, BLK_SIZE);
	p->l_type = leaf->l_type;
	p->l_end  = BLK_SIZE;
	p->l_total = MAX_FREE;

	copy_recs(p, leaf, 0);
	memmove(leaf, p, BLK_SIZE);
	aver(leaf->l_total == free_space(leaf));
	bdirty(leaf);
}
Example #14
0
File: inode.c Project: taysom/tau
u64 alloc_ino (dev_s *dev)
{
    super_s	*super;
    buf_s	*buf;
    u64	ino;
    FN;
    buf = bget(dev, SUPER_BLOCK);
    super = buf->b_data;

    if (super->sp_magic != SUPER_MAGIC) {
        eprintf("no super block");
    }
    ino = super->sp_ino++;
    bdirty(buf);
    bput(buf);

    return ino;
}
Example #15
0
File: inode.c Project: taysom/tau
static void init_super_block (void)
{
    super_s	*super;
    buf_s	*buf;
    FN;
    buf = bget(Inode_tree.t_dev, SUPER_BLOCK);
    super = buf->b_data;
    if (super->sp_magic != SUPER_MAGIC) {
        super->sp_magic = SUPER_MAGIC;
        super->sp_root  = 0;
        super->sp_next  = SUPER_BLOCK + 1;
        super->sp_ino   = ROOT_INO + 1;

        bdirty(buf);
    }
    bput(buf);

    init_root_inode();
}
Example #16
0
File: twins.c Project: wtaysom/tau
static int redo_alloc_block (log_s *log, logrec_s *logrec)
{
	super_s	*super;
	buf_s	*buf;
FN;
	buf = bget(log->lg_sys, SUPER_BLOCK);
	if (!buf) {
		eprintf("redo_alloc_block: no super block");
		return qERR_NOT_FOUND;
	}
	super = buf->b_data;
	if (logrec->lr_lsn <= super->sp_lsn) {
		bput(buf);
		return 0;
	}
	super->sp_lsn = logrec->lr_lsn;
	super->sp_next = logrec->lr_user[0];
	bdirty(buf);
	bput(buf);
	return 0;
}
Example #17
0
/* Mark the entity at bit number BIT of the bitmap starting at block
   BMAP-START of device DEV. Return TRUE if no errors occurred. */
bool
bmap_free(struct fs_device *dev, blkno bmap_start, u_long bit)
{
    blkno bmap_blk = (bit / (FS_BLKSIZ * 8)) + bmap_start;
    struct buf_head *buf = bread(dev, bmap_blk);
    if(buf == NULL)
	return FALSE;
    bit = bit % (FS_BLKSIZ * 8);
    if(!test_bit(buf->buf.bmap, bit))
    {
	kprintf("fs: Oops, freeing a free bit (%u) in bitmap %u\n",
		bit, bmap_start);
    }
    else
    {
	clear_bit(buf->buf.bmap, bit);
	bdirty(buf, TRUE);
    }
    brelse(buf);
    return TRUE;
}
Example #18
0
File: btree.c Project: taysom/tau
int insert_leaf (tree_s *tree, leaf_s *leaf, u64 key, void *rec, unint len)
{
	rec_s	*r;
	int	total = len + sizeof(rec_s);
FN;
	r = leaf_search(leaf, key);
	if (found(leaf, r, key)) {
		bput(leaf);
		return qERR_DUP;
	}
	memmove(r + 1, r, (char *)&leaf->l_rec[leaf->l_num] - (char *)r);
	++leaf->l_num;
	leaf->l_total -= total;
	leaf->l_end -= len;
	r->r_start = leaf->l_end;
	r->r_len   = len;
	r->r_key   = key;
	pack_rec(tree, (u8 *)leaf + r->r_start, rec, len);
	bdirty(leaf);
	bput(leaf);
	return 0;
}
Example #19
0
/*
 * blk_trunc()
 *	Remove the blocks from under the named file
 *
 * The freed blocks are allocated back onto the previous inode's managed
 * list.  Note that we don't mark the inode dirty.  This is because the
 * caller will often *further* dirty the inode, so no need to do it twice.
 */
void
blk_trunc(struct inode *i)
{
	int blocks;

	/*
	 * Add blocks worth of storage back onto free count
	 */
	blocks = BLOCKS(i->i_fsize);
	sblock->s_free += blocks;

	/*
	 * Flag start/len as 0.  blk_alloc() will notice this
	 * and update where the free blocks start.
	 */
	i->i_start = i->i_fsize = 0;
	bdirty(shandle);

	/*
	 * Sort out all references to our former block neighbours
	 */
	if (i->i_prev != I_FREE) {
		ilist[i->i_prev]->i_next = i->i_next;
		ilist[i->i_prev]->i_blocks += i->i_blocks;
		if (i == spc_inode) {
			spc_inode = ilist[i->i_prev];
		}
	}
	if (i->i_next != I_FREE ) {
		ilist[i->i_next]->i_prev = i->i_prev;
	}

	/*
	 * Finally remove references to our former neighbours
	 */
	i->i_next = I_FREE;
	i->i_prev = I_FREE;
}
Example #20
0
/*
 * Do an I/O operation to/from a cache block.
 */
int
smbfs_doio(struct vnode *vp, struct bio *bio, struct ucred *cr, struct thread *td)
{
	struct buf *bp = bio->bio_buf;
	struct smbmount *smp = VFSTOSMBFS(vp->v_mount);
	struct smbnode *np = VTOSMB(vp);
	struct uio uio, *uiop = &uio;
	struct iovec io;
	struct smb_cred scred;
	int error = 0;

	uiop->uio_iov = &io;
	uiop->uio_iovcnt = 1;
	uiop->uio_segflg = UIO_SYSSPACE;
	uiop->uio_td = td;

	smb_makescred(&scred, td, cr);

	if (bp->b_cmd == BUF_CMD_READ) {
	    io.iov_len = uiop->uio_resid = (size_t)bp->b_bcount;
	    io.iov_base = bp->b_data;
	    uiop->uio_rw = UIO_READ;
	    switch (vp->v_type) {
	      case VREG:
		uiop->uio_offset = bio->bio_offset;
		error = smb_read(smp->sm_share, np->n_fid, uiop, &scred);
		if (error)
			break;
		if (uiop->uio_resid) {
			size_t left = uiop->uio_resid;
			size_t nread = (size_t)bp->b_bcount - left;
			if (left > 0)
				bzero((char *)bp->b_data + nread, left);
		}
		break;
	    default:
		kprintf("smbfs_doio:  type %x unexpected\n",vp->v_type);
		break;
	    };
	    if (error) {
		bp->b_error = error;
		bp->b_flags |= B_ERROR;
	    }
	} else { /* write */
	    KKASSERT(bp->b_cmd == BUF_CMD_WRITE);
	    if (bio->bio_offset + bp->b_dirtyend > np->n_size)
		bp->b_dirtyend = np->n_size - bio->bio_offset;

	    if (bp->b_dirtyend > bp->b_dirtyoff) {
		io.iov_len = uiop->uio_resid =
			(size_t)(bp->b_dirtyend - bp->b_dirtyoff);
		uiop->uio_offset = bio->bio_offset + bp->b_dirtyoff;
		io.iov_base = (char *)bp->b_data + bp->b_dirtyoff;
		uiop->uio_rw = UIO_WRITE;
		error = smb_write(smp->sm_share, np->n_fid, uiop, &scred);

		/*
		 * For an interrupted write, the buffer is still valid
		 * and the write hasn't been pushed to the server yet,
		 * so we can't set BIO_ERROR and report the interruption
		 * by setting B_EINTR. For the async case, B_EINTR
		 * is not relevant, so the rpc attempt is essentially
		 * a noop.  For the case of a V3 write rpc not being
		 * committed to stable storage, the block is still
		 * dirty and requires either a commit rpc or another
		 * write rpc with iomode == NFSV3WRITE_FILESYNC before
		 * the block is reused. This is indicated by setting
		 * the B_DELWRI and B_NEEDCOMMIT flags.
		 */
    		if (error == EINTR
		    || (!error && (bp->b_flags & B_NEEDCOMMIT))) {

			crit_enter();
			bp->b_flags &= ~(B_INVAL|B_NOCACHE);
			if ((bp->b_flags & B_PAGING) == 0)
			    bdirty(bp);
			bp->b_flags |= B_EINTR;
			crit_exit();
	    	} else {
			if (error) {
				bp->b_flags |= B_ERROR;
				bp->b_error = error;
			}
			bp->b_dirtyoff = bp->b_dirtyend = 0;
		}
	    } else {
		bp->b_resid = 0;
		biodone(bio);
		return 0;
	    }
	}
	bp->b_resid = uiop->uio_resid;
	biodone(bio);
	return error;
}
Example #21
0
int
fuse_io_strategy(struct vnode *vp, struct buf *bp)
{
	struct fuse_filehandle *fufh;
	struct fuse_vnode_data *fvdat = VTOFUD(vp);
	struct ucred *cred;
	struct uio *uiop;
	struct uio uio;
	struct iovec io;
	int error = 0;

	const int biosize = fuse_iosize(vp);

	MPASS(vp->v_type == VREG || vp->v_type == VDIR);
	MPASS(bp->b_iocmd == BIO_READ || bp->b_iocmd == BIO_WRITE);
	FS_DEBUG("inode=%ju offset=%jd resid=%ld\n",
	    (uintmax_t)VTOI(vp), (intmax_t)(((off_t)bp->b_blkno) * biosize),
	    bp->b_bcount);

	error = fuse_filehandle_getrw(vp,
	    (bp->b_iocmd == BIO_READ) ? FUFH_RDONLY : FUFH_WRONLY, &fufh);
	if (error) {
		printf("FUSE: strategy: filehandles are closed\n");
		bp->b_ioflags |= BIO_ERROR;
		bp->b_error = error;
		return (error);
	}
	cred = bp->b_iocmd == BIO_READ ? bp->b_rcred : bp->b_wcred;

	uiop = &uio;
	uiop->uio_iov = &io;
	uiop->uio_iovcnt = 1;
	uiop->uio_segflg = UIO_SYSSPACE;
	uiop->uio_td = curthread;

	/*
         * clear BIO_ERROR and B_INVAL state prior to initiating the I/O.  We
         * do this here so we do not have to do it in all the code that
         * calls us.
         */
	bp->b_flags &= ~B_INVAL;
	bp->b_ioflags &= ~BIO_ERROR;

	KASSERT(!(bp->b_flags & B_DONE),
	    ("fuse_io_strategy: bp %p already marked done", bp));
	if (bp->b_iocmd == BIO_READ) {
		io.iov_len = uiop->uio_resid = bp->b_bcount;
		io.iov_base = bp->b_data;
		uiop->uio_rw = UIO_READ;

		uiop->uio_offset = ((off_t)bp->b_blkno) * biosize;
		error = fuse_read_directbackend(vp, uiop, cred, fufh);

		if ((!error && uiop->uio_resid) ||
		    (fsess_opt_brokenio(vnode_mount(vp)) && error == EIO &&
		    uiop->uio_offset < fvdat->filesize && fvdat->filesize > 0 &&
		    uiop->uio_offset >= fvdat->cached_attrs.va_size)) {
			/*
	                 * If we had a short read with no error, we must have
	                 * hit a file hole.  We should zero-fill the remainder.
	                 * This can also occur if the server hits the file EOF.
	                 *
	                 * Holes used to be able to occur due to pending
	                 * writes, but that is not possible any longer.
	                 */
			int nread = bp->b_bcount - uiop->uio_resid;
			int left = uiop->uio_resid;

			if (error != 0) {
				printf("FUSE: Fix broken io: offset %ju, "
				       " resid %zd, file size %ju/%ju\n", 
				       (uintmax_t)uiop->uio_offset,
				    uiop->uio_resid, fvdat->filesize,
				    fvdat->cached_attrs.va_size);
				error = 0;
			}
			if (left > 0)
				bzero((char *)bp->b_data + nread, left);
			uiop->uio_resid = 0;
		}
		if (error) {
			bp->b_ioflags |= BIO_ERROR;
			bp->b_error = error;
		}
	} else {
		/*
	         * If we only need to commit, try to commit
	         */
		if (bp->b_flags & B_NEEDCOMMIT) {
			FS_DEBUG("write: B_NEEDCOMMIT flags set\n");
		}
		/*
	         * Setup for actual write
	         */
		if ((off_t)bp->b_blkno * biosize + bp->b_dirtyend > 
		    fvdat->filesize)
			bp->b_dirtyend = fvdat->filesize - 
				(off_t)bp->b_blkno * biosize;

		if (bp->b_dirtyend > bp->b_dirtyoff) {
			io.iov_len = uiop->uio_resid = bp->b_dirtyend
			    - bp->b_dirtyoff;
			uiop->uio_offset = (off_t)bp->b_blkno * biosize
			    + bp->b_dirtyoff;
			io.iov_base = (char *)bp->b_data + bp->b_dirtyoff;
			uiop->uio_rw = UIO_WRITE;

			error = fuse_write_directbackend(vp, uiop, cred, fufh, 0);

			if (error == EINTR || error == ETIMEDOUT
			    || (!error && (bp->b_flags & B_NEEDCOMMIT))) {

				bp->b_flags &= ~(B_INVAL | B_NOCACHE);
				if ((bp->b_flags & B_PAGING) == 0) {
					bdirty(bp);
					bp->b_flags &= ~B_DONE;
				}
				if ((error == EINTR || error == ETIMEDOUT) &&
				    (bp->b_flags & B_ASYNC) == 0)
					bp->b_flags |= B_EINTR;
			} else {
				if (error) {
					bp->b_ioflags |= BIO_ERROR;
					bp->b_flags |= B_INVAL;
					bp->b_error = error;
				}
				bp->b_dirtyoff = bp->b_dirtyend = 0;
			}
		} else {
			bp->b_resid = 0;
			bufdone(bp);
			return (0);
		}
	}
	bp->b_resid = uiop->uio_resid;
	bufdone(bp);
	return (error);
}
Example #22
0
/*
 * Do an I/O operation to/from a cache block.
 */
int
nwfs_doio(struct vnode *vp, struct bio *bio, struct ucred *cr, struct thread *td)
{
	struct buf *bp = bio->bio_buf;
	struct uio *uiop;
	struct nwnode *np;
	struct nwmount *nmp;
	int error = 0;
	struct uio uio;
	struct iovec io;

	np = VTONW(vp);
	nmp = VFSTONWFS(vp->v_mount);
	uiop = &uio;
	uiop->uio_iov = &io;
	uiop->uio_iovcnt = 1;
	uiop->uio_segflg = UIO_SYSSPACE;
	uiop->uio_td = td;

	if (bp->b_cmd == BUF_CMD_READ) {
	    io.iov_len = uiop->uio_resid = (size_t)bp->b_bcount;
	    io.iov_base = bp->b_data;
	    uiop->uio_rw = UIO_READ;
	    switch (vp->v_type) {
	      case VREG:
		uiop->uio_offset = bio->bio_offset;
		error = ncp_read(NWFSTOCONN(nmp), &np->n_fh, uiop, cr);
		if (error)
			break;
		if (uiop->uio_resid) {
			size_t left = uiop->uio_resid;
			size_t nread = bp->b_bcount - left;
			if (left > 0)
				bzero((char *)bp->b_data + nread, left);
		}
		break;
/*	    case VDIR:
		nfsstats.readdir_bios++;
		uiop->uio_offset = bio->bio_offset;
		if (nmp->nm_flag & NFSMNT_RDIRPLUS) {
			error = nfs_readdirplusrpc(vp, uiop, cr);
			if (error == NFSERR_NOTSUPP)
				nmp->nm_flag &= ~NFSMNT_RDIRPLUS;
		}
		if ((nmp->nm_flag & NFSMNT_RDIRPLUS) == 0)
			error = nfs_readdirrpc(vp, uiop, cr);
		if (error == 0 && uiop->uio_resid == (size_t)bp->b_bcount)
			bp->b_flags |= B_INVAL;
		break;
*/
	    default:
		kprintf("nwfs_doio:  type %x unexpected\n",vp->v_type);
		break;
	    }
	    if (error) {
		bp->b_flags |= B_ERROR;
		bp->b_error = error;
	    }
	} else { /* write */
	    KKASSERT(bp->b_cmd == BUF_CMD_WRITE);
	    if (bio->bio_offset + bp->b_dirtyend > np->n_size)
		bp->b_dirtyend = np->n_size - bio->bio_offset;

	    if (bp->b_dirtyend > bp->b_dirtyoff) {
		io.iov_len = uiop->uio_resid =
			(size_t)(bp->b_dirtyend - bp->b_dirtyoff);
		uiop->uio_offset = bio->bio_offset + bp->b_dirtyoff;
		io.iov_base = (char *)bp->b_data + bp->b_dirtyoff;
		uiop->uio_rw = UIO_WRITE;
		error = ncp_write(NWFSTOCONN(nmp), &np->n_fh, uiop, cr);

		/*
		 * For an interrupted write, the buffer is still valid
		 * and the write hasn't been pushed to the server yet,
		 * so we can't set B_ERROR and report the interruption
		 * by setting B_EINTR. For the async case, B_EINTR
		 * is not relevant, so the rpc attempt is essentially
		 * a noop.  For the case of a V3 write rpc not being
		 * committed to stable storage, the block is still
		 * dirty and requires either a commit rpc or another
		 * write rpc with iomode == NFSV3WRITE_FILESYNC before
		 * the block is reused. This is indicated by setting
		 * the B_DELWRI and B_NEEDCOMMIT flags.
		 */
    		if (error == EINTR
		    || (!error && (bp->b_flags & B_NEEDCOMMIT))) {

			crit_enter();
			bp->b_flags &= ~(B_INVAL|B_NOCACHE);
			if ((bp->b_flags & B_PAGING) == 0)
			    bdirty(bp);
			bp->b_flags |= B_EINTR;
			crit_exit();
	    	} else {
			if (error) {
				bp->b_flags |= B_ERROR;
				bp->b_error /*= np->n_error */= error;
/*				np->n_flag |= NWRITEERR;*/
			}
			bp->b_dirtyoff = bp->b_dirtyend = 0;
		}
	    } else {
		bp->b_resid = 0;
		biodone(bio);
		return (0);
	    }
	}
	bp->b_resid = (int)uiop->uio_resid;
	biodone(bio);
	return (error);
}
Example #23
0
/*
 * Do an I/O operation to/from a cache block.
 */
int
smbfs_doio(struct vnode *vp, struct buf *bp, struct ucred *cr, struct thread *td)
{
	struct smbmount *smp = VFSTOSMBFS(vp->v_mount);
	struct smbnode *np = VTOSMB(vp);
	struct uio *uiop;
	struct iovec io;
	struct smb_cred *scred;
	int error = 0;

	uiop = malloc(sizeof(struct uio), M_SMBFSDATA, M_WAITOK);
	uiop->uio_iov = &io;
	uiop->uio_iovcnt = 1;
	uiop->uio_segflg = UIO_SYSSPACE;
	uiop->uio_td = td;

	scred = smbfs_malloc_scred();
	smb_makescred(scred, td, cr);

	if (bp->b_iocmd == BIO_READ) {
	    io.iov_len = uiop->uio_resid = bp->b_bcount;
	    io.iov_base = bp->b_data;
	    uiop->uio_rw = UIO_READ;
	    switch (vp->v_type) {
	      case VREG:
		uiop->uio_offset = ((off_t)bp->b_blkno) * DEV_BSIZE;
		error = smb_read(smp->sm_share, np->n_fid, uiop, scred);
		if (error)
			break;
		if (uiop->uio_resid) {
			int left = uiop->uio_resid;
			int nread = bp->b_bcount - left;
			if (left > 0)
			    bzero((char *)bp->b_data + nread, left);
		}
		break;
	    default:
		printf("smbfs_doio:  type %x unexpected\n",vp->v_type);
		break;
	    };
	    if (error) {
		bp->b_error = error;
		bp->b_ioflags |= BIO_ERROR;
	    }
	} else { /* write */
	    if (((bp->b_blkno * DEV_BSIZE) + bp->b_dirtyend) > np->n_size)
		bp->b_dirtyend = np->n_size - (bp->b_blkno * DEV_BSIZE);

	    if (bp->b_dirtyend > bp->b_dirtyoff) {
		io.iov_len = uiop->uio_resid = bp->b_dirtyend - bp->b_dirtyoff;
		uiop->uio_offset = ((off_t)bp->b_blkno) * DEV_BSIZE + bp->b_dirtyoff;
		io.iov_base = (char *)bp->b_data + bp->b_dirtyoff;
		uiop->uio_rw = UIO_WRITE;
		error = smb_write(smp->sm_share, np->n_fid, uiop, scred);

		/*
		 * For an interrupted write, the buffer is still valid
		 * and the write hasn't been pushed to the server yet,
		 * so we can't set BIO_ERROR and report the interruption
		 * by setting B_EINTR. For the B_ASYNC case, B_EINTR
		 * is not relevant, so the rpc attempt is essentially
		 * a noop.  For the case of a V3 write rpc not being
		 * committed to stable storage, the block is still
		 * dirty and requires either a commit rpc or another
		 * write rpc with iomode == NFSV3WRITE_FILESYNC before
		 * the block is reused. This is indicated by setting
		 * the B_DELWRI and B_NEEDCOMMIT flags.
		 */
		if (error == EINTR
		    || (!error && (bp->b_flags & B_NEEDCOMMIT))) {
			int s;

			s = splbio();
			bp->b_flags &= ~(B_INVAL|B_NOCACHE);
			if ((bp->b_flags & B_ASYNC) == 0)
			    bp->b_flags |= B_EINTR;
			if ((bp->b_flags & B_PAGING) == 0) {
			    bdirty(bp);
			    bp->b_flags &= ~B_DONE;
			}
			if ((bp->b_flags & B_ASYNC) == 0)
			    bp->b_flags |= B_EINTR;
			splx(s);
		} else {
			if (error) {
				bp->b_ioflags |= BIO_ERROR;
				bp->b_error = error;
			}
			bp->b_dirtyoff = bp->b_dirtyend = 0;
		}
	    } else {
		bp->b_resid = 0;
		bufdone(bp);
		free(uiop, M_SMBFSDATA);
		smbfs_free_scred(scred);
		return 0;
	    }
	}
	bp->b_resid = uiop->uio_resid;
	bufdone(bp);
	free(uiop, M_SMBFSDATA);
	smbfs_free_scred(scred);
	return error;
}
Example #24
0
int
puffs_doio(struct vnode *vp, struct bio *bio, struct thread *td)
{
	struct buf *bp = bio->bio_buf;
	struct ucred *cred;
	struct uio *uiop;
	struct uio uio;
	struct iovec io;
	size_t n;
	int error = 0;

	if (td != NULL && td->td_proc != NULL)
		cred = td->td_proc->p_ucred;
	else
		cred = proc0.p_ucred;

	uiop = &uio;
	uiop->uio_iov = &io;
	uiop->uio_iovcnt = 1;
	uiop->uio_segflg = UIO_SYSSPACE;
	uiop->uio_td = td;

	/*
	 * clear B_ERROR and B_INVAL state prior to initiating the I/O.  We
	 * do this here so we do not have to do it in all the code that
	 * calls us.
	 */
	bp->b_flags &= ~(B_ERROR | B_INVAL);

	KASSERT(bp->b_cmd != BUF_CMD_DONE,
	    ("puffs_doio: bp %p already marked done!", bp));

	if (bp->b_cmd == BUF_CMD_READ) {
		io.iov_len = uiop->uio_resid = (size_t)bp->b_bcount;
		io.iov_base = bp->b_data;
		uiop->uio_rw = UIO_READ;

		uiop->uio_offset = bio->bio_offset;
		error = puffs_directread(vp, uiop, 0, cred);
		if (error == 0 && uiop->uio_resid) {
			n = (size_t)bp->b_bcount - uiop->uio_resid;
			bzero(bp->b_data + n, bp->b_bcount - n);
			uiop->uio_resid = 0;
		}
		if (error) {
			bp->b_flags |= B_ERROR;
			bp->b_error = error;
		}
		bp->b_resid = uiop->uio_resid;
	} else {
		KKASSERT(bp->b_cmd == BUF_CMD_WRITE);
		if (bio->bio_offset + bp->b_dirtyend > puffs_meta_getsize(vp))
			bp->b_dirtyend = puffs_meta_getsize(vp) -
			    bio->bio_offset;

		if (bp->b_dirtyend > bp->b_dirtyoff) {
			io.iov_len = uiop->uio_resid = bp->b_dirtyend
			    - bp->b_dirtyoff;
			uiop->uio_offset = bio->bio_offset + bp->b_dirtyoff;
			io.iov_base = (char *)bp->b_data + bp->b_dirtyoff;
			uiop->uio_rw = UIO_WRITE;

			error = puffs_directwrite(vp, uiop, 0, cred);

			if (error == EINTR
			    || (!error && (bp->b_flags & B_NEEDCOMMIT))) {
				crit_enter();
				bp->b_flags &= ~(B_INVAL|B_NOCACHE);
				if ((bp->b_flags & B_PAGING) == 0)
					bdirty(bp);
				if (error)
					bp->b_flags |= B_EINTR;
				crit_exit();
			} else {
				if (error) {
					bp->b_flags |= B_ERROR;
					bp->b_error = error;
				}
				bp->b_dirtyoff = bp->b_dirtyend = 0;
			}
			bp->b_resid = uiop->uio_resid;
		} else {
			bp->b_resid = 0;
		}
	}

	biodone(bio);
	KKASSERT(bp->b_cmd == BUF_CMD_DONE);
	if (bp->b_flags & B_EINTR)
		return (EINTR);
	if (bp->b_flags & B_ERROR)
		return (bp->b_error ? bp->b_error : EIO);
	return (0);
}