"share entry with an open file\n");
}
- if ((share_entry->op_type == NO_OPLOCK) &&
- (fsp->oplock_type == FAKE_LEVEL_II_OPLOCK))
- {
- /* Someone has already written to it, but I haven't yet
- * noticed */
- return;
- }
-
if (((uint16)fsp->oplock_type) != share_entry->op_type) {
goto panic;
}
((access_mask & ~stat_open_bits) == 0));
}
+static bool has_delete_on_close(struct share_mode_lock *lck,
+ uint32_t name_hash)
+{
+ struct share_mode_data *d = lck->data;
+ uint32_t i;
+
+ if (d->num_share_modes == 0) {
+ return false;
+ }
+ if (!is_delete_on_close_set(lck, name_hash)) {
+ return false;
+ }
+ for (i=0; i<d->num_share_modes; i++) {
+ if (!share_mode_stale_pid(d, i)) {
+ return true;
+ }
+ }
+ return false;
+}
+
/****************************************************************************
Deal with share modes
Invarient: Share mode must be locked on entry and exit.
static NTSTATUS open_mode_check(connection_struct *conn,
struct share_mode_lock *lck,
- uint32_t name_hash,
uint32 access_mask,
uint32 share_access,
- uint32 create_options,
bool *file_existed)
{
int i;
return NT_STATUS_OK;
}
- /* A delete on close prohibits everything */
-
- if (is_delete_on_close_set(lck, name_hash)) {
- /*
- * Check the delete on close token
- * is valid. It could have been left
- * after a server crash.
- */
- for(i = 0; i < lck->data->num_share_modes; i++) {
- if (!share_mode_stale_pid(lck->data, i)) {
-
- *file_existed = true;
-
- return NT_STATUS_DELETE_PENDING;
- }
- }
- return NT_STATUS_OK;
- }
-
if (is_stat_open(access_mask)) {
/* Stat open that doesn't trigger oplock breaks or share mode
* checks... ! JRA. */
bool *got_level2,
bool *got_no_oplock)
{
+ struct share_mode_data *d = lck->data;
int i;
*pp_batch = NULL;
return;
}
- for (i=0; i<lck->data->num_share_modes; i++) {
- struct share_mode_entry *e = &lck->data->share_modes[i];
+ for (i=0; i<d->num_share_modes; i++) {
+ struct share_mode_entry *e = &d->share_modes[i];
if (!is_valid_share_mode_entry(e)) {
continue;
if (BATCH_OPLOCK_TYPE(e->op_type)) {
/* batch - can only be one. */
- if (share_mode_stale_pid(lck->data, i)) {
+ if (share_mode_stale_pid(d, i)) {
DEBUG(10, ("Found stale batch oplock\n"));
continue;
}
}
if (EXCLUSIVE_OPLOCK_TYPE(e->op_type)) {
- if (share_mode_stale_pid(lck->data, i)) {
+ if (share_mode_stale_pid(d, i)) {
DEBUG(10, ("Found stale duplicate oplock\n"));
continue;
}
if (LEVEL_II_OPLOCK_TYPE(e->op_type)) {
if (*pp_batch || *pp_ex_or_batch) {
- if (share_mode_stale_pid(lck->data, i)) {
+ if (share_mode_stale_pid(d, i)) {
DEBUG(10, ("Found stale LevelII "
"oplock\n"));
continue;
if (e->op_type == NO_OPLOCK) {
if (*pp_batch || *pp_ex_or_batch) {
- if (share_mode_stale_pid(lck->data, i)) {
+ if (share_mode_stale_pid(d, i)) {
DEBUG(10, ("Found stale NO_OPLOCK "
"entry\n"));
continue;
* what was found in the existing share modes.
*/
- if (got_a_none_oplock) {
- fsp->oplock_type = NO_OPLOCK;
- } else if (got_level2_oplock) {
- if (fsp->oplock_type == NO_OPLOCK ||
- fsp->oplock_type == FAKE_LEVEL_II_OPLOCK) {
- /* Store a level2 oplock, but don't tell the client */
- fsp->oplock_type = FAKE_LEVEL_II_OPLOCK;
- } else {
+ if (got_level2_oplock || got_a_none_oplock) {
+ if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
fsp->oplock_type = LEVEL_II_OPLOCK;
}
- } else {
- /* All share_mode_entries are placeholders or deferred.
- * Silently upgrade to fake levelII if the client didn't
- * ask for an oplock. */
- if (fsp->oplock_type == NO_OPLOCK) {
- /* Store a level2 oplock, but don't tell the client */
- fsp->oplock_type = FAKE_LEVEL_II_OPLOCK;
- }
}
/*
* or if we've turned them off.
*/
if (fsp->oplock_type == LEVEL_II_OPLOCK && !allow_level2) {
- fsp->oplock_type = FAKE_LEVEL_II_OPLOCK;
+ fsp->oplock_type = NO_OPLOCK;
+ }
+
+ if (fsp->oplock_type == LEVEL_II_OPLOCK && !got_level2_oplock) {
+ /*
+ * We're the first level2 oplock. Indicate that in brlock.tdb.
+ */
+ struct byte_range_lock *brl;
+
+ brl = brl_get_locks(talloc_tos(), fsp);
+ if (brl != NULL) {
+ brl_set_have_read_oplocks(brl, true);
+ TALLOC_FREE(brl);
+ }
}
DEBUG(10,("grant_fsp_oplock_type: oplock type 0x%x on file %s\n",
&got_level2_oplock,
&got_a_none_oplock);
+ if (has_delete_on_close(lck, fsp->name_hash)) {
+ TALLOC_FREE(lck);
+ fd_close(fsp);
+ return NT_STATUS_DELETE_PENDING;
+ }
+
/* First pass - send break only on batch oplocks. */
if ((req != NULL) &&
delay_for_batch_oplocks(fsp,
return NT_STATUS_SHARING_VIOLATION;
}
- status = open_mode_check(conn, lck, fsp->name_hash,
+ status = open_mode_check(conn, lck,
access_mask, share_access,
- create_options, &file_existed);
+ &file_existed);
if (NT_STATUS_IS_OK(status)) {
/* We might be going to allow this open. Check oplock
}
}
- if (NT_STATUS_EQUAL(status, NT_STATUS_DELETE_PENDING)) {
- /* DELETE_PENDING is not deferred for a second */
- TALLOC_FREE(lck);
- fd_close(fsp);
- return status;
- }
-
if (!NT_STATUS_IS_OK(status)) {
uint32 can_access_mask;
bool can_access = True;
status = set_file_oplock(fsp, fsp->oplock_type);
if (!NT_STATUS_IS_OK(status)) {
/*
- * Could not get the kernel oplock or there are byte-range
- * locks on the file.
+ * Could not get the kernel oplock
*/
fsp->oplock_type = NO_OPLOCK;
}
- set_share_mode(lck, fsp, get_current_uid(conn),
- req ? req->mid : 0,
- fsp->oplock_type);
+ if (!set_share_mode(lck, fsp, get_current_uid(conn),
+ req ? req->mid : 0,
+ fsp->oplock_type)) {
+ TALLOC_FREE(lck);
+ fd_close(fsp);
+ return NT_STATUS_NO_MEMORY;
+ }
/* Handle strange delete on close create semantics. */
if (create_options & FILE_DELETE_ON_CLOSE) {
return NT_STATUS_SHARING_VIOLATION;
}
- status = open_mode_check(conn, lck, fsp->name_hash,
+ if (has_delete_on_close(lck, fsp->name_hash)) {
+ TALLOC_FREE(lck);
+ fd_close(fsp);
+ file_free(req, fsp);
+ return NT_STATUS_DELETE_PENDING;
+ }
+
+ status = open_mode_check(conn, lck,
access_mask, share_access,
- create_options, &dir_existed);
+ &dir_existed);
if (!NT_STATUS_IS_OK(status)) {
TALLOC_FREE(lck);
return status;
}
- set_share_mode(lck, fsp, get_current_uid(conn),
- req ? req->mid : 0, NO_OPLOCK);
+ if (!set_share_mode(lck, fsp, get_current_uid(conn),
+ req ? req->mid : 0, NO_OPLOCK)) {
+ TALLOC_FREE(lck);
+ fd_close(fsp);
+ file_free(req, fsp);
+ return NT_STATUS_NO_MEMORY;
+ }
/* For directories the delete on close bit at open time seems
always to be honored on close... See test 19 in Samba4 BASE-DELETE. */
if (create_options & FILE_DELETE_ON_CLOSE) {
status = can_set_delete_on_close(fsp, 0);
if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status, NT_STATUS_DIRECTORY_NOT_EMPTY)) {
+ del_share_mode(lck, fsp);
TALLOC_FREE(lck);
fd_close(fsp);
file_free(req, fsp);