示例#1
0
static void onefs_cbrl_async_success(uint64_t id)
{
	struct blocking_lock_record *blr;
	struct onefs_cbrl_blr_state *bs;
	uint16 num_locks;

	DEBUG(10, ("CBRL async success!\n"));

	/* Find BLR with id. Its okay not to find one (race with cancel) */
	blr = onefs_cbrl_find_blr(id);
	if (blr == NULL)
		return;

	bs = (struct onefs_cbrl_blr_state *)blr->blr_private;
	SMB_ASSERT(bs);
	SMB_ASSERT(bs->state == ONEFS_CBRL_ASYNC);

	blr->lock_num++;

	num_locks = SVAL(blr->req->vwv+7, 0);

	if (blr->lock_num == num_locks)
		bs->state = ONEFS_CBRL_DONE;
	else
		bs->state = ONEFS_CBRL_NONE;

	/* Self contend our own level 2 oplock. The kernel handles
	 * contention of other opener's level 2 oplocks. */
	contend_level2_oplocks_begin(blr->fsp,
	    LEVEL2_CONTEND_WINDOWS_BRL);

	/* Process the queue, to try the next lock or finish up. */
	process_blocking_lock_queue();
}
示例#2
0
int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len)
{
	int ret;
	SMB_STRUCT_STAT st;
	SMB_OFF_T offset;
	size_t total;
	size_t num_to_write;
	ssize_t pwrite_ret;

	ret = SMB_VFS_FSTAT(fsp, &st);
	if (ret == -1) {
		return ret;
	}

	if (len <= st.st_ex_size) {
		return 0;
	}

	DEBUG(10,("vfs_fill_sparse: write zeros in file %s from len %.0f to "
		  "len %.0f (%.0f bytes)\n", fsp_str_dbg(fsp),
		  (double)st.st_ex_size, (double)len,
		  (double)(len - st.st_ex_size)));

	contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_FILL_SPARSE);

	flush_write_cache(fsp, SIZECHANGE_FLUSH);

	if (!sparse_buf) {
		sparse_buf = SMB_CALLOC_ARRAY(char, SPARSE_BUF_WRITE_SIZE);
		if (!sparse_buf) {
			errno = ENOMEM;
			ret = -1;
			goto out;
		}
	}
示例#3
0
int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len)
{
	int ret;

	contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_SET_FILE_LEN);

	DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n",
		  fsp_str_dbg(fsp), (double)len));
	flush_write_cache(fsp, SIZECHANGE_FLUSH);
	if ((ret = SMB_VFS_FTRUNCATE(fsp, len)) != -1) {
		set_filelen_write_cache(fsp, len);
		notify_fname(fsp->conn, NOTIFY_ACTION_MODIFIED,
			     FILE_NOTIFY_CHANGE_SIZE
			     | FILE_NOTIFY_CHANGE_ATTRIBUTES,
			     fsp->fsp_name->base_name);
	}

	contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_SET_FILE_LEN);

	return ret;
}
示例#4
0
ssize_t write_file(struct smb_request *req,
			files_struct *fsp,
			const char *data,
			SMB_OFF_T pos,
			size_t n)
{
	write_cache *wcp = fsp->wcp;
	ssize_t total_written = 0;
	int write_path = -1;

	if (fsp->print_file) {
		uint32_t t;
		int ret;

		ret = print_spool_write(fsp, data, n, pos, &t);
		if (ret) {
			errno = ret;
			return -1;
		}
		return t;
	}

	if (!fsp->can_write) {
		errno = EPERM;
		return -1;
	}

	if (!fsp->modified) {
		fsp->modified = True;

		if (SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st) == 0) {
			trigger_write_time_update(fsp);
			if (!fsp->posix_open &&
					(lp_store_dos_attributes(SNUM(fsp->conn)) ||
					MAP_ARCHIVE(fsp->conn))) {
				int dosmode = dos_mode(fsp->conn, fsp->fsp_name);
				if (!IS_DOS_ARCHIVE(dosmode)) {
					file_set_dosmode(fsp->conn, fsp->fsp_name,
						 dosmode | FILE_ATTRIBUTE_ARCHIVE, NULL, false);
				}
			}

			/*
			 * If this is the first write and we have an exclusive oplock then setup
			 * the write cache.
			 */

			if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type) && !wcp) {
				setup_write_cache(fsp,
						 fsp->fsp_name->st.st_ex_size);
				wcp = fsp->wcp;
			}
		}
	}

