*/
#include "includes.h"
+#include "smbd/globals.h"
static bool setup_write_cache(files_struct *, SMB_OFF_T);
return(ret);
}
-/* how many write cache buffers have been allocated */
-static unsigned int allocated_write_caches;
-
/****************************************************************************
*Really* write to a file.
****************************************************************************/
if (ret != -1) {
fsp->fh->pos += ret;
- /*
- * It turns out that setting the last write time from a Windows
- * client stops any subsequent writes from updating the write time.
- * Doing this after the write gives a race condition here where
- * a stat may see the changed write time before we reset it here,
- * but it's cheaper than having to store the write time in shared
- * memory and look it up using dev/inode across all running smbd's.
- * The 99% solution will hopefully be good enough in this case. JRA.
- */
-
- if (!null_timespec(fsp->pending_modtime)) {
- set_filetime(fsp->conn, fsp->fsp_name,
- fsp->pending_modtime);
-
- /* If we didn't get the "set modtime" call ourselves, we must
- store the last write time to restore on close. JRA. */
- if (!fsp->pending_modtime_owner) {
- fsp->last_write_time = timespec_current();
- }
- }
-
/* Yes - this is correct - writes don't update this. JRA. */
/* Found by Samba4 tests. */
#if 0
return ret;
}
+static void update_write_time_handler(struct event_context *ctx,
+ struct timed_event *te,
+ struct timeval now,
+ void *private_data)
+{
+ files_struct *fsp = (files_struct *)private_data;
+
+ /* Remove the timed event handler. */
+ TALLOC_FREE(fsp->update_write_time_event);
+ DEBUG(5, ("Update write time on %s\n", fsp->fsp_name));
+
+ /* change the write time if not already changed by someone else */
+ update_write_time(fsp);
+}
+
+/*********************************************************
+ Schedule a write time update for WRITE_TIME_UPDATE_USEC_DELAY
+ in the future.
+*********************************************************/
+
+void trigger_write_time_update(struct files_struct *fsp)
+{
+ int delay;
+
+ if (fsp->write_time_forced) {
+ /* No point - "sticky" write times
+ * in effect.
+ */
+ return;
+ }
+
+ if (fsp->update_write_time_triggered) {
+ /*
+ * We only update the write time
+ * on the first write. After that
+ * no other writes affect this.
+ */
+ return;
+ }
+ fsp->update_write_time_triggered = true;
+
+ delay = lp_parm_int(SNUM(fsp->conn),
+ "smbd", "writetimeupdatedelay",
+ WRITE_TIME_UPDATE_USEC_DELAY);
+
+ /* trigger the update 2 seconds later */
+ fsp->update_write_time_on_close = true;
+ fsp->update_write_time_event =
+ event_add_timed(smbd_event_context(), NULL,
+ timeval_current_ofs(0, delay),
+ update_write_time_handler, fsp);
+}
+
+void trigger_write_time_update_immediate(struct files_struct *fsp)
+{
+ if (fsp->write_time_forced) {
+ /*
+ * No point - "sticky" write times
+ * in effect.
+ */
+ return;
+ }
+
+ TALLOC_FREE(fsp->update_write_time_event);
+ DEBUG(5, ("Update write time immediate on %s\n", fsp->fsp_name));
+
+ fsp->update_write_time_triggered = true;
+
+ fsp->update_write_time_on_close = false;
+ update_write_time(fsp);
+}
+
/****************************************************************************
Write to a file.
****************************************************************************/
int write_path = -1;
if (fsp->print_file) {
- fstring sharename;
uint32 jobid;
- if (!rap_to_pjobid(fsp->rap_print_jobid, sharename, &jobid)) {
+ if (!rap_to_pjobid(fsp->rap_print_jobid, NULL, &jobid)) {
DEBUG(3,("write_file: Unable to map RAP jobid %u to jobid.\n",
(unsigned int)fsp->rap_print_jobid ));
errno = EBADF;
fsp->modified = True;
if (SMB_VFS_FSTAT(fsp, &st) == 0) {
- int dosmode = dos_mode(fsp->conn,fsp->fsp_name,&st);
+ int dosmode;
+ trigger_write_time_update(fsp);
+ dosmode = dos_mode(fsp->conn,fsp->fsp_name,&st);
if ((lp_store_dos_attributes(SNUM(fsp->conn)) ||
MAP_ARCHIVE(fsp->conn)) &&
!IS_DOS_ARCHIVE(dosmode)) {
* the shared memory area whilst doing this.
*/
- release_level_2_oplocks_on_change(fsp);
+ /* 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) {
/* The cache *must* have been flushed before we do this. */
if (fsp->wcp->data_size != 0) {
char *msg;
- asprintf(&msg, "set_filelen_write_cache: size change "
+ if (asprintf(&msg, "set_filelen_write_cache: size change "
"on file %s with write cache size = %lu\n",
fsp->fsp_name,
- (unsigned long)fsp->wcp->data_size);
- smb_panic(msg);
+ (unsigned long)fsp->wcp->data_size) != -1) {
+ smb_panic(msg);
+ } else {
+ smb_panic("set_filelen_write_cache");
+ }
}
fsp->wcp->file_size = file_size;
}