From 813273c87e4f48d7d8415c8ee9a1a553ed369429 Mon Sep 17 00:00:00 2001 From: Zack Kirsch Date: Mon, 9 Feb 2009 21:51:29 -0800 Subject: [PATCH] Add VFS ops for Windows BRL: Lock, Unlock and Cancel: This patch adds 3 new VFS OPs for Windows byte range locking: BRL_LOCK_WINDOWS, BRL_UNLOCK_WINDOWS and BRL_CANCEL_WINDOWS. Specifically: * I renamed brl_lock_windows, brl_unlock_windows and brl_lock_cancel to *_default as the default implementations of the VFS ops. * The blocking_lock_record (BLR) is now passed into the brl_lock_windows and brl_cancel_windows paths. The Onefs implementation uses it - future implementations may find it useful too. * Created brl_lock_cancel to do what brl_lock/brl_unlock do: set up a lock_struct and call either the Posix or Windows lock function. These happen to be the same for the default implementation. * Added helper functions: increment_current_lock_count() and decrement_current_lock_count(). * Minor spelling correction in brl_timeout_fn: brl -> blr. * Changed blocking_lock_cancel() to return the BLR that it has cancelled. This allows us to assert its the lock that we wanted to cancel. If this assert ever fires, this path will need to take in the BLR to cancel, rather than choosing on its own. * Adds a small helper function: find_blocking_lock_record_by_id(). Used by the OneFS implementation, but could be useful for others. --- source3/include/locking.h | 20 ++++++++ source3/include/proto.h | 26 ++++++++-- source3/include/vfs.h | 24 +++++++++ source3/include/vfs_macros.h | 9 ++++ source3/locking/brlock.c | 66 +++++++++++++++++------- source3/locking/locking.c | 81 +++++++++++++++++------------ source3/modules/vfs_default.c | 41 +++++++++++++++ source3/modules/vfs_full_audit.c | 73 ++++++++++++++++++++++++++ source3/smbd/blocking.c | 107 +++++++++++++++++++++------------------ source3/smbd/reply.c | 18 +++++-- 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 b2b7236721d..3fd5b94de7c 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 34104727e99..ed2c50af2ff 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 f944c899c64..ffa1a95ed02 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 e57cbd25386..dcef63da866 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 edba4ed30a0..d12c4affc38 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 b342fa9b1ea..902b230e602 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 4b123ab03ed..f52ca09c084 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 faa91c3a408..15eafc1b56a 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 33aa748cdc9..42849931f3a 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 256160c4025..1ed5e7229e6 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 cea066e97ff..759e520866c 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)) { /* -- 2.11.4.GIT