#ifdef WITH_PROFILE
	DO_PROFILE_INC(writecache_total_writes);
	if (!fsp->oplock_type) {
		DO_PROFILE_INC(writecache_non_oplock_writes);
	}
#endif

	/*
	 * If this file is level II oplocked then we need
	 * to grab the shared memory lock and inform all
	 * other files with a level II lock that they need
	 * to flush their read caches. We keep the lock over
	 * the shared memory area whilst doing this.
	 */

	/* This should actually be improved to span the write. */
	contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_WRITE);
	contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_WRITE);

#ifdef WITH_PROFILE
	if (profile_p && profile_p->writecache_total_writes % 500 == 0) {
		DEBUG(3,("WRITECACHE: initwrites=%u abutted=%u total=%u \
nonop=%u allocated=%u active=%u direct=%u perfect=%u readhits=%u\n",
			profile_p->writecache_init_writes,
			profile_p->writecache_abutted_writes,
			profile_p->writecache_total_writes,
			profile_p->writecache_non_oplock_writes,
			profile_p->writecache_allocated_write_caches,
			profile_p->writecache_num_write_caches,
			profile_p->writecache_direct_writes,
			profile_p->writecache_num_perfect_writes,
			profile_p->writecache_read_hits ));

		DEBUG(3,("WRITECACHE: Flushes SEEK=%d, READ=%d, WRITE=%d, READRAW=%d, OPLOCK=%d, CLOSE=%d, SYNC=%d\n",
			profile_p->writecache_flushed_writes[SEEK_FLUSH],
			profile_p->writecache_flushed_writes[READ_FLUSH],
			profile_p->writecache_flushed_writes[WRITE_FLUSH],
			profile_p->writecache_flushed_writes[READRAW_FLUSH],
			profile_p->writecache_flushed_writes[OPLOCK_RELEASE_FLUSH],
			profile_p->writecache_flushed_writes[CLOSE_FLUSH],
			profile_p->writecache_flushed_writes[SYNC_FLUSH] ));
	}
