enum brl_flavour lock_flav;
};
+/****************************************************************************
+ This is the structure to queue to implement blocking locks.
+*****************************************************************************/
+
+struct blocking_lock_record {
+ struct blocking_lock_record *next;
+ struct blocking_lock_record *prev;
+ struct files_struct *fsp;
+ struct timeval expire_time;
+ int lock_num;
+ uint64_t offset;
+ uint64_t count;
+ uint32_t lock_pid;
+ uint32_t blocking_pid; /* PID that blocks us. */
+ enum brl_flavour lock_flav;
+ enum brl_type lock_type;
+ struct smb_request *req;
+ void *blr_private; /* Implementation specific. */
+};
+
#endif /* _LOCKING_H_ */
bool brl_same_context(const struct lock_context *ctx1,
const struct lock_context *ctx2);
+NTSTATUS brl_lock_failed(files_struct *fsp, const struct lock_struct *lock, bool blocking_lock);
void brl_init(bool read_only);
void brl_shutdown(void);
+
+NTSTATUS brl_lock_windows_default(struct byte_range_lock *br_lck,
+ struct lock_struct *plock,
+ bool blocking_lock);
+
NTSTATUS brl_lock(struct messaging_context *msg_ctx,
struct byte_range_lock *br_lck,
uint32 smbpid,
enum brl_type lock_type,
enum brl_flavour lock_flav,
bool blocking_lock,
- uint32 *psmbpid);
+ uint32 *psmbpid,
+ struct blocking_lock_record *blr);
bool brl_unlock(struct messaging_context *msg_ctx,
struct byte_range_lock *br_lck,
uint32 smbpid,
br_off start,
br_off size,
enum brl_flavour lock_flav);
+bool brl_unlock_windows_default(struct messaging_context *msg_ctx,
+ struct byte_range_lock *br_lck,
+ const struct lock_struct *plock);
bool brl_locktest(struct byte_range_lock *br_lck,
uint32 smbpid,
struct server_id pid,
struct server_id pid,
br_off start,
br_off size,
- enum brl_flavour lock_flav);
+ enum brl_flavour lock_flav,
+ struct blocking_lock_record *blr);
+bool brl_lock_cancel_default(struct byte_range_lock *br_lck,
+ struct lock_struct *plock);
void brl_close_fnum(struct messaging_context *msg_ctx,
struct byte_range_lock *br_lck);
int brl_forall(void (*fn)(struct file_id id, struct server_id pid,
enum brl_flavour lock_flav,
bool blocking_lock,
NTSTATUS *perr,
- uint32 *plock_pid);
+ uint32 *plock_pid,
+ struct blocking_lock_record *blr);
NTSTATUS do_unlock(struct messaging_context *msg_ctx,
files_struct *fsp,
uint32 lock_pid,
uint32 lock_pid,
uint64_t count,
uint64_t offset,
- enum brl_flavour lock_flav);
+ enum brl_flavour lock_flav,
+ struct blocking_lock_record *blr);
void locking_close_file(struct messaging_context *msg_ctx,
files_struct *fsp);
bool locking_init(void);
/* The following definitions come from smbd/blocking.c */
+void process_blocking_lock_queue(void);
bool push_blocking_lock_request( struct byte_range_lock *br_lck,
struct smb_request *req,
files_struct *fsp,
void cancel_pending_lock_requests_by_fid(files_struct *fsp, struct byte_range_lock *br_lck);
void remove_pending_lock_requests_by_mid(int mid);
bool blocking_lock_was_deferred(int mid);
-bool blocking_lock_cancel(files_struct *fsp,
+struct blocking_lock_record *blocking_lock_cancel(files_struct *fsp,
uint32 lock_pid,
uint64_t offset,
uint64_t count,
/* Leave at 25 - not yet released. Add get_alloc_size call. -- tprouty. */
/* Leave at 25 - not yet released. Add SMB_STRUCT_STAT to readdir. - sdann */
/* Leave at 25 - not yet released. Add init_search_op call. - sdann */
+/* Leave at 25 - not yet released. Add locking calls. -- zkirsch. */
#define SMB_VFS_INTERFACE_VERSION 25
struct smb_request;
struct ea_list;
struct smb_file_time;
+struct blocking_lock_record;
/*
Available VFS operations. These values must be in sync with vfs_ops struct
SMB_VFS_OP_FILE_ID_CREATE,
SMB_VFS_OP_STREAMINFO,
SMB_VFS_OP_GET_REAL_FILENAME,
+ SMB_VFS_OP_BRL_LOCK_WINDOWS,
+ SMB_VFS_OP_BRL_UNLOCK_WINDOWS,
+ SMB_VFS_OP_BRL_CANCEL_WINDOWS,
/* NT ACL operations. */
TALLOC_CTX *mem_ctx,
char **found_name);
+ NTSTATUS (*brl_lock_windows)(struct vfs_handle_struct *handle,
+ struct byte_range_lock *br_lck,
+ struct lock_struct *plock,
+ bool blocking_lock,
+ struct blocking_lock_record *blr);
+
+ bool (*brl_unlock_windows)(struct vfs_handle_struct *handle,
+ struct messaging_context *msg_ctx,
+ struct byte_range_lock *br_lck,
+ const struct lock_struct *plock);
+
+ bool (*brl_cancel_windows)(struct vfs_handle_struct *handle,
+ struct byte_range_lock *br_lck,
+ struct lock_struct *plock,
+ struct blocking_lock_record *blr);
+
/* NT ACL operations. */
NTSTATUS (*fget_nt_acl)(struct vfs_handle_struct *handle,
struct vfs_handle_struct *file_id_create;
struct vfs_handle_struct *streaminfo;
struct vfs_handle_struct *get_real_filename;
+ struct vfs_handle_struct *brl_lock_windows;
+ struct vfs_handle_struct *brl_unlock_windows;
+ struct vfs_handle_struct *brl_cancel_windows;
/* NT ACL operations. */
#define SMB_VFS_FILE_ID_CREATE(conn, dev, inode) ((conn)->vfs.ops.file_id_create((conn)->vfs.handles.file_id_create, (dev), (inode)))
#define SMB_VFS_STREAMINFO(conn, fsp, fname, mem_ctx, num_streams, streams) ((conn)->vfs.ops.streaminfo((conn)->vfs.handles.streaminfo, (fsp), (fname), (mem_ctx), (num_streams), (streams)))
#define SMB_VFS_GET_REAL_FILENAME(conn, path, name, mem_ctx, found_name) ((conn)->vfs.ops.get_real_filename((conn)->vfs.handles.get_real_filename, (path), (name), (mem_ctx), (found_name)))
+#define SMB_VFS_BRL_LOCK_WINDOWS(conn, br_lck, plock, blocking_lock, blr) ((conn)->vfs.ops.brl_lock_windows((conn)->vfs.handles.brl_lock_windows, (br_lck), (plock), (blocking_lock), (blr)))
+#define SMB_VFS_BRL_UNLOCK_WINDOWS(conn, msg_ctx, br_lck, plock) ((conn)->vfs.ops.brl_unlock_windows((conn)->vfs.handles.brl_unlock_windows, (msg_ctx), (br_lck), (plock)))
+#define SMB_VFS_BRL_CANCEL_WINDOWS(conn, br_lck, plock, blr) ((conn)->vfs.ops.brl_cancel_windows((conn)->vfs.handles.brl_cancel_windows, (br_lck), (plock), (blr)))
/* NT ACL operations. */
#define SMB_VFS_FGET_NT_ACL(fsp, security_info, ppdesc) ((fsp)->conn->vfs.ops.fget_nt_acl((fsp)->conn->vfs.handles.fget_nt_acl, (fsp), (security_info), (ppdesc)))
#define SMB_VFS_OPAQUE_FILE_ID_CREATE(conn, dev, inode) ((conn)->vfs.ops_opaque.file_id_create((conn)->vfs_opaque.handles.file_id_create, (dev), (inode)))
#define SMB_VFS_OPAQUE_STREAMINFO(conn, fsp, fname, mem_ctx, num_streams, streams) ((conn)->vfs_opaque.ops.streaminfo((conn)->vfs_opaque.handles.streaminfo, (fsp), (fname), (mem_ctx), (num_streams), (streams)))
#define SMB_VFS_OPAQUE_GET_REAL_FILENAME(conn, path, name, mem_ctx, found_name) ((conn)->vfs_opaque.ops.get_real_filename((conn)->vfs_opaque.handles.get_real_filename, (path), (name), (mem_ctx), (found_name)))
+#define SMB_VFS_OPAQUE_BRL_LOCK_WINDOWS(conn, br_lck, plock, blocking_lock, blr) ((conn)->vfs_opaque.ops.brl_lock_windows((conn)->vfs_opaque.handles.brl_lock_windows, (br_lck), (plock), (blocking_lock), (blr)))
+#define SMB_VFS_OPAQUE_BRL_UNLOCK_WINDOWS(conn, msg_ctx, br_lck, plock) ((conn)->vfs_opaque.ops.brl_unlock_windows((conn)->vfs_opaque.handles.brl_unlock_windows, (msg_ctx), (br_lck), (plock)))
+#define SMB_VFS_OPAQUE_BRL_CANCEL_WINDOWS(conn, br_lck, plock, blr) ((conn)->vfs_opaque.ops.brl_cancel_windows((conn)->vfs_opaque.handles.brl_cancel_windows, (br_lck), (plock), (blr)))
/* NT ACL operations. */
#define SMB_VFS_OPAQUE_FGET_NT_ACL(fsp, security_info, ppdesc) ((fsp)->conn->vfs_opaque.ops.fget_nt_acl((fsp)->conn->vfs_opaque.handles.fget_nt_acl, (fsp), (security_info), (ppdesc)))
#define SMB_VFS_NEXT_FILE_ID_CREATE(handle, dev, inode) ((handle)->vfs_next.ops.file_id_create((handle)->vfs_next.handles.file_id_create, (dev), (inode)))
#define SMB_VFS_NEXT_STREAMINFO(handle, fsp, fname, mem_ctx, num_streams, streams) ((handle)->vfs_next.ops.streaminfo((handle)->vfs_next.handles.streaminfo, (fsp), (fname), (mem_ctx), (num_streams), (streams)))
#define SMB_VFS_NEXT_GET_REAL_FILENAME(handle, path, name, mem_ctx, found_name) ((handle)->vfs_next.ops.get_real_filename((handle)->vfs_next.handles.get_real_filename, (path), (name), (mem_ctx), (found_name)))
+#define SMB_VFS_NEXT_BRL_LOCK_WINDOWS(handle, br_lck, plock, blocking_lock, blr) ((handle)->vfs_next.ops.brl_lock_windows((handle)->vfs_next.handles.brl_lock_windows, (br_lck), (plock), (blocking_lock), (blr)))
+#define SMB_VFS_NEXT_BRL_UNLOCK_WINDOWS(handle, msg_ctx, br_lck, plock) ((handle)->vfs_next.ops.brl_unlock_windows((handle)->vfs_next.handles.brl_unlock_windows, (msg_ctx), (br_lck), (plock)))
+#define SMB_VFS_NEXT_BRL_CANCEL_WINDOWS(handle, br_lck, plock, blr) ((handle)->vfs_next.ops.brl_cancel_windows((handle)->vfs_next.handles.brl_cancel_windows, (br_lck), (plock), (blr)))
/* NT ACL operations. */
#define SMB_VFS_NEXT_FGET_NT_ACL(handle, fsp, security_info, ppdesc) ((handle)->vfs_next.ops.fget_nt_acl((handle)->vfs_next.handles.fget_nt_acl, (fsp), (security_info), (ppdesc)))
app depends on this ?
****************************************************************************/
-static NTSTATUS brl_lock_failed(files_struct *fsp, const struct lock_struct *lock, bool blocking_lock)
+NTSTATUS brl_lock_failed(files_struct *fsp, const struct lock_struct *lock, bool blocking_lock)
{
if (lock->start >= 0xEF000000 && (lock->start >> 63) == 0) {
/* amazing the little things you learn with a test
Lock a range of bytes - Windows lock semantics.
****************************************************************************/
-static NTSTATUS brl_lock_windows(struct byte_range_lock *br_lck,
- struct lock_struct *plock, bool blocking_lock)
+NTSTATUS brl_lock_windows_default(struct byte_range_lock *br_lck,
+ struct lock_struct *plock, bool blocking_lock)
{
unsigned int i;
files_struct *fsp = br_lck->fsp;
struct lock_struct *locks = br_lck->lock_data;
NTSTATUS status;
+ SMB_ASSERT(plock->lock_type != UNLOCK_LOCK);
+
for (i=0; i < br_lck->num_locks; i++) {
/* Do any Windows or POSIX locks conflict ? */
if (brl_conflict(&locks[i], plock)) {
enum brl_type lock_type,
enum brl_flavour lock_flav,
bool blocking_lock,
- uint32 *psmbpid)
+ uint32 *psmbpid,
+ struct blocking_lock_record *blr)
{
NTSTATUS ret;
struct lock_struct lock;
lock.lock_flav = lock_flav;
if (lock_flav == WINDOWS_LOCK) {
- ret = brl_lock_windows(br_lck, &lock, blocking_lock);
+ ret = SMB_VFS_BRL_LOCK_WINDOWS(br_lck->fsp->conn, br_lck,
+ &lock, blocking_lock, blr);
} else {
ret = brl_lock_posix(msg_ctx, br_lck, &lock);
}
Unlock a range of bytes - Windows semantics.
****************************************************************************/
-static bool brl_unlock_windows(struct messaging_context *msg_ctx,
+bool brl_unlock_windows_default(struct messaging_context *msg_ctx,
struct byte_range_lock *br_lck,
const struct lock_struct *plock)
{
struct lock_struct *locks = br_lck->lock_data;
enum brl_type deleted_lock_type = READ_LOCK; /* shut the compiler up.... */
+ SMB_ASSERT(plock->lock_type == UNLOCK_LOCK);
+
#if ZERO_ZERO
/* Delete write locks by preference... The lock list
is sorted in the zero zero case. */
lock.lock_flav = lock_flav;
if (lock_flav == WINDOWS_LOCK) {
- return brl_unlock_windows(msg_ctx, br_lck, &lock);
+ return SMB_VFS_BRL_UNLOCK_WINDOWS(br_lck->fsp->conn, msg_ctx,
+ br_lck, &lock);
} else {
return brl_unlock_posix(msg_ctx, br_lck, &lock);
}
/****************************************************************************
Remove a particular pending lock.
****************************************************************************/
-
bool brl_lock_cancel(struct byte_range_lock *br_lck,
uint32 smbpid,
struct server_id pid,
br_off start,
br_off size,
- enum brl_flavour lock_flav)
+ enum brl_flavour lock_flav,
+ struct blocking_lock_record *blr)
+{
+ bool ret;
+ struct lock_struct lock;
+
+ lock.context.smbpid = smbpid;
+ lock.context.pid = pid;
+ lock.context.tid = br_lck->fsp->conn->cnum;
+ lock.start = start;
+ lock.size = size;
+ lock.fnum = br_lck->fsp->fnum;
+ lock.lock_flav = lock_flav;
+ /* lock.lock_type doesn't matter */
+
+ if (lock_flav == WINDOWS_LOCK) {
+ ret = SMB_VFS_BRL_CANCEL_WINDOWS(br_lck->fsp->conn, br_lck,
+ &lock, blr);
+ } else {
+ ret = brl_lock_cancel_default(br_lck, &lock);
+ }
+
+ return ret;
+}
+
+bool brl_lock_cancel_default(struct byte_range_lock *br_lck,
+ struct lock_struct *plock)
{
unsigned int i;
struct lock_struct *locks = br_lck->lock_data;
- struct lock_context context;
- context.smbpid = smbpid;
- context.pid = pid;
- context.tid = br_lck->fsp->conn->cnum;
+ SMB_ASSERT(plock);
for (i = 0; i < br_lck->num_locks; i++) {
struct lock_struct *lock = &locks[i];
/* For pending locks we *always* care about the fnum. */
- if (brl_same_context(&lock->context, &context) &&
- lock->fnum == br_lck->fsp->fnum &&
+ if (brl_same_context(&lock->context, &plock->context) &&
+ lock->fnum == plock->fnum &&
IS_PENDING_LOCK(lock->lock_type) &&
- lock->lock_flav == lock_flav &&
- lock->start == start &&
- lock->size == size) {
+ lock->lock_flav == plock->lock_flav &&
+ lock->start == plock->start &&
+ lock->size == plock->size) {
break;
}
}
/****************************************************************************
Ensure this set of lock entries is valid.
****************************************************************************/
-
static bool validate_lock_entries(unsigned int *pnum_entries, struct lock_struct **pplocks)
{
unsigned int i;
return status;
}
+static void increment_current_lock_count(files_struct *fsp,
+ enum brl_flavour lock_flav)
+{
+ if (lock_flav == WINDOWS_LOCK &&
+ fsp->current_lock_count != NO_LOCKING_COUNT) {
+ /* blocking ie. pending, locks also count here,
+ * as this is an efficiency counter to avoid checking
+ * the lock db. on close. JRA. */
+
+ fsp->current_lock_count++;
+ } else {
+ /* Notice that this has had a POSIX lock request.
+ * We can't count locks after this so forget them.
+ */
+ fsp->current_lock_count = NO_LOCKING_COUNT;
+ }
+}
+
+static void decrement_current_lock_count(files_struct *fsp,
+ enum brl_flavour lock_flav)
+{
+ if (lock_flav == WINDOWS_LOCK &&
+ fsp->current_lock_count != NO_LOCKING_COUNT) {
+ SMB_ASSERT(fsp->current_lock_count > 0);
+ fsp->current_lock_count--;
+ }
+}
+
/****************************************************************************
Utility function called by locking requests.
****************************************************************************/
enum brl_flavour lock_flav,
bool blocking_lock,
NTSTATUS *perr,
- uint32 *plock_pid)
+ uint32 *plock_pid,
+ struct blocking_lock_record *blr)
{
struct byte_range_lock *br_lck = NULL;
/* NOTE! 0 byte long ranges ARE allowed and should be stored */
- DEBUG(10,("do_lock: lock flavour %s lock type %s start=%.0f len=%.0f requested for fnum %d file %s\n",
+ DEBUG(10,("do_lock: lock flavour %s lock type %s start=%.0f len=%.0f "
+ "blocking_lock=%s requested for fnum %d file %s\n",
lock_flav_name(lock_flav), lock_type_name(lock_type),
- (double)offset, (double)count, fsp->fnum, fsp->fsp_name ));
+ (double)offset, (double)count, blocking_lock ? "true" :
+ "false", fsp->fnum, fsp->fsp_name));
br_lck = brl_get_locks(talloc_tos(), fsp);
if (!br_lck) {
lock_type,
lock_flav,
blocking_lock,
- plock_pid);
+ plock_pid,
+ blr);
- if (lock_flav == WINDOWS_LOCK &&
- fsp->current_lock_count != NO_LOCKING_COUNT) {
- /* blocking ie. pending, locks also count here,
- * as this is an efficiency counter to avoid checking
- * the lock db. on close. JRA. */
-
- fsp->current_lock_count++;
- } else {
- /* Notice that this has had a POSIX lock request.
- * We can't count locks after this so forget them.
- */
- fsp->current_lock_count = NO_LOCKING_COUNT;
- }
+ DEBUG(10, ("do_lock: returning status=%s\n", nt_errstr(*perr)));
+ increment_current_lock_count(fsp, lock_flav);
return br_lck;
}
return NT_STATUS_RANGE_NOT_LOCKED;
}
- if (lock_flav == WINDOWS_LOCK &&
- fsp->current_lock_count != NO_LOCKING_COUNT) {
- SMB_ASSERT(fsp->current_lock_count > 0);
- fsp->current_lock_count--;
- }
-
+ decrement_current_lock_count(fsp, lock_flav);
return NT_STATUS_OK;
}
uint32 lock_pid,
uint64_t count,
uint64_t offset,
- enum brl_flavour lock_flav)
+ enum brl_flavour lock_flav,
+ struct blocking_lock_record *blr)
{
bool ok = False;
struct byte_range_lock *br_lck = NULL;
-
+
+ SMB_ASSERT(blr);
+
if (!fsp->can_lock) {
return fsp->is_directory ?
NT_STATUS_INVALID_DEVICE_REQUEST : NT_STATUS_INVALID_HANDLE;
procid_self(),
offset,
count,
- lock_flav);
-
+ lock_flav,
+ blr);
+
TALLOC_FREE(br_lck);
if (!ok) {
return NT_STATUS_DOS(ERRDOS, ERRcancelviolation);
}
- if (lock_flav == WINDOWS_LOCK &&
- fsp->current_lock_count != NO_LOCKING_COUNT) {
- SMB_ASSERT(fsp->current_lock_count > 0);
- fsp->current_lock_count--;
- }
-
+ decrement_current_lock_count(fsp, lock_flav);
return NT_STATUS_OK;
}
found_name);
}
+static NTSTATUS vfswrap_brl_lock_windows(struct vfs_handle_struct *handle,
+ struct byte_range_lock *br_lck,
+ struct lock_struct *plock,
+ bool blocking_lock,
+ struct blocking_lock_record *blr)
+{
+ SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK);
+
+ /* Note: blr is not used in the default implementation. */
+ return brl_lock_windows_default(br_lck, plock, blocking_lock);
+}
+
+static bool vfswrap_brl_unlock_windows(struct vfs_handle_struct *handle,
+ struct messaging_context *msg_ctx,
+ struct byte_range_lock *br_lck,
+ const struct lock_struct *plock)
+{
+ SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK);
+
+ return brl_unlock_windows_default(msg_ctx, br_lck, plock);
+}
+
+static bool vfswrap_brl_cancel_windows(struct vfs_handle_struct *handle,
+ struct byte_range_lock *br_lck,
+ struct lock_struct *plock,
+ struct blocking_lock_record *blr)
+{
+ SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK);
+
+ /* Note: blr is not used in the default implementation. */
+ return brl_lock_cancel_default(br_lck, plock);
+}
+
+/* NT ACL operations. */
+
static NTSTATUS vfswrap_fget_nt_acl(vfs_handle_struct *handle,
files_struct *fsp,
uint32 security_info, SEC_DESC **ppdesc)
SMB_VFS_LAYER_OPAQUE},
{SMB_VFS_OP(vfswrap_get_real_filename), SMB_VFS_OP_GET_REAL_FILENAME,
SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_brl_lock_windows), SMB_VFS_OP_BRL_LOCK_WINDOWS,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_brl_unlock_windows),SMB_VFS_OP_BRL_UNLOCK_WINDOWS,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_brl_cancel_windows),SMB_VFS_OP_BRL_CANCEL_WINDOWS,
+ SMB_VFS_LAYER_OPAQUE},
/* NT ACL operations. */
const char *name,
TALLOC_CTX *mem_ctx,
char **found_name);
+static NTSTATUS smb_full_audit_brl_lock_windows(struct vfs_handle_struct *handle,
+ struct byte_range_lock *br_lck,
+ struct lock_struct *plock,
+ bool blocking_lock,
+ struct blocking_lock_record *blr);
+static bool smb_full_audit_brl_unlock_windows(struct vfs_handle_struct *handle,
+ struct messaging_context *msg_ctx,
+ struct byte_range_lock *br_lck,
+ const struct lock_struct *plock);
+static bool smb_full_audit_brl_cancel_windows(struct vfs_handle_struct *handle,
+ struct byte_range_lock *br_lck,
+ struct lock_struct *plock,
+ struct blocking_lock_record *blr);
static NTSTATUS smb_full_audit_fget_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
uint32 security_info,
SEC_DESC **ppdesc);
SMB_VFS_LAYER_LOGGER},
{SMB_VFS_OP(smb_full_audit_get_real_filename), SMB_VFS_OP_GET_REAL_FILENAME,
SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_brl_lock_windows), SMB_VFS_OP_BRL_LOCK_WINDOWS,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_brl_unlock_windows), SMB_VFS_OP_BRL_UNLOCK_WINDOWS,
+ SMB_VFS_LAYER_LOGGER},
+ {SMB_VFS_OP(smb_full_audit_brl_cancel_windows), SMB_VFS_OP_BRL_CANCEL_WINDOWS,
+ SMB_VFS_LAYER_LOGGER},
/* NT ACL operations. */
{ SMB_VFS_OP_FILE_ID_CREATE, "file_id_create" },
{ SMB_VFS_OP_STREAMINFO, "streaminfo" },
{ SMB_VFS_OP_GET_REAL_FILENAME, "get_real_filename" },
+ { SMB_VFS_OP_BRL_LOCK_WINDOWS, "brl_lock_windows" },
+ { SMB_VFS_OP_BRL_UNLOCK_WINDOWS, "brl_unlock_windows" },
+ { SMB_VFS_OP_BRL_CANCEL_WINDOWS, "brl_cancel_windows" },
{ SMB_VFS_OP_FGET_NT_ACL, "fget_nt_acl" },
{ SMB_VFS_OP_GET_NT_ACL, "get_nt_acl" },
{ SMB_VFS_OP_FSET_NT_ACL, "fset_nt_acl" },
return result;
}
+static NTSTATUS smb_full_audit_brl_lock_windows(struct vfs_handle_struct *handle,
+ struct byte_range_lock *br_lck,
+ struct lock_struct *plock,
+ bool blocking_lock,
+ struct blocking_lock_record *blr)
+{
+ NTSTATUS result;
+
+ result = SMB_VFS_NEXT_BRL_LOCK_WINDOWS(handle, br_lck, plock,
+ blocking_lock, blr);
+
+ do_log(SMB_VFS_OP_BRL_LOCK_WINDOWS, NT_STATUS_IS_OK(result), handle,
+ "%s:%llu-%llu. type=%d. blocking=%d", br_lck->fsp->fsp_name,
+ plock->start, plock->size, plock->lock_type, blocking_lock );
+
+ return result;
+}
+
+static bool smb_full_audit_brl_unlock_windows(struct vfs_handle_struct *handle,
+ struct messaging_context *msg_ctx,
+ struct byte_range_lock *br_lck,
+ const struct lock_struct *plock)
+{
+ bool result;
+
+ result = SMB_VFS_NEXT_BRL_UNLOCK_WINDOWS(handle, msg_ctx, br_lck,
+ plock);
+
+ do_log(SMB_VFS_OP_BRL_UNLOCK_WINDOWS, (result == 0), handle,
+ "%s:%llu-%llu:%d", br_lck->fsp->fsp_name, plock->start,
+ plock->size, plock->lock_type);
+
+ return result;
+}
+
+static bool smb_full_audit_brl_cancel_windows(struct vfs_handle_struct *handle,
+ struct byte_range_lock *br_lck,
+ struct lock_struct *plock,
+ struct blocking_lock_record *blr)
+{
+ bool result;
+
+ result = SMB_VFS_NEXT_BRL_CANCEL_WINDOWS(handle, br_lck, plock, blr);
+
+ do_log(SMB_VFS_OP_BRL_CANCEL_WINDOWS, (result == 0), handle,
+ "%s:%llu-%llu:%d", br_lck->fsp->fsp_name, plock->start,
+ plock->size);
+
+ return result;
+}
+
static NTSTATUS smb_full_audit_fget_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
uint32 security_info,
SEC_DESC **ppdesc)
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_LOCKING
-/****************************************************************************
- This is the structure to queue to implement blocking locks.
- notify. It consists of the requesting SMB and the expiry time.
-*****************************************************************************/
-
-struct blocking_lock_record {
- struct blocking_lock_record *next;
- struct blocking_lock_record *prev;
- files_struct *fsp;
- struct timeval expire_time;
- int lock_num;
- uint64_t offset;
- uint64_t count;
- uint32_t lock_pid;
- uint32_t blocking_pid; /* PID that blocks us. */
- enum brl_flavour lock_flav;
- enum brl_type lock_type;
- struct smb_request *req;
-};
-
/****************************************************************************
Determine if this is a secondary element of a chained SMB.
**************************************************************************/
uint32_t msg_type,
struct server_id server_id,
DATA_BLOB *data);
-static void process_blocking_lock_queue(void);
static void brl_timeout_fn(struct event_context *event_ctx,
struct timed_event *te,
next_timeout = timeval_zero();
- for (brl = blocking_lock_queue; brl; brl = brl->next) {
- if (timeval_is_zero(&brl->expire_time)) {
+ for (blr = blocking_lock_queue; blr; blr = blr->next) {
+ if (timeval_is_zero(&blr->expire_time)) {
/*
* If we're blocked on pid 0xFFFFFFFF this is
* a POSIX lock, so calculate a timeout of
* 10 seconds into the future.
*/
- if (brl->blocking_pid == 0xFFFFFFFF) {
+ if (blr->blocking_pid == 0xFFFFFFFF) {
struct timeval psx_to = timeval_current_ofs(10, 0);
next_timeout = timeval_min(&next_timeout, &psx_to);
}
}
if (timeval_is_zero(&next_timeout)) {
- next_timeout = brl->expire_time;
+ next_timeout = blr->expire_time;
}
else {
next_timeout = timeval_min(&next_timeout,
- &brl->expire_time);
+ &blr->expire_time);
}
}
if (timeval_is_zero(&next_timeout)) {
+ DEBUG(10, ("Next timeout = Infinite.\n"));
return True;
}
+ if (DEBUGLVL(10)) {
+ struct timeval cur, from_now;
+
+ cur = timeval_current();
+ from_now = timeval_until(&cur, &next_timeout);
+ DEBUG(10, ("Next timeout = %d.%d seconds from now.\n",
+ (int)from_now.tv_sec, (int)from_now.tv_usec));
+ }
+
if (!(brl_timeout = event_add_timed(smbd_event_context(), NULL,
next_timeout,
brl_timeout_fn, NULL))) {
blr->lock_type = lock_type;
blr->offset = offset;
blr->count = count;
+
+ /* Specific brl_lock() implementations can fill this in. */
+ blr->blr_private = NULL;
/* Add a pending lock record for this. */
- status = brl_lock(smbd_messaging_context(), br_lck,
+ status = brl_lock(smbd_messaging_context(),
+ br_lck,
lock_pid,
procid_self(),
offset,
lock_type == READ_LOCK ? PENDING_READ_LOCK : PENDING_WRITE_LOCK,
blr->lock_flav,
lock_timeout ? True : False, /* blocking_lock. */
- NULL);
+ NULL,
+ blr);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0,("push_blocking_lock_request: failed to add PENDING_LOCK record.\n"));
- DLIST_REMOVE(blocking_lock_queue, blr);
TALLOC_FREE(blr);
return False;
}
static void blocking_lock_reply_error(struct blocking_lock_record *blr, NTSTATUS status)
{
+ DEBUG(10, ("Replying with error=%s. BLR = %p\n", nt_errstr(status), blr));
+
switch(blr->req->cmd) {
case SMBlockingX:
reply_lockingX_error(blr, status);
WINDOWS_LOCK,
True,
&status,
- &blr->blocking_pid);
+ &blr->blocking_pid,
+ blr);
TALLOC_FREE(br_lck);
blr->lock_flav,
True,
&status,
- &blr->blocking_pid);
+ &blr->blocking_pid,
+ blr);
TALLOC_FREE(br_lck);
if (!NT_STATUS_IS_OK(status)) {
void cancel_pending_lock_requests_by_fid(files_struct *fsp, struct byte_range_lock *br_lck)
{
- struct blocking_lock_record *blr, *next = NULL;
+ struct blocking_lock_record *blr, *blr_cancelled, *next = NULL;
for(blr = blocking_lock_queue; blr; blr = next) {
unsigned char locktype = 0;
"request type %d for file %s fnum = %d\n",
blr->req->cmd, fsp->fsp_name, fsp->fnum));
- brl_lock_cancel(br_lck,
- blr->lock_pid,
- procid_self(),
- blr->offset,
- blr->count,
- blr->lock_flav);
-
- blocking_lock_cancel(fsp,
+ blr_cancelled = blocking_lock_cancel(fsp,
blr->lock_pid,
blr->offset,
blr->count,
locktype,
NT_STATUS_RANGE_NOT_LOCKED);
+ SMB_ASSERT(blr_cancelled == blr);
+
+ brl_lock_cancel(br_lck,
+ blr->lock_pid,
+ procid_self(),
+ blr->offset,
+ blr->count,
+ blr->lock_flav,
+ blr);
+
/* We're closing the file fsp here, so ensure
* we don't have a dangling pointer. */
blr->fsp = NULL;
procid_self(),
blr->offset,
blr->count,
- blr->lock_flav);
+ blr->lock_flav,
+ blr);
TALLOC_FREE(br_lck);
}
Process the blocking lock queue. Note that this is only called as root.
*****************************************************************************/
-static void process_blocking_lock_queue(void)
+void process_blocking_lock_queue(void)
{
struct timeval tv_curr = timeval_current();
struct blocking_lock_record *blr, *next = NULL;
* and False if we still need to wait.
*/
+ DEBUG(10, ("Processing BLR = %p\n", blr));
+
if(blocking_lock_record_process(blr)) {
struct byte_range_lock *br_lck = brl_get_locks(
talloc_tos(), blr->fsp);
+ DEBUG(10, ("BLR_process returned true: cancelling and "
+ "removing lock. BLR = %p\n", blr));
+
if (br_lck) {
brl_lock_cancel(br_lck,
blr->lock_pid,
procid_self(),
blr->offset,
blr->count,
- blr->lock_flav);
+ blr->lock_flav,
+ blr);
TALLOC_FREE(br_lck);
}
struct byte_range_lock *br_lck = brl_get_locks(
talloc_tos(), blr->fsp);
+ DEBUG(10, ("Lock timed out! BLR = %p\n", blr));
+
/*
* Lock expired - throw away all previously
* obtained locks and return lock error.
procid_self(),
blr->offset,
blr->count,
- blr->lock_flav);
+ blr->lock_flav,
+ blr);
TALLOC_FREE(br_lck);
}
/****************************************************************************
Send ourselves a blocking lock cancelled message. Handled asynchronously above.
+ Returns the blocking_lock_record that is being cancelled.
*****************************************************************************/
-bool blocking_lock_cancel(files_struct *fsp,
+struct blocking_lock_record *blocking_lock_cancel(files_struct *fsp,
uint32 lock_pid,
uint64_t offset,
uint64_t count,
}
if (!blr) {
- return False;
+ return NULL;
}
/* Check the flags are right. */
if (blr->req->cmd == SMBlockingX &&
(locktype & LOCKING_ANDX_LARGE_FILES) !=
(CVAL(blr->req->vwv+3, 0) & LOCKING_ANDX_LARGE_FILES)) {
- return False;
+ return NULL;
}
/* Move to cancelled queue. */
MSG_SMB_BLOCKING_LOCK_CANCEL,
(uint8 *)&msg, sizeof(msg));
- return True;
+ return blr;
}
WINDOWS_LOCK,
False, /* Non-blocking lock. */
&status,
+ NULL,
NULL);
TALLOC_FREE(br_lck);
WINDOWS_LOCK,
False, /* Non-blocking lock. */
&status,
+ NULL,
NULL);
TALLOC_FREE(br_lck);
offset,
WINDOWS_LOCK);
+ DEBUG(10, ("reply_lockingX: unlock returned %s\n",
+ nt_errstr(status)));
+
if (NT_STATUS_V(status)) {
END_PROFILE(SMBlockingX);
reply_nterror(req, status);
fsp->fsp_name, (int)lock_timeout ));
if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
+ struct blocking_lock_record *blr;
+
if (lp_blocking_locks(SNUM(conn))) {
/* Schedule a message to ourselves to
remove the blocking lock record and
return the right error. */
- if (!blocking_lock_cancel(fsp,
+ blr = blocking_lock_cancel(fsp,
lock_pid,
offset,
count,
WINDOWS_LOCK,
locktype,
- NT_STATUS_FILE_LOCK_CONFLICT)) {
+ NT_STATUS_FILE_LOCK_CONFLICT);
+ if (blr == NULL) {
END_PROFILE(SMBlockingX);
reply_nterror(
req,
lock_pid,
count,
offset,
- WINDOWS_LOCK);
+ WINDOWS_LOCK,
+ blr);
} else {
bool blocking_lock = lock_timeout ? True : False;
bool defer_lock = False;
WINDOWS_LOCK,
blocking_lock,
&status,
- &block_smbpid);
+ &block_smbpid,
+ NULL);
if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
/* Windows internal resolution for blocking locks seems
POSIX_LOCK,
blocking_lock,
&status,
- &block_smbpid);
+ &block_smbpid,
+ NULL);
if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
/*