From 22dbd67708f1651a2341d70ce576fac360affccf Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Mon, 10 Apr 2006 15:33:04 +0000 Subject: 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 08e52ead03304ff04229e1bfe544ff40e2564fc7) --- source3/locking/posix.c | 91 ++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 75 insertions(+), 16 deletions(-) (limited to 'source3/locking/posix.c') diff --git a/source3/locking/posix.c b/source3/locking/posix.c index 07246474f3..e7075c57a6 100644 --- a/source3/locking/posix.c +++ b/source3/locking/posix.c @@ -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; -- cgit