示例#5
0
文件: aio.c 项目: rti7743/samba
NTSTATUS schedule_aio_write_and_X(connection_struct *conn,
			      struct smb_request *smbreq,
			      files_struct *fsp, const char *data,
			      SMB_OFF_T startpos,
			      size_t numtowrite)
{
	struct aio_extra *aio_ex;
	SMB_STRUCT_AIOCB *a;
	size_t bufsize;
	size_t min_aio_write_size = lp_aio_write_size(SNUM(conn));
	int ret;

	/* Ensure aio is initialized. */
	if (!initialize_async_io_handler()) {
		return NT_STATUS_RETRY;
	}

	if (fsp->base_fsp != NULL) {
		/* No AIO on streams yet */
		DEBUG(10, ("AIO on streams not yet supported\n"));
		return NT_STATUS_RETRY;
	}

	if ((!min_aio_write_size || (numtowrite < min_aio_write_size))
	    && !SMB_VFS_AIO_FORCE(fsp)) {
		/* Too small a write for aio request. */
		DEBUG(10,("schedule_aio_write_and_X: write size (%u) too "
			  "small for minimum aio_write of %u\n",
			  (unsigned int)numtowrite,
			  (unsigned int)min_aio_write_size ));
		return NT_STATUS_RETRY;
	}

	/* Only do this on non-chained and non-chaining writes not using the
	 * write cache. */
        if (req_is_in_chain(smbreq) || (lp_write_cache_size(SNUM(conn)) != 0)) {
		return NT_STATUS_RETRY;
	}

	if (outstanding_aio_calls >= aio_pending_size) {
		DEBUG(3,("schedule_aio_write_and_X: Already have %d aio "
			 "activities outstanding.\n",
			  outstanding_aio_calls ));
		DEBUG(10,("schedule_aio_write_and_X: failed to schedule "
			  "aio_write for file %s, offset %.0f, len = %u "
			  "(mid = %u)\n",
			  fsp_str_dbg(fsp), (double)startpos,
			  (unsigned int)numtowrite,
			  (unsigned int)smbreq->mid ));
		return NT_STATUS_RETRY;
	}

	bufsize = smb_size + 6*2;

	if (!(aio_ex = create_aio_extra(NULL, fsp, bufsize))) {
		DEBUG(0,("schedule_aio_write_and_X: malloc fail.\n"));
		return NT_STATUS_NO_MEMORY;
	}
	aio_ex->handle_completion = handle_aio_write_complete;
	aio_ex->write_through = BITSETW(smbreq->vwv+7,0);

	construct_reply_common_req(smbreq, (char *)aio_ex->outbuf.data);
	srv_set_message((char *)aio_ex->outbuf.data, 6, 0, True);
	SCVAL(aio_ex->outbuf.data,smb_vwv0,0xFF); /* Never a chained reply. */

	init_strict_lock_struct(fsp, (uint64_t)smbreq->smbpid,
		(uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
		&aio_ex->lock);

	/* Take the lock until the AIO completes. */
	if (!SMB_VFS_STRICT_LOCK(conn, fsp, &aio_ex->lock)) {
		TALLOC_FREE(aio_ex);
		return NT_STATUS_FILE_LOCK_CONFLICT;
	}

	a = &aio_ex->acb;

	/* Now set up the aio record for the write call. */

	a->aio_fildes = fsp->fh->fd;
	a->aio_buf = discard_const_p(char, data);
	a->aio_nbytes = numtowrite;
	a->aio_offset = startpos;
	a->aio_sigevent.sigev_notify = SIGEV_SIGNAL;
	a->aio_sigevent.sigev_signo  = RT_SIGNAL_AIO;
	a->aio_sigevent.sigev_value.sival_ptr = aio_ex;

	ret = SMB_VFS_AIO_WRITE(fsp, a);
	if (ret == -1) {
		DEBUG(3,("schedule_aio_wrote_and_X: aio_write failed. "
			 "Error %s\n", strerror(errno) ));
		SMB_VFS_STRICT_UNLOCK(conn, fsp, &aio_ex->lock);
		TALLOC_FREE(aio_ex);
		return NT_STATUS_RETRY;
	}

	outstanding_aio_calls++;
	aio_ex->smbreq = talloc_move(aio_ex, &smbreq);

	/* This should actually be improved to span the write. */
	contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_WRITE);
	contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_WRITE);

	if (!aio_ex->write_through && !lp_syncalways(SNUM(fsp->conn))
	    && fsp->aio_write_behind) {
		/* Lie to the client and immediately claim we finished the
		 * write. */
	        SSVAL(aio_ex->outbuf.data,smb_vwv2,numtowrite);
                SSVAL(aio_ex->outbuf.data,smb_vwv4,(numtowrite>>16)&1);
		show_msg((char *)aio_ex->outbuf.data);
		if (!srv_send_smb(aio_ex->smbreq->sconn,
				(char *)aio_ex->outbuf.data,
				true, aio_ex->smbreq->seqnum+1,
				IS_CONN_ENCRYPTED(fsp->conn),
				&aio_ex->smbreq->pcd)) {
			exit_server_cleanly("schedule_aio_write_and_X: "
					    "srv_send_smb failed.");
		}
		DEBUG(10,("schedule_aio_write_and_X: scheduled aio_write "
			  "behind for file %s\n", fsp_str_dbg(fsp)));
	}
示例#6
0
ssize_t write_file(struct smb_request *req,
			files_struct *fsp,
			const char *data,
			off_t pos,
			size_t n)
{
	struct write_cache *wcp = fsp->wcp;
	ssize_t total_written = 0;
	int write_path = -1;

	if (fsp->print_file) {
		uint32_t t;
		int ret;

		ret = print_spool_write(fsp, data, n, pos, &t);
		if (ret) {
			errno = ret;
			return -1;
		}
		return t;
	}

	if (!fsp->can_write) {
		errno = EPERM;
		return -1;
	}

	/*
	 * If this is the first write and we have an exclusive oplock
	 * then setup the write cache.
	 */

	if (!fsp->modified &&
	    EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type) &&
	    (wcp == NULL)) {
		setup_write_cache(fsp, fsp->fsp_name->st.st_ex_size);
		wcp = fsp->wcp;
	}

	mark_file_modified(fsp);

