Hi there. I'm running Samba 2.2.3a on RedHat 7.1 + kernel 2.4.17. My
girlfriend's laptop is running Windows 2000 + service pack 2. She has
about a thousand MP3s stored on a Samba share on my RedHat machine. We
were finding that she couldn't rename any MP3s on the Samba share: she
would always get a sharing violation.
After a day of reading Samba logs at debug 10 (_such_ fun [ ;) ]) and
adding debug information so I could figure out what was up, I found some
oddness in check_file_sharing. It was always reporting the MP3s as having
a single share mode of op_type _0_, locked by the Samba server that was
trying to do the rename.
op_type 0 seemed to imply an unlocked share, so I went in to see if I
could tweak the server to work in that case. A full patch (including a
TON of DEBUG() changes) is included below -- in brief, though, I changed
the test in check_file_sharing (open.c:1234) from
if (BATCH_OPLOCK_TYPE(share_entry->op_type))
to
if (BATCH_OPLOCK_TYPE(share_entry->op_type) ||
NO_OPLOCK_TYPE(share_entry->op_type))
after adding a NO_OPLOCK_TYPE macro in include/smb.h. I then had to
re-enable the code that JRA removed (open.c:1237 - 1273) -- presumably the
server ends up trying to break a lock that's not held without that change.
I don't know much about CIFS or Samba, so I don't know if this is
actually
the right solution. Please advise -- I'd like to fix this problem for
real if my hac-- err, modification isn't correct. [ :) ]
Thanks,
Flynn
<flynn@kodachi.com>
==== begin patch ===--- ../samba-2.2.3a/source/smbd/open.c Sat Feb 2 16:46:56
2002
+++ source/smbd/open.c Mon Feb 25 00:11:06 2002
@@ -1200,15 +1200,38 @@
SMB_DEV_T dev;
SMB_INO_T inode;
- if (vfs_stat(conn,fname,&sbuf) == -1)
+ DEBUG(3, ("check_file_sharing: entering, checking %s\n", fname));
+
+ if (vfs_stat(conn,fname,&sbuf) == -1) {
+ DEBUG(3, ("check_file_sharing: can't stat %s, returning
TRUE\n",
+ fname));
+
return(True);
+ }
dev = sbuf.st_dev;
inode = sbuf.st_ino;
+ DEBUG(3, ("check_file_sharing: call lock_share_entry\n"));
lock_share_entry(conn, dev, inode);
+
+ DEBUG(3, ("check_file_sharing: call get_share_modes\n"));
num_share_modes = get_share_modes(conn, dev, inode, &old_shares);
+ DEBUG(3, ("check_file_sharing: num_share_modes: %d\n",
num_share_modes));
+
+ /* This code was shamelessly lifted from locking/locking.c. */
+ for (i = 0; i < num_share_modes; i++) {
+ share_mode_entry *entry_p = &old_shares[i];
+
+ DEBUG(5, ("check_file_sharing: share mode [%d]:\n"
+ " pid = %u, share_mode = 0x%x, port = 0x%x, type =
0x%x,\n"
+ " file_id = %lu, dev = 0x%x, inode = %.0f\n",
+ i, entry_p->pid, entry_p->share_mode, entry_p->op_port,
+ entry_p->op_type, entry_p->share_file_id,
+ (unsigned int) entry_p->dev, (double) entry_p->inode));
+ }
+
/*
* Check if the share modes will give us access.
*/
@@ -1231,10 +1254,12 @@
* Check if someone has an oplock on this file. If so we must
* break it before continuing.
*/
- if(BATCH_OPLOCK_TYPE(share_entry->op_type))
+
+ if (BATCH_OPLOCK_TYPE(share_entry->op_type) ||
+ NO_OPLOCK_TYPE(share_entry->op_type))
{
-#if 0
+#if 1
/* JRA. Try removing this code to see if the new oplock changes
fix the problem. I'm dubious, but Andrew is recommending we
@@ -1297,22 +1322,26 @@
* this to proceed. This takes precedence over share modes.
*/
- if(!rename_op &&
GET_ALLOW_SHARE_DELETE(share_entry->share_mode))
+ if(!rename_op &&
GET_ALLOW_SHARE_DELETE(share_entry->share_mode)) {
+ DEBUG(3, ("check_file_sharing: allowing delete\n"));
continue;
+ }
/*
* Someone else has a share lock on it, check to see
* if we can too.
*/
- if ((GET_DENY_MODE(share_entry->share_mode) != DENY_DOS) ||
- (share_entry->pid != pid))
+ if ((GET_DENY_MODE(share_entry->share_mode) != DENY_DOS) ||
+ (share_entry->pid != pid)) {
+ DEBUG(3, ("check_file_sharing: bailing early\n"));
goto free_and_exit;
-
+ }
} /* end for */
if(broke_oplock)
{
+ DEBUG(3, ("check_file_sharing: reloading share modes\n"));
SAFE_FREE(old_shares);
num_share_modes = get_share_modes(conn, dev, inode, &old_shares);
}
@@ -1332,7 +1361,7 @@
ret = True;
free_and_exit:
-
+ DEBUG(3, ("check_file_sharing: returning %s\n", ret ?
"True" : "False"));
unlock_share_entry(conn, dev, inode);
SAFE_FREE(old_shares);
return(ret);
--- ../samba-2.2.3a/source/smbd/reply.c Sat Feb 2 16:46:56 2002
+++ source/smbd/reply.c Mon Feb 25 00:02:37 2002
@@ -3621,12 +3621,19 @@
static NTSTATUS can_rename(char *fname,connection_struct *conn)
{
- if (!CAN_WRITE(conn))
+ DEBUG(4, ("can_rename: checking %s\n", fname));
+
+ if (!CAN_WRITE(conn)) {
+ DEBUG(4, ("can_rename: cannot write\n"));
return NT_STATUS_ACCESS_DENIED;
+ }
- if (!check_file_sharing(conn,fname,True))
+ if (!check_file_sharing(conn,fname,True)) {
+ DEBUG(4, ("can_rename: sharing violation\n"));
return NT_STATUS_SHARING_VIOLATION;
+ }
+ DEBUG(4, ("can_rename: returning OK\n"));
return NT_STATUS_OK;
}
@@ -3651,9 +3658,16 @@
*directory = *mask = 0;
+ DEBUG(3, ("rename_internals: entering\n"
+ " name == %s\n"
+ " newname == %s\n",
+ name, newname));
+
rc = unix_convert(name,conn,0,&bad_path1,&sbuf1);
unix_convert(newname,conn,newname_last_component,&bad_path2,&sbuf2);
+ DEBUG(3, ("rename_internals: both names unix_converted, rc
%d\n", rc));
+
/*
* Split the old name into directory and last component
* strings. Note that unix_convert may have stripped off a
@@ -3683,11 +3697,21 @@
* Tine Smukavec <valentin.smukavec@hermes.si>.
*/
- if (!rc && is_mangled(mask))
- check_mangled_cache( mask );
+ if (!rc) {
+ DEBUG(3, ("rename_internals: checking for mangling\n"));
+
+ if (is_mangled(mask)) {
+ DEBUG(3,
+ ("rename_internals: mangled, checking mangled
cache\n"));
+
+ check_mangled_cache( mask );
+ }
+ }
has_wild = ms_has_wild(mask);
+ DEBUG(3, ("rename_internals: has_wild %d\n", has_wild));
+
if (!has_wild) {
pstring zdirectory;
pstring znewname;
@@ -3710,10 +3734,16 @@
pstrcpy(newname, tmpstr);
}
- DEBUG(3,("rename_internals: case_sensitive = %d, case_preserve = %d,
short case preserve = %d, \
-directory = %s, newname = %s, newname_last_component = %s, is_8_3 = %d\n",
- case_sensitive, case_preserve, short_case_preserve, directory,
- newname, newname_last_component, is_short_name));
+ DEBUG(3,
+ ("rename_internals:"
+ " no wildcards, case_sensitive %d,"
+ " case_preserve %d, short case preserve %d, is_8_3
%d\n"
+ " directory = %s\n"
+ " newname = %s\n"
+ " newname_last_component = %s\n",
+ case_sensitive, case_preserve, short_case_preserve,
+ is_short_name,
+ directory, newname, newname_last_component));
/*
* Check for special case with case preserving and not
@@ -3731,6 +3761,8 @@
strcsequal(directory, newname)) {
pstring newname_modified_last_component;
+ DEBUG(3, ("rename_internals: just a case
change\n"));
+
/*
* Get the last component of the modified name.
* Note that we guarantee that newname contains a '/'
@@ -3749,9 +3781,12 @@
}
}
+ DEBUG(3, ("rename_internals: resolving wildcards
(why?)\n"));
resolve_wildcards(directory,newname);
+ DEBUG(3, ("rename_internals: done resolving
wildcards\n"));
+
/*
* The source object must exist.
*/
@@ -3781,11 +3816,14 @@
return error;
}
+ DEBUG(3, ("rename_internals: checking
can_rename\n"));
error = can_rename(directory,conn);
if (!NT_STATUS_IS_OK(error)) {
- DEBUG(3,("rename_internals: Error %s rename %s -> %s\n",
- get_nt_error_msg(error), directory,newname));
+ DEBUG(3,
+ ("rename_internals:"
+ " Error from can_rename: %s rename %s ->
%s\n",
+ get_nt_error_msg(error), directory,newname));
return error;
}
@@ -3808,6 +3846,8 @@
return NT_STATUS_OBJECT_NAME_COLLISION;
}
+ DEBUG(3, ("rename_internals: calling
vfs_ops.rename\n"));
+
if(conn->vfs_ops.rename(conn,zdirectory, znewname) == 0) {
DEBUG(3,("rename_internals: succeeded doing rename on %s ->
%s\n",
directory,newname));
@@ -3819,8 +3859,10 @@
else
error = map_nt_error_from_unix(errno);
- DEBUG(3,("rename_internals: Error %s rename %s -> %s\n",
- get_nt_error_msg(error), directory,newname));
+ DEBUG(3,
+ ("rename_internals:"
+ " Error from vfs_ops.rename: %s rename %s ->
%s\n",
+ get_nt_error_msg(error), directory,newname));
return error;
} else {
--- ../samba-2.2.3a/source/include/smb.h Sat Feb 2 16:46:40 2002
+++ source/include/smb.h Sun Feb 24 23:25:37 2002
@@ -1426,6 +1426,7 @@
#define BATCH_OPLOCK 2
#define LEVEL_II_OPLOCK 4
+#define NO_OPLOCK_TYPE(lck) ((lck) == NO_OPLOCK)
#define EXCLUSIVE_OPLOCK_TYPE(lck) ((lck) &
(EXCLUSIVE_OPLOCK|BATCH_OPLOCK))
#define BATCH_OPLOCK_TYPE(lck) ((lck) & BATCH_OPLOCK)
#define LEVEL_II_OPLOCK_TYPE(lck) ((lck) & LEVEL_II_OPLOCK)
==== end patch ===
--
Don't reinvent the flat tire.
(From the "Can't Happen" paper by Ian Darwin and Geoff
Collyer)