share.c revision bbaa8b60dd95d714741fc474adad3cf710ef4efd
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/sysmacros.h>
int share_debug = 0;
#ifdef DEBUG
static void print_shares(struct vnode *);
static void print_share(struct shrlock *);
#endif
static int isreadonly(struct vnode *);
/*
* Add the share reservation shr to vp.
*/
int
{
struct shrlocklist *shrl;
/*
* An access of zero is not legal, however some older clients
* generate it anyways. Allow the request only if it is
* coming from a remote system. Be generous in what you
* accept and strict in what you send.
*/
return (EINVAL);
}
/*
* Sanity check to make sure we have valid options.
* There is known overlap but it doesn't hurt to be careful.
*/
return (EINVAL);
}
return (EINVAL);
}
/*
* If the share owner matches previous request
* do special handling.
*/
/*
* If the existing request is F_COMPAT and
* is the first share then allow any F_COMPAT
* from the same process. Trick: If the existing
* F_COMPAT is write access then it must have
* the same owner as the first.
*/
break;
}
/*
* If a first share has been done in compatibility mode
* handle the special cases.
*/
/*
* If not compat and want write access or
* want to deny read or
* write exists, fails
*/
return (EAGAIN);
}
/*
* If read only file allow, this may allow
* a deny write but that is meaningless on
* a read only file.
*/
if (isreadonly(vp))
break;
return (EAGAIN);
}
/*
* This is a compat request and read access
* and the first was also read access
* we always allow it, otherwise we reject because
* we have handled the only valid write case above.
*/
break;
return (EAGAIN);
}
/*
* If we are trying to share in compatibility mode
* and the current share is compat (and not the first)
* we don't know enough.
*/
continue;
/*
* If this is a compat we check for what can't succeed.
*/
/*
* If we want write access or
* if anyone is denying read or
* if anyone has write access we fail
*/
return (EAGAIN);
}
/*
* If the first was opened with only read access
* and is a read only file we allow.
*/
isreadonly(vp)) {
break;
}
return (EAGAIN);
}
/*
* We still can't determine our fate so continue
*/
continue;
}
/*
* Simple bitwise test, if we are trying to access what
* someone else is denying or we are trying to deny
* what someone else is accessing we fail.
*/
return (EAGAIN);
}
}
/*
* Make sure no other deny modes are also set with F_COMPAT
*/
#ifdef DEBUG
if (share_debug)
#endif
return (0);
}
/*
* nlmid sysid pid
* ===== ===== ===
* !=0 !=0 =0 in cluster; NLM lock
* !=0 =0 =0 in cluster; special case for NLM lock
* !=0 =0 !=0 in cluster; PXFS local lock
* !=0 !=0 !=0 cannot happen
* =0 !=0 =0 not in cluster; NLM lock
* =0 =0 !=0 not in cluster; local lock
* =0 =0 =0 cannot happen
* =0 !=0 !=0 cannot happen
*/
static int
{
int result = 0;
if (nlmid1 != 0) { /* in a cluster */
/*
* Lock obtained through nlm server. Just need to
* compare whole sysids. pid will always = 0.
*/
/*
* This is a special case. The NLM server wishes to
* delete all share locks obtained through nlmid1.
*/
/*
* Lock obtained locally through PXFS. Match nlmids
* and pids.
*/
}
} else { /* not in a cluster */
}
return (result);
}
/*
* Delete the given share reservation. Returns 0 if okay, EINVAL if the
* share could not be found. If the share reservation is an NBMAND share
* reservation, signal anyone waiting for the share to go away (e.g.,
* blocking lock requests).
*/
int
{
struct shrlocklist *shrl;
struct shrlocklist **shrlp;
int found = 0;
int is_nbmand = 0;
/*
* Delete the shares with the matching sysid and owner
* But if own_len == 0 and sysid == 0 delete all with matching pid
* But if own_len == 0 delete all with matching sysid.
*/
while (*shrlp) {
is_nbmand = 1;
/* XXX deref sysid */
found++;
continue;
}
}
if (is_nbmand)
}
/*
* Clean up all local share reservations that the given process has with
* the given file.
*/
void
{
}
/*
* Cleanup all remote share reservations that
* were made by the given sysid on given vnode.
*/
void
{
if (sysid == 0)
return;
}
/*
* Cleanup share reservations on given vnode made
* by the either given pid or sysid.
* If sysid is 0, remove all shares made by given pid,
* otherwise all shares made by the given sysid will
* be removed.
*/
static void
{
return;
}
static int
{
int result = 0;
/*
* Lock obtained through nlm server. Just need to
* compare whole sysids.
*/
/*
* This is a special case. The NLM server identified
* by nlmid1 wishes to find out if it has obtained
* any share locks on the vnode.
*/
}
} else { /* not in a cluster */
}
return (result);
}
/*
* Determine whether there are any shares for the given vnode
* with a remote sysid. Returns zero if not, non-zero if there are.
* If sysid is non-zero then determine if this sysid has a share.
*
* Note that the return value from this function is potentially invalid
* once it has been returned. The caller is responsible for providing its
* own synchronization mechanism to ensure that the return value is useful.
*/
int
{
struct shrlocklist *shrl;
int result = 0;
while (shrl) {
result = 1;
break;
}
}
return (result);
}
static int
{
}
#ifdef DEBUG
static void
{
struct shrlocklist *shrl;
printf("<NULL>\n");
return;
}
while (shrl) {
}
}
static void
{
int i;
printf("<NULL>\n");
return;
}
printf("R");
printf("W");
printf("N");
printf("\n");
printf(" deny: ");
printf("C");
printf("R");
printf("W");
printf("N");
printf("\n");
printf("'");
printf("'\n");
}
#endif
/*
* Return non-zero if the given I/O request conflicts with a registered
* share reservation.
*
* A process is identified by the tuple (sysid, pid). When the caller
* context is passed to nbl_share_conflict, the sysid and pid in the
* caller context are used. Otherwise the sysid is zero, and the pid is
* taken from the current process.
*
* Conflict Algorithm:
* 1. An op request of NBL_READ will fail if a different
* process has a mandatory share reservation with deny read.
*
* 2. An op request of NBL_WRITE will fail if a different
* process has a mandatory share reservation with deny write.
*
* 3. An op request of NBL_READWRITE will fail if a different
* process has a mandatory share reservation with deny read
* or deny write.
*
* 4. An op request of NBL_REMOVE will fail if there is
* a mandatory share reservation with an access of read,
* write, or remove. (Anything other than meta data access).
*
* 5. An op request of NBL_RENAME will fail if there is
* a mandatory share reservation with:
* a) access write or access remove
* or
* b) access read and deny remove
*
* Otherwise there is no conflict and the op request succeeds.
*
* This behavior is required for interoperability between
* the nfs server, cifs server, and local access.
* This behavior can result in non-posix semantics.
*
* When mandatory share reservations are enabled, a process
* should call nbl_share_conflict to determine if the
* desired operation would conflict with an existing share
* reservation.
*
* The call to nbl_share_conflict may be skipped if the
* process has an existing share reservation and the operation
* is being performed in the context of that existing share
* reservation.
*/
int
{
struct shrlocklist *shrl;
int conflict = 0;
int sysid;
sysid = 0;
} else {
}
continue;
/*
* NBL_READ, NBL_WRITE, and NBL_READWRITE need to
* check if the share reservation being examined
* belongs to the current process.
* NBL_REMOVE and NBL_RENAME do not.
* This behavior is required by the conflict
* algorithm described above.
*/
switch (op) {
case NBL_READ:
conflict = 1;
break;
case NBL_WRITE:
conflict = 1;
break;
case NBL_READWRITE:
conflict = 1;
break;
case NBL_REMOVE:
conflict = 1;
break;
case NBL_RENAME:
conflict = 1;
conflict = 1;
break;
#ifdef DEBUG
default:
"nbl_share_conflict: bogus op (%d)",
op);
break;
#endif
}
if (conflict)
break;
}
return (conflict);
}
/*
* Determine if the given process has a NBMAND share reservation on the
* given vnode. Returns 1 if the process has such a share reservation,
* returns 0 otherwise.
*/
int
{
struct shrlocklist *shrl;
/*
* Any NBMAND share reservation on the vp for this process?
*/
return (1);
}
}
return (0);
}