#ifdef WITH_PROFILE
	DO_PROFILE_INC(writecache_total_writes);
	if (!fsp->oplock_type) {
		DO_PROFILE_INC(writecache_non_oplock_writes);
	}
#endif

	/*
	 * If this file is level II oplocked then we need
	 * to grab the shared memory lock and inform all
	 * other files with a level II lock that they need
	 * to flush their read caches. We keep the lock over
	 * the shared memory area whilst doing this.
	 */

	/* This should actually be improved to span the write. */
	contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_WRITE);
	contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_WRITE);

#ifdef WITH_PROFILE
	if (profile_p && profile_p->writecache_total_writes % 500 == 0) {
		DEBUG(3,("WRITECACHE: initwrites=%u abutted=%u total=%u \
nonop=%u allocated=%u active=%u direct=%u perfect=%u readhits=%u\n",
			profile_p->writecache_init_writes,
			profile_p->writecache_abutted_writes,
			profile_p->writecache_total_writes,
			profile_p->writecache_non_oplock_writes,
			profile_p->writecache_allocated_write_caches,
			profile_p->writecache_num_write_caches,
			profile_p->writecache_direct_writes,
			profile_p->writecache_num_perfect_writes,
			profile_p->writecache_read_hits ));

		DEBUG(3,("WRITECACHE: Flushes SEEK=%d, READ=%d, WRITE=%d, READRAW=%d, OPLOCK=%d, CLOSE=%d, SYNC=%d\n",
			profile_p->writecache_flushed_writes[SEEK_FLUSH],
			profile_p->writecache_flushed_writes[READ_FLUSH],
			profile_p->writecache_flushed_writes[WRITE_FLUSH],
			profile_p->writecache_flushed_writes[READRAW_FLUSH],
			profile_p->writecache_flushed_writes[OPLOCK_RELEASE_FLUSH],
			profile_p->writecache_flushed_writes[CLOSE_FLUSH],
			profile_p->writecache_flushed_writes[SYNC_FLUSH] ));
	}
示例#7
0
int vfs_allocate_file_space(files_struct *fsp, uint64_t len)
{
	int ret;
	SMB_STRUCT_STAT st;
	connection_struct *conn = fsp->conn;
	uint64_t space_avail;
	uint64_t bsize,dfree,dsize;

	/*
	 * Actually try and commit the space on disk....
	 */

	DEBUG(10,("vfs_allocate_file_space: file %s, len %.0f\n",
		  fsp_str_dbg(fsp), (double)len));

	if (((SMB_OFF_T)len) < 0) {
		DEBUG(0,("vfs_allocate_file_space: %s negative len "
			 "requested.\n", fsp_str_dbg(fsp)));
		errno = EINVAL;
		return -1;
	}

	ret = SMB_VFS_FSTAT(fsp, &st);
	if (ret == -1)
		return ret;

	if (len == (uint64_t)st.st_ex_size)
		return 0;

	if (len < (uint64_t)st.st_ex_size) {
		/* Shrink - use ftruncate. */

		DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current "
			  "size %.0f\n", fsp_str_dbg(fsp),
			  (double)st.st_ex_size));

		contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_ALLOC_SHRINK);

		flush_write_cache(fsp, SIZECHANGE_FLUSH);
		if ((ret = SMB_VFS_FTRUNCATE(fsp, (SMB_OFF_T)len)) != -1) {
			set_filelen_write_cache(fsp, len);
		}

		contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_ALLOC_SHRINK);

		return ret;
	}

	/* Grow - we need to test if we have enough space. */

	contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_ALLOC_GROW);
	contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_ALLOC_GROW);

	if (!lp_strict_allocate(SNUM(fsp->conn)))
		return 0;

	len -= st.st_ex_size;
	len /= 1024; /* Len is now number of 1k blocks needed. */
	space_avail = get_dfree_info(conn, fsp->fsp_name->base_name, false,
				     &bsize, &dfree, &dsize);
	if (space_avail == (uint64_t)-1) {
		return -1;
	}

	DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, "
		  "needed blocks = %.0f, space avail = %.0f\n",
		  fsp_str_dbg(fsp), (double)st.st_ex_size, (double)len,
		  (double)space_avail));

	if (len > space_avail) {
		errno = ENOSPC;
		return -1;
	}

	return 0;
}