diff options
-rw-r--r-- | source3/include/locking.h | 20 | ||||
-rw-r--r-- | source3/include/proto.h | 26 | ||||
-rw-r--r-- | source3/include/vfs.h | 24 | ||||
-rw-r--r-- | source3/include/vfs_macros.h | 9 | ||||
-rw-r--r-- | source3/locking/brlock.c | 66 | ||||
-rw-r--r-- | source3/locking/locking.c | 81 | ||||
-rw-r--r-- | source3/modules/vfs_default.c | 41 | ||||
-rw-r--r-- | source3/modules/vfs_full_audit.c | 73 | ||||
-rw-r--r-- | source3/smbd/blocking.c | 107 | ||||
-rw-r--r-- | source3/smbd/reply.c | 18 | ||||
-rw-r--r-- | source3/smbd/trans2.c | 3 |
11 files changed, 358 insertions, 110 deletions
diff --git a/source3/include/locking.h b/source3/include/locking.h index b2b7236721..3fd5b94de7 100644 --- a/source3/include/locking.h +++ b/source3/include/locking.h @@ -75,4 +75,24 @@ struct lock_struct { 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_ */ diff --git a/source3/include/proto.h b/source3/include/proto.h index 34104727e9..ed2c50af2f 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -3379,8 +3379,14 @@ struct packet_struct *receive_unexpected(enum packet_type packet_type, int id, 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, @@ -3390,7 +3396,8 @@ NTSTATUS brl_lock(struct messaging_context *msg_ctx, 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, @@ -3398,6 +3405,9 @@ bool brl_unlock(struct messaging_context *msg_ctx, 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, @@ -3417,7 +3427,10 @@ bool brl_lock_cancel(struct byte_range_lock *br_lck, 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, @@ -3456,7 +3469,8 @@ struct byte_range_lock *do_lock(struct messaging_context *msg_ctx, 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, @@ -3467,7 +3481,8 @@ NTSTATUS do_lock_cancel(files_struct *fsp, 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); @@ -6342,6 +6357,7 @@ void smbd_aio_complete_mid(unsigned int mid); /* 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, @@ -6356,7 +6372,7 @@ bool push_blocking_lock_request( struct byte_range_lock *br_lck, 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, diff --git a/source3/include/vfs.h b/source3/include/vfs.h index f944c899c6..ffa1a95ed0 100644 --- a/source3/include/vfs.h +++ b/source3/include/vfs.h @@ -115,6 +115,7 @@ /* 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 @@ -142,6 +143,7 @@ struct vfs_statvfs_struct; 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 @@ -218,6 +220,9 @@ typedef enum _vfs_op_type { 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. */ @@ -393,6 +398,22 @@ struct vfs_ops { 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, @@ -531,6 +552,9 @@ struct vfs_ops { 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. */ diff --git a/source3/include/vfs_macros.h b/source3/include/vfs_macros.h index e57cbd2538..dcef63da86 100644 --- a/source3/include/vfs_macros.h +++ b/source3/include/vfs_macros.h @@ -88,6 +88,9 @@ #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))) @@ -217,6 +220,9 @@ #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))) @@ -347,6 +353,9 @@ #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))) diff --git a/source3/locking/brlock.c b/source3/locking/brlock.c index edba4ed30a..d12c4affc3 100644 --- a/source3/locking/brlock.c +++ b/source3/locking/brlock.c @@ -228,7 +228,7 @@ static bool brl_pending_overlap(const struct lock_struct *lock, const struct loc 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 @@ -305,14 +305,16 @@ static int lock_compare(const struct lock_struct *lck1, 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)) { @@ -781,7 +783,8 @@ NTSTATUS brl_lock(struct messaging_context *msg_ctx, 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; @@ -807,7 +810,8 @@ NTSTATUS brl_lock(struct messaging_context *msg_ctx, 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); } @@ -828,7 +832,7 @@ NTSTATUS brl_lock(struct messaging_context *msg_ctx, 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) { @@ -836,6 +840,8 @@ static bool brl_unlock_windows(struct messaging_context *msg_ctx, 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. */ @@ -1130,7 +1136,8 @@ bool brl_unlock(struct messaging_context *msg_ctx, 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); } @@ -1266,32 +1273,54 @@ NTSTATUS brl_lockquery(struct byte_range_lock *br_lck, /**************************************************************************** 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; } } @@ -1460,7 +1489,6 @@ void brl_close_fnum(struct messaging_context *msg_ctx, /**************************************************************************** Ensure this set of lock entries is valid. ****************************************************************************/ - static bool validate_lock_entries(unsigned int *pnum_entries, struct lock_struct **pplocks) { unsigned int i; diff --git a/source3/locking/locking.c b/source3/locking/locking.c index b342fa9b1e..902b230e60 100644 --- a/source3/locking/locking.c +++ b/source3/locking/locking.c @@ -177,6 +177,34 @@ NTSTATUS query_lock(files_struct *fsp, 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. ****************************************************************************/ @@ -190,7 +218,8 @@ struct byte_range_lock *do_lock(struct messaging_context *msg_ctx, 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; @@ -206,9 +235,11 @@ struct byte_range_lock *do_lock(struct messaging_context *msg_ctx, /* 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) { @@ -225,22 +256,12 @@ struct byte_range_lock *do_lock(struct messaging_context *msg_ctx, 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; } @@ -289,12 +310,7 @@ NTSTATUS do_unlock(struct messaging_context *msg_ctx, 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; } @@ -306,11 +322,14 @@ NTSTATUS do_lock_cancel(files_struct *fsp, 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; @@ -333,8 +352,9 @@ NTSTATUS do_lock_cancel(files_struct *fsp, procid_self(), offset, count, - lock_flav); - + lock_flav, + blr); + TALLOC_FREE(br_lck); if (!ok) { @@ -342,12 +362,7 @@ NTSTATUS do_lock_cancel(files_struct *fsp, 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; } diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c index 4b123ab03e..f52ca09c08 100644 --- a/source3/modules/vfs_default.c +++ b/source3/modules/vfs_default.c @@ -1113,6 +1113,41 @@ static int vfswrap_get_real_filename(struct vfs_handle_struct *handle, 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) @@ -1540,6 +1575,12 @@ static vfs_op_tuple vfs_default_ops[] = { 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. */ diff --git a/source3/modules/vfs_full_audit.c b/source3/modules/vfs_full_audit.c index faa91c3a40..15eafc1b56 100644 --- a/source3/modules/vfs_full_audit.c +++ b/source3/modules/vfs_full_audit.c @@ -221,6 +221,19 @@ static int smb_full_audit_get_real_filename(struct vfs_handle_struct *handle, 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); @@ -464,6 +477,12 @@ static vfs_op_tuple audit_op_tuples[] = { 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. */ @@ -638,6 +657,9 @@ static struct { { 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" }, @@ -1693,6 +1715,57 @@ static int smb_full_audit_get_real_filename(struct vfs_handle_struct *handle, 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) diff --git a/source3/smbd/blocking.c b/source3/smbd/blocking.c index 33aa748cdc..42849931f3 100644 --- a/source3/smbd/blocking.c +++ b/source3/smbd/blocking.c @@ -24,26 +24,6 @@ #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. **************************************************************************/ @@ -52,7 +32,6 @@ static void received_unlock_msg(struct messaging_context *msg, 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, @@ -82,14 +61,14 @@ static bool recalc_brl_timeout(void) 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); } @@ -98,18 +77,28 @@ static bool recalc_brl_timeout(void) } 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))) { @@ -173,9 +162,13 @@ bool push_blocking_lock_request( struct byte_range_lock *br_lck, 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, @@ -183,11 +176,11 @@ bool push_blocking_lock_request( struct byte_range_lock *br_lck, 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; } @@ -332,6 +325,8 @@ static void reply_lockingX_error(struct blocking_lock_record *blr, NTSTATUS stat 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); @@ -409,7 +404,8 @@ static bool process_lockingX(struct blocking_lock_record *blr) WINDOWS_LOCK, True, &status, - &blr->blocking_pid); + &blr->blocking_pid, + blr); TALLOC_FREE(br_lck); @@ -470,7 +466,8 @@ static bool process_trans2(struct blocking_lock_record *blr) blr->lock_flav, True, &status, - &blr->blocking_pid); + &blr->blocking_pid, + blr); TALLOC_FREE(br_lck); if (!NT_STATUS_IS_OK(status)) { @@ -521,7 +518,7 @@ static bool blocking_lock_record_process(struct blocking_lock_record *blr) 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; @@ -539,14 +536,7 @@ void cancel_pending_lock_requests_by_fid(files_struct *fsp, struct byte_range_lo "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, @@ -554,6 +544,16 @@ void cancel_pending_lock_requests_by_fid(files_struct *fsp, struct byte_range_lo 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; @@ -592,7 +592,8 @@ void remove_pending_lock_requests_by_mid(int mid) procid_self(), blr->offset, blr->count, - blr->lock_flav); + blr->lock_flav, + blr); TALLOC_FREE(br_lck); } @@ -637,7 +638,7 @@ static void received_unlock_msg(struct messaging_context *msg, 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; @@ -657,17 +658,23 @@ static void process_blocking_lock_queue(void) * 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); } @@ -686,6 +693,8 @@ static void process_blocking_lock_queue(void) 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. @@ -702,7 +711,8 @@ static void process_blocking_lock_queue(void) procid_self(), blr->offset, blr->count, - blr->lock_flav); + blr->lock_flav, + blr); TALLOC_FREE(br_lck); } @@ -757,9 +767,10 @@ static void process_blocking_lock_cancel_message(struct messaging_context *ctx, /**************************************************************************** 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, @@ -790,14 +801,14 @@ bool blocking_lock_cancel(files_struct *fsp, } 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. */ @@ -812,5 +823,5 @@ bool blocking_lock_cancel(files_struct *fsp, MSG_SMB_BLOCKING_LOCK_CANCEL, (uint8 *)&msg, sizeof(msg)); - return True; + return blr; } diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index 256160c402..1ed5e7229e 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -3040,6 +3040,7 @@ void reply_lockread(struct smb_request *req) WINDOWS_LOCK, False, /* Non-blocking lock. */ &status, + NULL, NULL); TALLOC_FREE(br_lck); @@ -4514,6 +4515,7 @@ void reply_lock(struct smb_request *req) WINDOWS_LOCK, False, /* Non-blocking lock. */ &status, + NULL, NULL); TALLOC_FREE(br_lck); @@ -6904,6 +6906,9 @@ void reply_lockingX(struct smb_request *req) 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); @@ -6945,19 +6950,22 @@ void reply_lockingX(struct smb_request *req) 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, @@ -6972,7 +6980,8 @@ void reply_lockingX(struct smb_request *req) lock_pid, count, offset, - WINDOWS_LOCK); + WINDOWS_LOCK, + blr); } else { bool blocking_lock = lock_timeout ? True : False; bool defer_lock = False; @@ -6988,7 +6997,8 @@ void reply_lockingX(struct smb_request *req) 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 diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index cea066e97f..759e520866 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -5628,7 +5628,8 @@ static NTSTATUS smb_set_posix_lock(connection_struct *conn, POSIX_LOCK, blocking_lock, &status, - &block_smbpid); + &block_smbpid, + NULL); if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) { /* |