svn commit: samba r9586 - in trunk/source/smbd: .
vlendec at samba.org
vlendec at samba.org
Wed Aug 24 14:13:59 GMT 2005
Author: vlendec
Date: 2005-08-24 14:13:58 +0000 (Wed, 24 Aug 2005)
New Revision: 9586
WebSVN: http://websvn.samba.org/cgi-bin/viewcvs.cgi?view=rev&root=samba&rev=9586
Log:
I *hate* code duplication... :-)
This changes the handling of the race condition where two smbd's detect that a
file does not exist and try to create it, and the share mode requests create a
violation or other error from the open_mode_check.
Volker
Modified:
trunk/source/smbd/open.c
Changeset:
Modified: trunk/source/smbd/open.c
===================================================================
--- trunk/source/smbd/open.c 2005-08-24 13:27:24 UTC (rev 9585)
+++ trunk/source/smbd/open.c 2005-08-24 14:13:58 UTC (rev 9586)
@@ -707,6 +707,15 @@
SAFE_FREE(de_array);
}
+static BOOL request_timed_out(struct timeval request_time,
+ struct timeval timeout)
+{
+ struct timeval now, end_time;
+ GetTimeOfDay(&now);
+ end_time = timeval_sum(&request_time, &timeout);
+ return (timeval_compare(&end_time, &now) < 0);
+}
+
/****************************************************************************
Handle the 1 second delay in returning a SHARING_VIOLATION error.
****************************************************************************/
@@ -720,17 +729,6 @@
pid_t mypid = sys_getpid();
deferred_open_entry *de_array = NULL;
int num_de_entries, i;
- struct timeval now, end_time;
-
- GetTimeOfDay(&now);
- end_time = timeval_sum(&request_time, &timeout);
-
- if (timeval_compare(&end_time, &now) < 0) {
- /* Request already timed out */
- DEBUG(10, ("Request timed out\n"));
- return;
- }
-
/* Paranoia check */
num_de_entries = get_deferred_opens(state->dev, state->inode, &de_array);
@@ -1347,12 +1345,15 @@
if (delay_for_oplocks(fsp)) {
struct deferred_open_record state;
+ struct timeval timeout;
if (delayed_for_oplocks) {
DEBUG(0, ("Trying to delay for oplocks twice\n"));
exit_server("exiting");
}
+ timeout = timeval_set(OPLOCK_BREAK_TIMEOUT*2, 0);
+
/* Normally the smbd we asked should respond within
* OPLOCK_BREAK_TIMEOUT seconds regardless of whether
* the client did, give twice the timeout as a safety
@@ -1363,9 +1364,10 @@
state.dev = dev;
state.inode = inode;
- defer_open(request_time,
- timeval_set(OPLOCK_BREAK_TIMEOUT*2, 0),
- fname, &state);
+ if (!request_timed_out(request_time, timeout)) {
+ defer_open(request_time, timeout,
+ fname, &state);
+ }
unlock_share_entry(dev, inode);
return NULL;
@@ -1444,14 +1446,22 @@
* cope with the braindead 1 second delay.
*/
- if (!internal_only_open && lp_defer_sharing_violations()) {
+ if (!internal_only_open &&
+ lp_defer_sharing_violations()) {
+ struct timeval timeout;
struct deferred_open_record state;
+
+ timeout = timeval_set(0, SHARING_VIOLATION_USEC_WAIT);
+
state.delayed_for_oplocks = False;
state.dev = dev;
state.inode = inode;
- defer_open(request_time,
- timeval_set(0, SHARING_VIOLATION_USEC_WAIT),
- fname, &state);
+
+ if (!request_timed_out(request_time,
+ timeout)) {
+ defer_open(request_time, timeout,
+ fname, &state);
+ }
}
unlock_share_entry(dev, inode);
@@ -1514,16 +1524,17 @@
return NULL;
}
- /*
- * Deal with the race condition where two smbd's detect the file
- * doesn't exist and do the create at the same time. One of them will
- * win and set a share mode, the other (ie. this one) should check if
- * the requested share mode for this create is allowed.
- */
-
if (!file_existed) {
/*
+ * Deal with the race condition where two smbd's detect the
+ * file doesn't exist and do the create at the same time. One
+ * of them will win and set a share mode, the other (ie. this
+ * one) should check if the requested share mode for this
+ * create is allowed.
+ */
+
+ /*
* Now the file exists and fsp is successfully opened,
* fsp->dev and fsp->inode are valid and should replace the
* dev=0,inode=0 from a non existent file. Spotted by
@@ -1539,63 +1550,26 @@
access_mask, share_access,
create_options, &file_existed);
- if (NT_STATUS_EQUAL(status, NT_STATUS_DELETE_PENDING)) {
- set_saved_ntstatus(status);
+ if (!NT_STATUS_IS_OK(status)) {
+ struct deferred_open_record state;
+
unlock_share_entry(dev, inode);
fd_close(conn, fsp);
file_free(fsp);
- return NULL;
- }
- if (!NT_STATUS_IS_OK(status)) {
+ state.delayed_for_oplocks = False;
+ state.dev = dev;
+ state.inode = inode;
- SMB_ASSERT(NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION));
+ /* Do it all over again immediately. In the second
+ * round we will find that the file existed and handle
+ * the DELETE_PENDING and FCB cases correctly. No need
+ * to duplicate the code here. Essentially this is a
+ * "goto top of this function", but don't tell
+ * anybody... */
- /* Check if this can be done with the deny_dos and fcb
- * calls. */
- if (create_options &
- (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS|
- NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) {
- files_struct *fsp_dup;
- fsp_dup = fcb_or_dos_open(conn, fname, dev, inode,
- access_mask, share_access,
- create_options);
- if (fsp_dup) {
- unlock_share_entry(dev, inode);
- fd_close(conn, fsp);
- file_free(fsp);
- if (pinfo) {
- *pinfo = FILE_WAS_OPENED;
- }
- conn->num_files_open++;
- return fsp_dup;
- }
-
- /*
- * If we're returning a share violation,
- * ensure we cope with the braindead 1 second
- * delay.
- */
-
- if (lp_defer_sharing_violations()) {
- struct deferred_open_record state;
- state.delayed_for_oplocks = False;
- state.dev = dev;
- state.inode = inode;
- defer_open(request_time,
- timeval_set(0, SHARING_VIOLATION_USEC_WAIT),
- fname, &state);
- }
- }
-
- unlock_share_entry_fsp(fsp);
- fd_close(conn,fsp);
- file_free(fsp);
- /*
- * We have detected a sharing violation here, so
- * return the correct code.
- */
- set_saved_ntstatus(NT_STATUS_SHARING_VIOLATION);
+ defer_open(request_time, timeval_zero(),
+ fname, &state);
return NULL;
}
More information about the samba-cvs
mailing list