diff options
Diffstat (limited to 'source3/locking/locking.c')
-rw-r--r-- | source3/locking/locking.c | 305 |
1 files changed, 187 insertions, 118 deletions
diff --git a/source3/locking/locking.c b/source3/locking/locking.c index 0ecc90c794..0b3f625d03 100644 --- a/source3/locking/locking.c +++ b/source3/locking/locking.c @@ -2,7 +2,7 @@ Unix SMB/CIFS implementation. Locking functions Copyright (C) Andrew Tridgell 1992-2000 - Copyright (C) Jeremy Allison 1992-2000 + Copyright (C) Jeremy Allison 1992-2006 Copyright (C) Volker Lendecke 2005 This program is free software; you can redistribute it and/or modify @@ -33,6 +33,7 @@ rewrtten completely to use new tdb code. Tridge, Dec '99 Added POSIX locking support. Jeremy Allison (jeremy@valinux.com), Apr. 2000. + Added Unix Extensions POSIX locking support. Jeremy Allison Mar 2006. */ #include "includes.h" @@ -45,120 +46,179 @@ uint16 global_smbpid; static TDB_CONTEXT *tdb; /**************************************************************************** - Debugging aid :-). + Debugging aids :-). ****************************************************************************/ -static const char *lock_type_name(enum brl_type lock_type) +const char *lock_type_name(enum brl_type lock_type) { - return (lock_type == READ_LOCK) ? "READ" : "WRITE"; + switch (lock_type) { + case READ_LOCK: + return "READ"; + case WRITE_LOCK: + return "WRITE"; + case PENDING_LOCK: + return "PENDING"; + default: + return "other"; + } +} + +const char *lock_flav_name(enum brl_flavour lock_flav) +{ + return (lock_flav == WINDOWS_LOCK) ? "WINDOWS_LOCK" : "POSIX_LOCK"; } /**************************************************************************** Utility function called to see if a file region is locked. + Called in the read/write codepath. ****************************************************************************/ -BOOL is_locked(files_struct *fsp,connection_struct *conn, - SMB_BIG_UINT count,SMB_BIG_UINT offset, - enum brl_type lock_type) +BOOL is_locked(files_struct *fsp, + SMB_BIG_UINT count, + SMB_BIG_UINT offset, + enum brl_type lock_type) { - int snum = SNUM(conn); + int snum = SNUM(fsp->conn); int strict_locking = lp_strict_locking(snum); - BOOL ret; + enum brl_flavour lock_flav = lp_posix_cifsu_locktype(); + BOOL ret = True; - if (count == 0) - return(False); + if (count == 0) { + return False; + } - if (!lp_locking(snum) || !strict_locking) - return(False); + if (!lp_locking(snum) || !strict_locking) { + return False; + } if (strict_locking == Auto) { if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type) && (lock_type == READ_LOCK || lock_type == WRITE_LOCK)) { DEBUG(10,("is_locked: optimisation - exclusive oplock on file %s\n", fsp->fsp_name )); - ret = 0; + ret = False; } else if ((fsp->oplock_type == LEVEL_II_OPLOCK) && (lock_type == READ_LOCK)) { DEBUG(10,("is_locked: optimisation - level II oplock on file %s\n", fsp->fsp_name )); - ret = 0; + ret = False; } else { - ret = !brl_locktest(fsp->dev, fsp->inode, fsp->fnum, - global_smbpid, procid_self(), conn->cnum, - offset, count, lock_type); + struct byte_range_lock *br_lck = brl_get_locks(NULL, fsp); + if (!br_lck) { + return False; + } + ret = !brl_locktest(br_lck, + global_smbpid, + procid_self(), + offset, + count, + lock_type, + lock_flav); + TALLOC_FREE(br_lck); } } else { - ret = !brl_locktest(fsp->dev, fsp->inode, fsp->fnum, - global_smbpid, procid_self(), conn->cnum, - offset, count, lock_type); + struct byte_range_lock *br_lck = brl_get_locks(NULL, fsp); + if (!br_lck) { + return False; + } + ret = !brl_locktest(br_lck, + global_smbpid, + procid_self(), + offset, + count, + lock_type, + lock_flav); + TALLOC_FREE(br_lck); } - DEBUG(10,("is_locked: brl start=%.0f len=%.0f %s for file %s\n", + DEBUG(10,("is_locked: flavour = %s brl start=%.0f len=%.0f %s for fnum %d file %s\n", + lock_flav_name(lock_flav), (double)offset, (double)count, ret ? "locked" : "unlocked", - fsp->fsp_name )); + fsp->fnum, fsp->fsp_name )); - /* - * There is no lock held by an SMB daemon, check to - * see if there is a POSIX lock from a UNIX or NFS process. - */ + return ret; +} - if(!ret && lp_posix_locking(snum)) { - ret = is_posix_locked(fsp, offset, count, lock_type); +/**************************************************************************** + Find out if a lock could be granted - return who is blocking us if we can't. +****************************************************************************/ + +NTSTATUS query_lock(files_struct *fsp, + uint16 *psmbpid, + SMB_BIG_UINT *pcount, + SMB_BIG_UINT *poffset, + enum brl_type *plock_type, + enum brl_flavour lock_flav) +{ + struct byte_range_lock *br_lck = NULL; + NTSTATUS status = NT_STATUS_LOCK_NOT_GRANTED; - DEBUG(10,("is_locked: posix start=%.0f len=%.0f %s for file %s\n", - (double)offset, (double)count, ret ? "locked" : "unlocked", - fsp->fsp_name )); + if (!OPEN_FSP(fsp) || !fsp->can_lock) { + return NT_STATUS_INVALID_HANDLE; } - return ret; + if (!lp_locking(SNUM(fsp->conn))) { + return NT_STATUS_OK; + } + + br_lck = brl_get_locks(NULL, fsp); + if (!br_lck) { + return NT_STATUS_NO_MEMORY; + } + + status = brl_lockquery(br_lck, + psmbpid, + procid_self(), + poffset, + pcount, + plock_type, + lock_flav); + + TALLOC_FREE(br_lck); + return status; } /**************************************************************************** Utility function called by locking requests. ****************************************************************************/ -static NTSTATUS do_lock(files_struct *fsp,connection_struct *conn, uint16 lock_pid, - SMB_BIG_UINT count,SMB_BIG_UINT offset,enum brl_type lock_type, BOOL *my_lock_ctx) +NTSTATUS do_lock(files_struct *fsp, + uint16 lock_pid, + SMB_BIG_UINT count, + SMB_BIG_UINT offset, + enum brl_type lock_type, + enum brl_flavour lock_flav, + BOOL *my_lock_ctx) { + struct byte_range_lock *br_lck = NULL; NTSTATUS status = NT_STATUS_LOCK_NOT_GRANTED; - if (!lp_locking(SNUM(conn))) + if (!OPEN_FSP(fsp) || !fsp->can_lock) { + return NT_STATUS_INVALID_HANDLE; + } + + if (!lp_locking(SNUM(fsp->conn))) { return NT_STATUS_OK; + } /* NOTE! 0 byte long ranges ARE allowed and should be stored */ - DEBUG(10,("do_lock: lock type %s start=%.0f len=%.0f requested for file %s\n", - lock_type_name(lock_type), (double)offset, (double)count, fsp->fsp_name )); - - if (OPEN_FSP(fsp) && fsp->can_lock && (fsp->conn == conn)) { - status = brl_lock(fsp->dev, fsp->inode, fsp->fnum, - lock_pid, procid_self(), conn->cnum, - offset, count, - lock_type, my_lock_ctx); - - if (NT_STATUS_IS_OK(status) && lp_posix_locking(SNUM(conn))) { - - /* - * Try and get a POSIX lock on this range. - * Note that this is ok if it is a read lock - * overlapping on a different fd. JRA. - */ - - if (!set_posix_lock(fsp, offset, count, lock_type)) { - if (errno == EACCES || errno == EAGAIN) - status = NT_STATUS_FILE_LOCK_CONFLICT; - else - status = map_nt_error_from_unix(errno); - - /* - * We failed to map - we must now remove the brl - * lock entry. - */ - (void)brl_unlock(fsp->dev, fsp->inode, fsp->fnum, - lock_pid, procid_self(), conn->cnum, - offset, count, False, - NULL, NULL); - } - } + DEBUG(10,("do_lock: lock flavour %s lock type %s start=%.0f len=%.0f 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 )); + + br_lck = brl_get_locks(NULL, fsp); + if (!br_lck) { + return NT_STATUS_NO_MEMORY; } + status = brl_lock(br_lck, + lock_pid, + procid_self(), + offset, + count, + lock_type, + lock_flav, + my_lock_ctx); + + TALLOC_FREE(br_lck); return status; } @@ -169,20 +229,33 @@ static NTSTATUS do_lock(files_struct *fsp,connection_struct *conn, uint16 lock_p it, we need this. JRA. ****************************************************************************/ -NTSTATUS do_lock_spin(files_struct *fsp,connection_struct *conn, uint16 lock_pid, - SMB_BIG_UINT count,SMB_BIG_UINT offset,enum brl_type lock_type, BOOL *my_lock_ctx) +NTSTATUS do_lock_spin(files_struct *fsp, + uint16 lock_pid, + SMB_BIG_UINT count, + SMB_BIG_UINT offset, + enum brl_type lock_type, + enum brl_flavour lock_flav, + BOOL *my_lock_ctx) { int j, maxj = lp_lock_spin_count(); int sleeptime = lp_lock_sleep_time(); NTSTATUS status, ret; - if (maxj <= 0) + if (maxj <= 0) { maxj = 1; + } ret = NT_STATUS_OK; /* to keep dumb compilers happy */ for (j = 0; j < maxj; j++) { - status = do_lock(fsp, conn, lock_pid, count, offset, lock_type, my_lock_ctx); + status = do_lock(fsp, + lock_pid, + count, + offset, + lock_type, + lock_flav, + my_lock_ctx); + if (!NT_STATUS_EQUAL(status, NT_STATUS_LOCK_NOT_GRANTED) && !NT_STATUS_EQUAL(status, NT_STATUS_FILE_LOCK_CONFLICT)) { return status; @@ -191,72 +264,66 @@ NTSTATUS do_lock_spin(files_struct *fsp,connection_struct *conn, uint16 lock_pid if (j == 0) { ret = status; /* Don't spin if we blocked ourselves. */ - if (*my_lock_ctx) + if (*my_lock_ctx) { return ret; + } + + /* Only spin for Windows locks. */ + if (lock_flav == POSIX_LOCK) { + return ret; + } } - if (sleeptime) + + if (sleeptime) { sys_usleep(sleeptime); + } } return ret; } -/* Struct passed to brl_unlock. */ -struct posix_unlock_data_struct { - files_struct *fsp; - SMB_BIG_UINT offset; - SMB_BIG_UINT count; -}; - -/**************************************************************************** - Function passed to brl_unlock to allow POSIX unlock to be done first. -****************************************************************************/ - -static void posix_unlock(void *pre_data) -{ - struct posix_unlock_data_struct *pdata = (struct posix_unlock_data_struct *)pre_data; - - if (lp_posix_locking(SNUM(pdata->fsp->conn))) - release_posix_lock(pdata->fsp, pdata->offset, pdata->count); -} - /**************************************************************************** Utility function called by unlocking requests. ****************************************************************************/ -NTSTATUS do_unlock(files_struct *fsp,connection_struct *conn, uint16 lock_pid, - SMB_BIG_UINT count,SMB_BIG_UINT offset) +NTSTATUS do_unlock(files_struct *fsp, + uint16 lock_pid, + SMB_BIG_UINT count, + SMB_BIG_UINT offset, + enum brl_flavour lock_flav) { BOOL ok = False; - struct posix_unlock_data_struct posix_data; + struct byte_range_lock *br_lck = NULL; - if (!lp_locking(SNUM(conn))) + if (!lp_locking(SNUM(fsp->conn))) { return NT_STATUS_OK; + } - if (!OPEN_FSP(fsp) || !fsp->can_lock || (fsp->conn != conn)) { + if (!OPEN_FSP(fsp) || !fsp->can_lock) { return NT_STATUS_INVALID_HANDLE; } - DEBUG(10,("do_unlock: unlock start=%.0f len=%.0f requested for file %s\n", - (double)offset, (double)count, fsp->fsp_name )); + DEBUG(10,("do_unlock: unlock start=%.0f len=%.0f requested for fnum %d file %s\n", + (double)offset, (double)count, fsp->fnum, fsp->fsp_name )); - /* - * Remove the existing lock record from the tdb lockdb - * before looking at POSIX locks. If this record doesn't - * match then don't bother looking to remove POSIX locks. - */ - - posix_data.fsp = fsp; - posix_data.offset = offset; - posix_data.count = count; + br_lck = brl_get_locks(NULL, fsp); + if (!br_lck) { + return NT_STATUS_NO_MEMORY; + } - ok = brl_unlock(fsp->dev, fsp->inode, fsp->fnum, - lock_pid, procid_self(), conn->cnum, offset, count, - False, posix_unlock, (void *)&posix_data); + ok = brl_unlock(br_lck, + lock_pid, + procid_self(), + offset, + count, + lock_flav); + TALLOC_FREE(br_lck); + if (!ok) { DEBUG(10,("do_unlock: returning ERRlock.\n" )); return NT_STATUS_RANGE_NOT_LOCKED; } + return NT_STATUS_OK; } @@ -266,6 +333,7 @@ NTSTATUS do_unlock(files_struct *fsp,connection_struct *conn, uint16 lock_pid, void locking_close_file(files_struct *fsp) { + struct byte_range_lock *br_lck; struct process_id pid = procid_self(); if (!lp_locking(SNUM(fsp->conn))) @@ -275,13 +343,14 @@ void locking_close_file(files_struct *fsp) * Just release all the brl locks, no need to release individually. */ - brl_close(fsp->dev, fsp->inode, pid, fsp->conn->cnum, fsp->fnum); + br_lck = brl_get_locks(NULL,fsp); + if (br_lck) { + brl_close_fnum(br_lck, pid); + TALLOC_FREE(br_lck); + } if(lp_posix_locking(SNUM(fsp->conn))) { - - /* - * Release all the POSIX locks. - */ + /* Release all the POSIX locks.*/ posix_locking_close_file(fsp); } |