Author: jra
Date: 2005-12-14 17:46:26 +0000 (Wed, 14 Dec 2005)
New Revision: 12233

WebSVN: 
http://websvn.samba.org/cgi-bin/viewcvs.cgi?view=rev&root=samba&rev=12233

Log:
Reduce the race condition for renames by holding the lock
longer. Instigated by complaints on the fix for #3303 from
SATOH Fumiyasu <[EMAIL PROTECTED]>.
Jeremy.

Modified:
   trunk/source/locking/locking.c
   trunk/source/smbd/reply.c


Changeset:
Modified: trunk/source/locking/locking.c
===================================================================
--- trunk/source/locking/locking.c      2005-12-14 17:16:06 UTC (rev 12232)
+++ trunk/source/locking/locking.c      2005-12-14 17:46:26 UTC (rev 12233)
@@ -605,8 +605,8 @@
        lck->num_share_modes = 0;
        lck->share_modes = NULL;
        lck->delete_on_close = False;
+       lck->fresh = False;
        lck->modified = False;
-       lck->fresh = False;
 
        if (tdb_chainlock(tdb, key) != 0) {
                DEBUG(3, ("Could not lock share entry\n"));
@@ -668,6 +668,10 @@
        size_t msg_len;
        int i;
 
+       if (!lck) {
+               return False;
+       }
+
        DEBUG(10, ("rename_share_filename: servicepath %s newname %s\n",
                servicepath, newname));
 

Modified: trunk/source/smbd/reply.c
===================================================================
--- trunk/source/smbd/reply.c   2005-12-14 17:16:06 UTC (rev 12232)
+++ trunk/source/smbd/reply.c   2005-12-14 17:46:26 UTC (rev 12233)
@@ -4086,13 +4086,20 @@
  asynchronously.
 ****************************************************************************/
 
-static void rename_open_files(connection_struct *conn, SMB_DEV_T dev, 
SMB_INO_T inode, const char *newname)
+static void rename_open_files(connection_struct *conn, struct share_mode_lock 
*lck,
+                               SMB_DEV_T dev, SMB_INO_T inode, const char 
*newname)
 {
        files_struct *fsp;
        BOOL did_rename = False;
-       struct share_mode_lock *lck = NULL;
 
        for(fsp = file_find_di_first(dev, inode); fsp; fsp = 
file_find_di_next(fsp)) {
+               /* fsp_name is a relative path under the fsp. To change this 
for other
+                  sharepaths we need to manipulate relative paths. */
+               /* TODO - create the absolute path and manipulate the newname
+                  relative to the sharepath. */
+               if (fsp->conn != conn) {
+                       continue;
+               }
                DEBUG(10,("rename_open_files: renaming file fnum %d (dev = %x, 
inode = %.0f) from %s -> %s\n",
                        fsp->fnum, (unsigned int)fsp->dev, (double)fsp->inode,
                        fsp->fsp_name, newname ));
@@ -4105,19 +4112,8 @@
                        (unsigned int)dev, (double)inode, newname ));
        }
 
-       /* Notify all remote smbd's. */
-       lck = get_share_mode_lock(NULL, dev, inode, NULL, NULL);
-       if (lck == NULL) {
-               DEBUG(5,("rename_open_files: Could not get share mode lock for 
file %s\n",
-                       fsp->fsp_name));
-               return;
-       }
-
-       /* Change the stored filename. */
+       /* Send messages to all smbd's (not ourself) that the name has changed. 
*/
        rename_share_filename(lck, conn->connectpath, newname);
