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(); }
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; } }
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; }
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] )); }
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))); }
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] )); }
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; }