1
0
mirror of https://github.com/samba-team/samba.git synced 2025-08-04 08:22:08 +03:00

r15018: Merge Volker's ipc/trans2/nttrans changes over

into 3.0. Also merge the new POSIX lock code - this
is not enabled unless -DDEVELOPER is defined.
This doesn't yet map onto underlying system POSIX
locks. Updates vfs to allow lock queries.
Jeremy.
(This used to be commit 08e52ead03)
This commit is contained in:
Jeremy Allison
2006-04-10 15:33:04 +00:00
committed by Gerald (Jerry) Carter
parent 0f985dcb19
commit 22dbd67708
30 changed files with 3310 additions and 1719 deletions

File diff suppressed because it is too large Load Diff

View File

@ -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 ));
/*
* There is no lock held by an SMB daemon, check to
* see if there is a POSIX lock from a UNIX or NFS process.
*/
if(!ret && lp_posix_locking(snum)) {
ret = is_posix_locked(fsp, offset, count, lock_type);
DEBUG(10,("is_locked: posix start=%.0f len=%.0f %s for file %s\n",
(double)offset, (double)count, ret ? "locked" : "unlocked",
fsp->fsp_name ));
}
fsp->fnum, fsp->fsp_name ));
return ret;
}
/****************************************************************************
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;
if (!OPEN_FSP(fsp) || !fsp->can_lock) {
return NT_STATUS_INVALID_HANDLE;
}
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 ));
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 ));
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);
}
}
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.
*/
br_lck = brl_get_locks(NULL, fsp);
if (!br_lck) {
return NT_STATUS_NO_MEMORY;
}
posix_data.fsp = fsp;
posix_data.offset = offset;
posix_data.count = count;
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);
}

View File