-
-       /* Send messages to all smbd's (not ourself) that the name has changed. 
*/
-       talloc_free(lck);
 }
 
 /****************************************************************************
@@ -4161,6 +4157,7 @@
        NTSTATUS error = NT_STATUS_OK;
        BOOL dest_exists;
        BOOL rcdest = True;
+       struct share_mode_lock *lck = NULL;
 
        ZERO_STRUCT(sbuf);
        rcdest = 
unix_convert(newname,conn,newname_last_component,&bad_path,&sbuf);
@@ -4248,13 +4245,18 @@
                return NT_STATUS_ACCESS_DENIED;
        }
 
+       lck = get_share_mode_lock(NULL, fsp->dev, fsp->inode, NULL, NULL);
+
        if(SMB_VFS_RENAME(conn,fsp->fsp_name, newname) == 0) {
                DEBUG(3,("rename_internals_fsp: succeeded doing rename on %s -> 
%s\n",
                        fsp->fsp_name,newname));
-               rename_open_files(conn, fsp->dev, fsp->inode, newname);
+               rename_open_files(conn, lck, fsp->dev, fsp->inode, newname);
+               talloc_free(lck);
                return NT_STATUS_OK;    
        }
 
+       talloc_free(lck);
+
        if (errno == ENOTDIR || errno == EISDIR) {
                error = NT_STATUS_OBJECT_NAME_COLLISION;
        } else {
@@ -4286,6 +4288,7 @@
        BOOL rc = True;
        BOOL rcdest = True;
        SMB_STRUCT_STAT sbuf1, sbuf2;
+       struct share_mode_lock *lck = NULL;
 
        *directory = *mask = 0;
 
@@ -4456,7 +4459,7 @@
                 */
 
                if (strcsequal(directory, newname)) {
-                       rename_open_files(conn, sbuf1.st_dev, sbuf1.st_ino, 
newname);
+                       rename_open_files(conn, NULL, sbuf1.st_dev, 
sbuf1.st_ino, newname);
                        DEBUG(3,("rename_internals: identical names in rename 
%s - returning success\n", directory));
                        return NT_STATUS_OK;
                }
@@ -4471,13 +4474,17 @@
                        return NT_STATUS_SHARING_VIOLATION;
                }
 
+               lck = get_share_mode_lock(NULL, sbuf1.st_dev, sbuf1.st_ino, 
NULL, NULL);
+
                if(SMB_VFS_RENAME(conn,directory, newname) == 0) {
                        DEBUG(3,("rename_internals: succeeded doing rename on 
%s -> %s\n",
                                directory,newname));
-                       rename_open_files(conn, sbuf1.st_dev, sbuf1.st_ino, 
newname);
+                       rename_open_files(conn, lck, sbuf1.st_dev, 
sbuf1.st_ino, newname);
+                       talloc_free(lck);
                        return NT_STATUS_OK;    
                }
 
+               talloc_free(lck);
                if (errno == ENOTDIR || errno == EISDIR)
                        error = NT_STATUS_OBJECT_NAME_COLLISION;
                else
@@ -4555,7 +4562,7 @@
                                }
                                
                                if (strcsequal(fname,destname)) {
-                                       rename_open_files(conn, sbuf1.st_dev, 
sbuf1.st_ino, newname);
+                                       rename_open_files(conn, NULL, 
sbuf1.st_dev, sbuf1.st_ino, newname);
                                        DEBUG(3,("rename_internals: identical 
names in wildcard rename %s - success\n", fname));
                                        count++;
                                        error = NT_STATUS_OK;
@@ -4573,11 +4580,14 @@
                                        return NT_STATUS_SHARING_VIOLATION;
                                }
 
+                               lck = get_share_mode_lock(NULL, sbuf1.st_dev, 
sbuf1.st_ino, NULL, NULL);
+
                                if (!SMB_VFS_RENAME(conn,fname,destname)) {
-                                       rename_open_files(conn, sbuf1.st_dev, 
sbuf1.st_ino, newname);
+                                       rename_open_files(conn, lck, 
sbuf1.st_dev, sbuf1.st_ino, newname);
                                        count++;
                                        error = NT_STATUS_OK;
                                }
+                               talloc_free(lck);
                                DEBUG(3,("rename_internals: doing rename on %s 
-> %s\n",fname,destname));
                        }
                        CloseDir(dir_hnd);

Reply via email to