Write times code update.
authorJeremy Allison <jra@samba.org>
Sat, 6 Sep 2008 02:00:48 +0000 (19:00 -0700)
committerJeremy Allison <jra@samba.org>
Sat, 6 Sep 2008 02:00:48 +0000 (19:00 -0700)
Ok, here's the fix for the write times breakage
with the new tests in S4 smbtorture.

The key is keeping in the share mode struct
the "old_file_time" as the real write time,
set by all the write and allocation calls,
and the "changed_write_time" as the "sticky"
write time - set by the SET_FILE_TIME calls.

We can set them independently (although I
kept the optimization of not setting the
"old_file_time" is a "changed_write_time"
was already set, as we'll never see it.

This allows us to update the write time
immediately on the SMBwrite truncate case,
SET_END_OF_FILE and SET_ALLOCATION_SIZE calls,
whilst still have the 2 second delay on the
"normal" SMBwrite, SMBwriteX calls.

I think in a subsequent patch I'd like to
change the name of these from "old_file_time"
to "write_time" and "changed_write_time" to
"sticky_write_time" to make this clearer.

I think I also fixed a bug in Metze's original
code in that once a write timestamp had been
set from a "normal" SMBwriteX call the fsp->update_write_time_triggered
variable was set and then never reset - thus
meaning the write timestamp would never get
updated again on subsequent SMBwriteX's.

The new code checks the update_write_time_event
event instead, and doesn't update is there's
an event already scheduled.

Metze especially, please check this over for
your understanding.

Jeremy.
(This used to be commit 6f20585419046c4aca1f7d6c863cf79eb6ae53b0)

source3/include/proto.h
source3/include/smb.h
source3/locking/locking.c
source3/smbd/dosmode.c
source3/smbd/fileio.c
source3/smbd/reply.c
source3/smbd/trans2.c

index 291afac44d6cb7f222ab3f33a8134cb22e9c63aa..e94a2178c0ae3a348a12cca22087e68696c2b3b1 100644 (file)
@@ -5306,8 +5306,8 @@ void set_delete_on_close_token(struct share_mode_lock *lck, UNIX_USER_TOKEN *tok
 void set_delete_on_close_lck(struct share_mode_lock *lck, bool delete_on_close, UNIX_USER_TOKEN *tok);
 bool set_delete_on_close(files_struct *fsp, bool delete_on_close, UNIX_USER_TOKEN *tok);
 bool set_allow_initial_delete_on_close(struct share_mode_lock *lck, files_struct *fsp, bool delete_on_close);
-bool set_write_time(struct file_id fileid, struct timespec write_time,
-                   bool overwrite);
+bool set_sticky_write_time(struct file_id fileid, struct timespec write_time);
+bool set_write_time(struct file_id fileid, struct timespec write_time);
 int share_mode_forall(void (*fn)(const struct share_mode_entry *, const char *,
                                 const char *, void *),
                      void *private_data);
@@ -9616,11 +9616,10 @@ int file_set_dosmode(connection_struct *conn, const char *fname,
                     const char *parent_dir,
                     bool newfile);
 int file_ntimes(connection_struct *conn, const char *fname, const struct timespec ts[2]);
-bool set_write_time_path(connection_struct *conn, const char *fname,
-                        struct file_id fileid, const struct timespec mtime,
-                        bool overwrite);
-bool set_write_time_fsp(struct files_struct *fsp, const struct timespec mtime,
-                       bool overwrite);
+bool set_sticky_write_time_path(connection_struct *conn, const char *fname,
+                        struct file_id fileid, const struct timespec mtime);
+bool set_sticky_write_time_fsp(struct files_struct *fsp, const struct timespec mtime);
+bool update_write_time(struct files_struct *fsp);
 
 /* The following definitions come from smbd/error.c  */
 
@@ -9665,6 +9664,7 @@ bool directory_has_default_acl(connection_struct *conn, const char *fname);
 
 ssize_t read_file(files_struct *fsp,char *data,SMB_OFF_T pos,size_t n);
 void trigger_write_time_update(struct files_struct *fsp);
+void trigger_write_time_update_immediate(struct files_struct *fsp);
 ssize_t write_file(struct smb_request *req,
                        files_struct *fsp,
                        const char *data,
index c8c4f8c3cc98453750b1189e914e0cf7ec433a10..d450eb51fad54fb3d9236bee93a81f56b687eea6 100644 (file)
@@ -456,7 +456,6 @@ typedef struct files_struct {
        uint32 access_mask;             /* NTCreateX access bits (FILE_READ_DATA etc.) */
        uint32 share_access;            /* NTCreateX share constants (FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE). */
 
-       bool update_write_time_triggered;
        struct timed_event *update_write_time_event;
        bool update_write_time_on_close;
        struct timespec close_write_time;
index ca61a886a60489de450d3a520b5f527f7565d0a1..f1f92786682e7c54598d0a3c7f3e3a46e56b1ba2 100644 (file)
@@ -1405,22 +1405,21 @@ bool set_allow_initial_delete_on_close(struct share_mode_lock *lck, files_struct
        return True;
 }
 
-bool set_write_time(struct file_id fileid, struct timespec write_time,
-                   bool overwrite)
+bool set_sticky_write_time(struct file_id fileid, struct timespec write_time)
 {
        struct share_mode_lock *lck;
 
-       DEBUG(5,("set_write_time: %s overwrite=%d id=%s\n",
+       DEBUG(5,("set_sticky_write_time: %s id=%s\n",
                 timestring(debug_ctx(),
                            convert_timespec_to_time_t(write_time)),
-                overwrite, file_id_string_tos(&fileid)));
+                file_id_string_tos(&fileid)));
 
        lck = get_share_mode_lock(NULL, fileid, NULL, NULL, NULL);
        if (lck == NULL) {
                return False;
        }
 
-       if (overwrite || null_timespec(lck->changed_write_time)) {
+       if (timespec_compare(&lck->changed_write_time, &write_time) != 0) {
                lck->modified = True;
                lck->changed_write_time = write_time;
        }
@@ -1429,6 +1428,30 @@ bool set_write_time(struct file_id fileid, struct timespec write_time,
        return True;
 }
 
+bool set_write_time(struct file_id fileid, struct timespec write_time)
+{
+       struct share_mode_lock *lck;
+
+       DEBUG(5,("set_sticky_write_time: %s id=%s\n",
+                timestring(debug_ctx(),
+                           convert_timespec_to_time_t(write_time)),
+                file_id_string_tos(&fileid)));
+
+       lck = get_share_mode_lock(NULL, fileid, NULL, NULL, NULL);
+       if (lck == NULL) {
+               return False;
+       }
+
+       if (timespec_compare(&lck->old_write_time, &write_time) != 0) {
+               lck->modified = True;
+               lck->old_write_time = write_time;
+       }
+
+       TALLOC_FREE(lck);
+       return True;
+}
+
+
 struct forall_state {
        void (*fn)(const struct share_mode_entry *entry,
                   const char *sharepath,
index 0ac3873275b17688b7e0a260a9d4eb47940433f2..88c6a51770e290b1f71a63191ac710e326b2d18f 100644 (file)
@@ -616,39 +616,51 @@ int file_ntimes(connection_struct *conn, const char *fname, const struct timespe
        return ret;
 }
 
-/*******************************************************************
- Change a filetime - possibly allowing DOS semantics.
-*******************************************************************/
+/******************************************************************
+ Force a "sticky" write time on a pathname. This will always be
+ returned on all future write time queries and set on close.
+******************************************************************/
 
-bool set_write_time_path(connection_struct *conn, const char *fname,
-                        struct file_id fileid, const struct timespec mtime,
-                        bool overwrite)
+bool set_sticky_write_time_path(connection_struct *conn, const char *fname,
+                        struct file_id fileid, const struct timespec mtime)
 {
        if (null_timespec(mtime)) {
                return true;
        }
 
-       if (!set_write_time(fileid, mtime, overwrite)) {
+       if (!set_sticky_write_time(fileid, mtime)) {
                return false;
        }
 
-       /* in the overwrite case the caller should trigger the notify */
-       if (!overwrite) {
-               notify_fname(conn, NOTIFY_ACTION_MODIFIED,
-                            FILE_NOTIFY_CHANGE_LAST_WRITE, fname);
-       }
-
        return true;
 }
 
-bool set_write_time_fsp(struct files_struct *fsp, const struct timespec mtime,
-                       bool overwrite)
+/******************************************************************
+ Force a "sticky" write time on an fsp. This will always be
+ returned on all future write time queries and set on close.
+******************************************************************/
+
+bool set_sticky_write_time_fsp(struct files_struct *fsp, const struct timespec mtime)
 {
-       if (overwrite) {
-               fsp->write_time_forced = true;
-               TALLOC_FREE(fsp->update_write_time_event);
+       fsp->write_time_forced = true;
+       TALLOC_FREE(fsp->update_write_time_event);
+
+       return set_sticky_write_time_path(fsp->conn, fsp->fsp_name,
+                       fsp->file_id, mtime);
+}
+
+/******************************************************************
+ Update a write time immediately, without the 2 second delay.
+******************************************************************/
+
+bool update_write_time(struct files_struct *fsp)
+{
+       if (!set_write_time(fsp->file_id, timespec_current())) {
+               return false;
        }
 
-       return set_write_time_path(fsp->conn, fsp->fsp_name, fsp->file_id,
-                                  mtime, overwrite);
+       notify_fname(fsp->conn, NOTIFY_ACTION_MODIFIED,
+                       FILE_NOTIFY_CHANGE_LAST_WRITE, fsp->fsp_name);
+
+       return true;
 }
index 64cea7f7ced116b87b4f1ccac2361484429f8643..63850f24eba7234eb0b834b4a17664ea1dcb21ae 100644 (file)
@@ -176,28 +176,38 @@ static void update_write_time_handler(struct event_context *ctx,
                                      const struct timeval *now,
                                      void *private_data)
 {
-       files_struct *fsp = (files_struct *)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));
+       /* 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 someoneelse */
-       set_write_time_fsp(fsp, timespec_current(), false);
+       /* 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) {
+       if (fsp->update_write_time_event) {
+               /*
+                * No point - an event is already scheduled.
+                */
                return;
        }
-       fsp->update_write_time_triggered = true;
 
        delay = lp_parm_int(SNUM(fsp->conn),
                            "smbd", "writetimeupdatedelay",
@@ -212,6 +222,27 @@ void trigger_write_time_update(struct files_struct *fsp)
                                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;
+        }
+
+        if (fsp->update_write_time_event) {
+               /*
+                * No point - an event is already scheduled.
+                */
+                return;
+        }
+
+        fsp->update_write_time_on_close = true;
+       update_write_time(fsp);
+}
+
 /****************************************************************************
  Write to a file.
 ****************************************************************************/
index 16f8a5b1776815d78ef7f8d1be8db64f735758ba..6933533672e1e180693236ecae3243c19c3c975e 100644 (file)
@@ -3810,9 +3810,11 @@ void reply_write(struct smb_request *req)
                        END_PROFILE(SMBwrite);
                        return;
                }
-       } else
+               trigger_write_time_update_immediate(fsp);
+       } else {
                nwritten = write_file(req,fsp,data,startpos,numtowrite);
-  
+       }
+
        status = sync_file(conn, fsp, False);
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(5,("reply_write: sync_file for %s returned %s\n",
index 881b29c6f0ac76265344124282187ef0b88c342b..8d839b66b38b68d75b008e6e9c700040a469f36a 100644 (file)
@@ -4900,11 +4900,11 @@ NTSTATUS smb_set_file_time(connection_struct *conn,
                          time_to_asc(convert_timespec_to_time_t(ts[1])) ));
 
                if (fsp != NULL) {
-                       set_write_time_fsp(fsp, ts[1], true);
+                       set_sticky_write_time_fsp(fsp, ts[1]);
                } else {
-                       set_write_time_path(conn, fname,
+                       set_sticky_write_time_path(conn, fname,
                                            vfs_file_id_from_sbuf(conn, psbuf),
-                                           ts[1], true);
+                                           ts[1]);
                }
        }
 
@@ -4988,6 +4988,7 @@ static NTSTATUS smb_set_file_size(connection_struct *conn,
                if (vfs_set_filelen(fsp, size) == -1) {
                        return map_nt_error_from_unix(errno);
                }
+               trigger_write_time_update_immediate(fsp);
                return NT_STATUS_OK;
        }
 
@@ -5011,6 +5012,7 @@ static NTSTATUS smb_set_file_size(connection_struct *conn,
                return status;
        }
 
+       trigger_write_time_update_immediate(new_fsp);
        close_file(new_fsp,NORMAL_CLOSE);
        return NT_STATUS_OK;
 }
@@ -5737,7 +5739,7 @@ static NTSTATUS smb_set_file_allocation_info(connection_struct *conn,
                 * This is equivalent to a write. Ensure it's seen immediately
                 * if there are no pending writes.
                 */
-               trigger_write_time_update(fsp);
+               trigger_write_time_update_immediate(fsp);
                return NT_STATUS_OK;
        }
 
@@ -5771,7 +5773,7 @@ static NTSTATUS smb_set_file_allocation_info(connection_struct *conn,
         * This is equivalent to a write. Ensure it's seen immediately
         * if there are no pending writes.
         */
-       trigger_write_time_update(new_fsp);
+       trigger_write_time_update_immediate(new_fsp);
 
        close_file(new_fsp,NORMAL_CLOSE);
        return NT_STATUS_OK;