@ -644,8 +644,7 @@ static BOOL posix_lock_in_range(SMB_OFF_T *offset_out, SMB_OFF_T *count_out,
/****************************************************************************
Actual function that does POSIX locks. Copes with 64 -> 32 bit cruft and
broken NFS implementations. Returns True if we got the lock or the region
is unlocked in the F_GETLK case, False otherwise.
broken NFS implementations.
****************************************************************************/
static BOOL posix_fcntl_lock(files_struct *fsp, int op, SMB_OFF_T offset, SMB_OFF_T count, int type)
@ -654,9 +653,6 @@ static BOOL posix_fcntl_lock(files_struct *fsp, int op, SMB_OFF_T offset, SMB_OF
DEBUG(8,("posix_fcntl_lock %d %d %.0f %.0f %d\n",fsp->fh->fd,op,(double)offset,(double)count,type));
/* In the F_GETLK case this returns True if the region
was locked, False if unlocked. */
ret = SMB_VFS_LOCK(fsp,fsp->fh->fd,op,offset,count,type);
if (!ret && ((errno == EFBIG) || (errno == ENOLCK) || (errno == EINVAL))) {
@ -686,39 +682,97 @@ static BOOL posix_fcntl_lock(files_struct *fsp, int op, SMB_OFF_T offset, SMB_OF
}
DEBUG(8,("posix_fcntl_lock: Lock call %s\n", ret ? "successful" : "failed"));
return ret;
}
/****************************************************************************
Actual function that gets POSIX locks. Copes with 64 -> 32 bit cruft and
broken NFS implementations.
****************************************************************************/
static BOOL posix_fcntl_getlock(files_struct *fsp, SMB_OFF_T *poffset, SMB_OFF_T *pcount, int *ptype)
{
pid_t pid;
BOOL ret;
DEBUG(8,("posix_fcntl_getlock %d %.0f %.0f %d\n",
fsp->fh->fd,(double)*poffset,(double)*pcount,*ptype));
ret = SMB_VFS_GETLOCK(fsp,fsp->fh->fd,poffset,pcount,ptype,&pid);
if (!ret && ((errno == EFBIG) || (errno == ENOLCK) || (errno == EINVAL))) {
DEBUG(0,("posix_fcntl_getlock: WARNING: lock request at offset %.0f, length %.0f returned\n",
(double)*poffset,(double)*pcount));
DEBUG(0,("an %s error. This can happen when using 64 bit lock offsets\n", strerror(errno)));
DEBUG(0,("on 32 bit NFS mounted file systems.\n"));
/*
* If the offset is > 0x7FFFFFFF then this will cause problems on
* 32 bit NFS mounted filesystems. Just ignore it.
*/
if (*poffset & ~((SMB_OFF_T)0x7fffffff)) {
DEBUG(0,("Offset greater than 31 bits. Returning success.\n"));
return True;
}
if (*pcount & ~((SMB_OFF_T)0x7fffffff)) {
/* 32 bit NFS file system, retry with smaller offset */
DEBUG(0,("Count greater than 31 bits - retrying with 31 bit truncated length.\n"));
errno = 0;
*pcount &= 0x7fffffff;
ret = SMB_VFS_GETLOCK(fsp,fsp->fh->fd,poffset,pcount,ptype,&pid);
}
}
DEBUG(8,("posix_fcntl_getlock: Lock query call %s\n", ret ? "successful" : "failed"));
return ret;
}
/****************************************************************************
POSIX function to see if a file region is locked. Returns True if the
region is locked, False otherwise.
****************************************************************************/
BOOL is_posix_locked(files_struct *fsp, SMB_BIG_UINT u_offset, SMB_BIG_UINT u_count, enum brl_type lock_type)
BOOL is_posix_locked(files_struct *fsp,
SMB_BIG_UINT *pu_offset,
SMB_BIG_UINT *pu_count,
enum brl_type *plock_type,
enum brl_flavour lock_flav)
{
SMB_OFF_T offset;
SMB_OFF_T count;
int posix_lock_type = map_posix_lock_type(fsp,lock_type);
int posix_lock_type = map_posix_lock_type(fsp,*plock_type);
DEBUG(10,("is_posix_locked: File %s, offset = %.0f, count = %.0f, type = %s\n",
fsp->fsp_name, (double)u_offset, (double)u_count, posix_lock_type_name(lock_type) ));
fsp->fsp_name, (double)*pu_offset, (double)*pu_count, posix_lock_type_name(*plock_type) ));
/*
* If the requested lock won't fit in the POSIX range, we will
* never set it, so presume it is not locked.
*/
if(!posix_lock_in_range(&offset, &count, u_offset, u_count))
if(!posix_lock_in_range(&offset, &count, *pu_offset, *pu_count)) {
return False;
}
/*
* Note that most UNIX's can *test* for a write lock on
* a read-only fd, just not *set* a write lock on a read-only
* fd. So we don't need to use map_lock_type here.
*/
if (!posix_fcntl_getlock(fsp,&offset,&count,&posix_lock_type)) {
return False;
}
return posix_fcntl_lock(fsp,SMB_F_GETLK,offset,count,posix_lock_type);
if (posix_lock_type == F_UNLCK) {
return False;
}
if (lock_flav == POSIX_LOCK) {
/* Only POSIX lock queries need to know the details. */
*pu_offset = (SMB_BIG_UINT)offset;
*pu_count = (SMB_BIG_UINT)count;
*plock_type = (posix_lock_type == F_RDLCK) ? READ_LOCK : WRITE_LOCK;
}
return True;
}
/*
@ -958,9 +1012,14 @@ lock: start = %.0f, size = %.0f\n", (double)l_curr->start, (double)l_curr->size,
/****************************************************************************
POSIX function to acquire a lock. Returns True if the
lock could be granted, False if not.
TODO -- Fix POSIX lock flavour semantics.
****************************************************************************/
BOOL set_posix_lock(files_struct *fsp, SMB_BIG_UINT u_offset, SMB_BIG_UINT u_count, enum brl_type lock_type)
BOOL set_posix_lock(files_struct *fsp,
SMB_BIG_UINT u_offset,
SMB_BIG_UINT u_count,
enum brl_type lock_type,
enum brl_flavour lock_flav)
{
SMB_OFF_T offset;
SMB_OFF_T count;