mirror of
https://git.FreeBSD.org/src.git
synced 2025-01-13 14:40:22 +00:00
This completes the all partial file locking under NFS. The underlying
file is still completely covered by a flock(2) style lock, but we'll tackle that at a later date. Submitted by: "Andrew P. Lentvorski" <bsder@allcaps.org>
This commit is contained in:
parent
b6dc41baf1
commit
5f07c7b294
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/cvs2svn/branches/ANDREW_LOCKD/; revision=86641
@ -81,6 +81,7 @@ struct file_lock {
|
||||
fhandle_t filehandle; /* NFS filehandle */
|
||||
struct sockaddr *addr;
|
||||
struct nlm4_holder client; /* lock holder */
|
||||
/* XXX: client_cookie used *only* in send_granted */
|
||||
netobj client_cookie; /* cookie sent by the client */
|
||||
char client_name[SM_MAXSTRLEN];
|
||||
int nsm_status; /* status from the remote lock manager */
|
||||
@ -144,13 +145,15 @@ enum hwlock_status { HW_GRANTED = 0, HW_GRANTED_DUPLICATE,
|
||||
HW_DENIED, HW_DENIED_NOLOCK,
|
||||
HW_STALEFH, HW_READONLY, HW_RESERR };
|
||||
|
||||
enum split_status {SPL_DISJOINT, SPL_LOCK_CONTAINED, SPL_LOCK_LEFT,
|
||||
SPL_LOCK_RIGHT, SPL_UNLOCK_CONTAINED};
|
||||
|
||||
enum partialfilelock_status { PFL_GRANTED=0, PFL_GRANTED_DUPLICATE, PFL_DENIED,
|
||||
PFL_NFSDENIED, PFL_NFSBLOCKED, PFL_NFSDENIED_NOLOCK, PFL_NFSRESERR,
|
||||
PFL_HWDENIED, PFL_HWBLOCKED, PFL_HWDENIED_NOLOCK, PFL_HWRESERR};
|
||||
|
||||
enum LFLAGS {LEDGE_LEFT, LEDGE_LBOUNDARY, LEDGE_INSIDE, LEDGE_RBOUNDARY, LEDGE_RIGHT};
|
||||
enum RFLAGS {REDGE_LEFT, REDGE_LBOUNDARY, REDGE_INSIDE, REDGE_RBOUNDARY, REDGE_RIGHT};
|
||||
/* XXX: WARNING! I HAVE OVERLOADED THIS STATUS ENUM! SPLIT IT APART INTO TWO */
|
||||
enum split_status {SPL_DISJOINT=0, SPL_LOCK1=1, SPL_LOCK2=2, SPL_CONTAINED=4, SPL_RESERR=8};
|
||||
|
||||
enum partialfilelock_status lock_partialfilelock(struct file_lock *fl);
|
||||
|
||||
void send_granted(struct file_lock *fl, int opcode);
|
||||
@ -164,6 +167,9 @@ void copy_nlm4_lock_to_nlm4_holder(const struct nlm4_lock *src,
|
||||
void deallocate_file_lock(struct file_lock *fl);
|
||||
int regions_overlap(const u_int64_t start1, const u_int64_t len1,
|
||||
const u_int64_t start2, const u_int64_t len2);;
|
||||
enum split_status region_compare(const u_int64_t starte, const u_int64_t lene,
|
||||
const u_int64_t startu, const u_int64_t lenu,
|
||||
u_int64_t *start1, u_int64_t *len1, u_int64_t *start2, u_int64_t *len2);
|
||||
int same_netobj(const netobj *n0, const netobj *n1);
|
||||
int same_filelock_identity(const struct file_lock *fl0,
|
||||
const struct file_lock *fl2);
|
||||
@ -174,18 +180,18 @@ void dump_static_object(const unsigned char* object, const int sizeof_object,
|
||||
unsigned char* cbuff, const int sizeof_cbuff);
|
||||
void dump_netobj(const struct netobj *nobj);
|
||||
void dump_filelock(const struct file_lock *fl);
|
||||
struct file_lock * malloccopy_filelock(struct file_lock *fl);
|
||||
struct file_lock * get_lock_matching_unlock(const struct file_lock *fl);
|
||||
enum nfslock_status test_nfslock(const struct file_lock *fl,
|
||||
struct file_lock **conflicting_fl);
|
||||
enum nfslock_status lock_nfslock(struct file_lock *fl);
|
||||
enum nfslock_status delete_nfslock(struct file_lock *fl);
|
||||
enum nfslock_status unlock_nfslock(const struct file_lock *fl,
|
||||
struct file_lock **released_lock, struct file_lock *left_lock,
|
||||
struct file_lock *right_lock);
|
||||
struct file_lock **released_lock, struct file_lock **left_lock,
|
||||
struct file_lock **right_lock);
|
||||
enum hwlock_status lock_hwlock(struct file_lock *fl);
|
||||
enum split_status split_nfslock(const struct file_lock *exist_lock,
|
||||
const struct file_lock *unlock_lock, const struct file_lock *right_lock);
|
||||
enum split_status split_nfslock(const struct file_lock *exist_lock,
|
||||
const struct file_lock *unlock_lock, struct file_lock **left_lock,
|
||||
struct file_lock **right_lock);
|
||||
void add_blockingfilelock(struct file_lock *fl);
|
||||
enum hwlock_status unlock_hwlock(const struct file_lock *fl);
|
||||
enum hwlock_status test_hwlock(const struct file_lock *fl,
|
||||
@ -311,18 +317,21 @@ dump_filelock(const struct file_lock *fl)
|
||||
}
|
||||
|
||||
if (fl != NULL) {
|
||||
debuglog("Dumping file lock structure\n");
|
||||
debuglog("Dumping file lock structure @ %p\n", fl);
|
||||
|
||||
/*
|
||||
dump_static_object((unsigned char *)&fl->filehandle,
|
||||
sizeof(fl->filehandle), hbuff, sizeof(hbuff),
|
||||
cbuff, sizeof(cbuff));
|
||||
debuglog("Filehandle: %8s ::: %8s\n", hbuff, cbuff);
|
||||
*/
|
||||
|
||||
debuglog("Dumping nlm4_holder:\n"
|
||||
"exc: %x svid: %x offset:len %llx:%llx\n",
|
||||
fl->client.exclusive, fl->client.svid,
|
||||
fl->client.l_offset, fl->client.l_len);
|
||||
|
||||
|
||||
/*
|
||||
debuglog("Dumping client identity:\n");
|
||||
dump_netobj(&fl->client.oh);
|
||||
|
||||
@ -332,17 +341,12 @@ dump_filelock(const struct file_lock *fl)
|
||||
debuglog("nsm: %d status: %d flags: %d locker: %d"
|
||||
" fd: %d\n", fl->nsm_status, fl->status,
|
||||
fl->flags, fl->locker, fl->fd);
|
||||
*/
|
||||
} else {
|
||||
debuglog("NULL file lock structure\n");
|
||||
}
|
||||
}
|
||||
|
||||
struct file_lock *
|
||||
malloccopy_filelock(struct file_lock *fl)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
copy_nlm4_lock_to_nlm4_holder(src, exclusive, dest)
|
||||
const struct nlm4_lock *src;
|
||||
@ -358,10 +362,68 @@ copy_nlm4_lock_to_nlm4_holder(src, exclusive, dest)
|
||||
dest->l_len = src->l_len;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* allocate_file_lock: Create a lock with the given parameters
|
||||
*/
|
||||
|
||||
struct file_lock *
|
||||
allocate_file_lock(const netobj *lockowner, const netobj *matchcookie)
|
||||
{
|
||||
struct file_lock *newfl;
|
||||
|
||||
newfl = malloc(sizeof(struct file_lock));
|
||||
if (newfl == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
bzero(newfl, sizeof(newfl));
|
||||
|
||||
newfl->client.oh.n_bytes = malloc(lockowner->n_len);
|
||||
if (newfl->client.oh.n_bytes == NULL) {
|
||||
free(newfl);
|
||||
return NULL;
|
||||
}
|
||||
newfl->client.oh.n_len = lockowner->n_len;
|
||||
bcopy(lockowner->n_bytes, newfl->client.oh.n_bytes, lockowner->n_len);
|
||||
|
||||
newfl->client_cookie.n_bytes = malloc(matchcookie->n_len);
|
||||
if (newfl->client_cookie.n_bytes == NULL) {
|
||||
free(newfl->client.oh.n_bytes);
|
||||
free(newfl);
|
||||
return NULL;
|
||||
}
|
||||
newfl->client_cookie.n_len = matchcookie->n_len;
|
||||
bcopy(matchcookie->n_bytes, newfl->client_cookie.n_bytes, matchcookie->n_len);
|
||||
|
||||
return newfl;
|
||||
}
|
||||
|
||||
/*
|
||||
* file_file_lock: Force creation of a valid file lock
|
||||
*/
|
||||
void
|
||||
fill_file_lock(struct file_lock *fl, const fhandle_t *fh, struct sockaddr *addr,
|
||||
const bool_t exclusive, const int32_t svid, const u_int64_t offset, const u_int64_t len,
|
||||
const char* caller_name, const int state, const int status, const int flags, const int blocking)
|
||||
{
|
||||
bcopy(fh, &fl->filehandle, sizeof(fhandle_t));
|
||||
fl->addr = addr;
|
||||
|
||||
fl->client.exclusive = exclusive;
|
||||
fl->client.svid = svid;
|
||||
fl->client.l_offset = offset;
|
||||
fl->client.l_len = len;
|
||||
|
||||
strncpy(fl->client_name, caller_name, SM_MAXSTRLEN);
|
||||
|
||||
fl->nsm_status = state;
|
||||
fl->status = status;
|
||||
fl->flags = flags;
|
||||
fl->blocking = blocking;
|
||||
}
|
||||
|
||||
/*
|
||||
* deallocate_file_lock: Free all storage associated with a file lock
|
||||
* XXX: Check to see if this gets *all* the dynamic structures.
|
||||
* XXX: It should be placed closer to the file_lock definition.
|
||||
*/
|
||||
void
|
||||
deallocate_file_lock(struct file_lock *fl)
|
||||
@ -373,45 +435,203 @@ deallocate_file_lock(struct file_lock *fl)
|
||||
|
||||
/*
|
||||
* regions_overlap(): This function examines the two provided regions for
|
||||
* overlap. It is non-trivial because start+len *CAN* overflow a 64-bit
|
||||
* unsigned integer and NFS semantics are unspecified on this account.
|
||||
* XXX: Check to make sure I got *ALL* the cases.
|
||||
* XXX: This DESPERATELY needs a regression test.
|
||||
* overlap.
|
||||
*/
|
||||
int
|
||||
regions_overlap(start1, len1, start2, len2)
|
||||
const u_int64_t start1, len1, start2, len2;
|
||||
{
|
||||
int result;
|
||||
u_int64_t d1,d2,d3,d4;
|
||||
enum split_status result;
|
||||
|
||||
debuglog("Entering region overlap with vals: %llu:%llu--%llu:%llu\n",
|
||||
start1, len1, start2, len2);
|
||||
|
||||
/* XXX: Look for a way to collapse the region checks */
|
||||
|
||||
/* XXX: Need to adjust checks to account for integer overflow */
|
||||
if (len1 == 0 && len2 == 0) {
|
||||
/* Regions *must* overlap if they both extend to the end */
|
||||
result = 1;
|
||||
} else if (len1 == 0) {
|
||||
/* Region 2 is completely left of region 1 */
|
||||
result = (start2 + len2 > start1);
|
||||
} else if (len2 == 0) {
|
||||
/* Region 1 is completely left of region 2 */
|
||||
result = (start1 + len1 > start2);
|
||||
} else {
|
||||
/*
|
||||
* 1 is completely left of 2 or
|
||||
* 2 is completely left of 1
|
||||
*/
|
||||
result = !(start1+len1 <= start2 || start2+len2 <= start1);
|
||||
}
|
||||
result = region_compare(start1, len1, start2, len2,
|
||||
&d1, &d2, &d3, &d4);
|
||||
|
||||
debuglog("Exiting region overlap with val: %d\n",result);
|
||||
|
||||
if (result == SPL_DISJOINT) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
* region_compare(): Examine lock regions and split appropriately
|
||||
*
|
||||
* XXX: Fix 64 bit overflow problems
|
||||
* XXX: Check to make sure I got *ALL* the cases.
|
||||
* XXX: This DESPERATELY needs a regression test.
|
||||
*/
|
||||
enum split_status
|
||||
region_compare(starte, lene, startu, lenu,
|
||||
start1, len1, start2, len2)
|
||||
const u_int64_t starte, lene, startu, lenu;
|
||||
u_int64_t *start1, *len1, *start2, *len2;
|
||||
{
|
||||
/*
|
||||
* Please pay attention to the sequential exclusions
|
||||
* of the if statements!!!
|
||||
*/
|
||||
enum LFLAGS lflags;
|
||||
enum RFLAGS rflags;
|
||||
enum split_status retval;
|
||||
|
||||
retval = SPL_DISJOINT;
|
||||
|
||||
if (lene == 0 && lenu == 0) {
|
||||
/* Examine left edge of locker */
|
||||
if (startu < starte) {
|
||||
lflags = LEDGE_LEFT;
|
||||
} else if (startu == starte) {
|
||||
lflags = LEDGE_LBOUNDARY;
|
||||
} else {
|
||||
lflags = LEDGE_INSIDE;
|
||||
}
|
||||
|
||||
rflags = REDGE_RBOUNDARY; /* Both are infiinite */
|
||||
|
||||
if (lflags == LEDGE_INSIDE) {
|
||||
*start1 = starte;
|
||||
*len1 = startu - starte;
|
||||
}
|
||||
|
||||
if (lflags == LEDGE_LEFT || lflags == LEDGE_LBOUNDARY) {
|
||||
retval = SPL_CONTAINED;
|
||||
} else {
|
||||
retval = SPL_LOCK1;
|
||||
}
|
||||
} else if (lene == 0 && lenu != 0) {
|
||||
/* Established lock is infinite */
|
||||
/* Examine left edge of unlocker */
|
||||
if (startu < starte) {
|
||||
lflags = LEDGE_LEFT;
|
||||
} else if (startu == starte) {
|
||||
lflags = LEDGE_LBOUNDARY;
|
||||
} else if (startu > starte) {
|
||||
lflags = LEDGE_INSIDE;
|
||||
}
|
||||
|
||||
/* Examine right edge of unlocker */
|
||||
if (startu + lenu < starte) {
|
||||
/* Right edge of unlocker left of established lock */
|
||||
rflags = REDGE_LEFT;
|
||||
return SPL_DISJOINT;
|
||||
} else if (startu + lenu == starte) {
|
||||
/* Right edge of unlocker on start of established lock */
|
||||
rflags = REDGE_LBOUNDARY;
|
||||
return SPL_DISJOINT;
|
||||
} else { /* Infinifty is right of finity */
|
||||
/* Right edge of unlocker inside established lock */
|
||||
rflags = REDGE_INSIDE;
|
||||
}
|
||||
|
||||
if (lflags == LEDGE_INSIDE) {
|
||||
*start1 = starte;
|
||||
*len1 = startu - starte;
|
||||
retval |= SPL_LOCK1;
|
||||
}
|
||||
|
||||
if (rflags == REDGE_INSIDE) {
|
||||
/* Create right lock */
|
||||
*start2 = startu+lenu;
|
||||
*len2 = 0;
|
||||
retval |= SPL_LOCK2;
|
||||
}
|
||||
} else if (lene != 0 && lenu == 0) {
|
||||
/* Unlocker is infinite */
|
||||
/* Examine left edge of unlocker */
|
||||
if (startu < starte) {
|
||||
lflags = LEDGE_LEFT;
|
||||
retval = SPL_CONTAINED;
|
||||
return retval;
|
||||
} else if (startu == starte) {
|
||||
lflags = LEDGE_LBOUNDARY;
|
||||
retval = SPL_CONTAINED;
|
||||
return retval;
|
||||
} else if ((startu > starte) && (startu < starte + lene - 1)) {
|
||||
lflags = LEDGE_INSIDE;
|
||||
} else if (startu == starte + lene - 1) {
|
||||
lflags = LEDGE_RBOUNDARY;
|
||||
} else { /* startu > starte + lene -1 */
|
||||
lflags = LEDGE_RIGHT;
|
||||
return SPL_DISJOINT;
|
||||
}
|
||||
|
||||
rflags = REDGE_RIGHT; /* Infinity is right of finity */
|
||||
|
||||
if (lflags == LEDGE_INSIDE || lflags == LEDGE_RBOUNDARY) {
|
||||
*start1 = starte;
|
||||
*len1 = startu - starte;
|
||||
retval |= SPL_LOCK1;
|
||||
return retval;
|
||||
}
|
||||
|
||||
} else {
|
||||
/* Both locks are finite */
|
||||
|
||||
/* Examine left edge of unlocker */
|
||||
if (startu < starte) {
|
||||
lflags = LEDGE_LEFT;
|
||||
} else if (startu == starte) {
|
||||
lflags = LEDGE_LBOUNDARY;
|
||||
} else if ((startu > starte) && (startu < starte + lene - 1)) {
|
||||
lflags = LEDGE_INSIDE;
|
||||
} else if (startu == starte + lene - 1) {
|
||||
lflags = LEDGE_RBOUNDARY;
|
||||
} else { /* startu > starte + lene -1 */
|
||||
lflags = LEDGE_RIGHT;
|
||||
return SPL_DISJOINT;
|
||||
}
|
||||
|
||||
/* Examine right edge of unlocker */
|
||||
if (startu + lenu < starte) {
|
||||
/* Right edge of unlocker left of established lock */
|
||||
rflags = REDGE_LEFT;
|
||||
return SPL_DISJOINT;
|
||||
} else if (startu + lenu == starte) {
|
||||
/* Right edge of unlocker on start of established lock */
|
||||
rflags = REDGE_LBOUNDARY;
|
||||
return SPL_DISJOINT;
|
||||
} else if (startu + lenu < starte + lene) {
|
||||
/* Right edge of unlocker inside established lock */
|
||||
rflags = REDGE_INSIDE;
|
||||
} else if (startu + lenu == starte + lene) {
|
||||
/* Right edge of unlocker on right edge of established lock */
|
||||
rflags = REDGE_RBOUNDARY;
|
||||
} else { /* startu + lenu > starte + lene */
|
||||
/* Right edge of unlocker is right of established lock */
|
||||
rflags = REDGE_RIGHT;
|
||||
}
|
||||
|
||||
if (lflags == LEDGE_INSIDE || lflags == LEDGE_RBOUNDARY) {
|
||||
/* Create left lock */
|
||||
*start1 = starte;
|
||||
*len1 = (startu - starte);
|
||||
retval |= SPL_LOCK1;
|
||||
}
|
||||
|
||||
if (rflags == REDGE_INSIDE) {
|
||||
/* Create right lock */
|
||||
*start2 = startu+lenu;
|
||||
*len2 = starte+lene-(startu+lenu);
|
||||
retval |= SPL_LOCK2;
|
||||
}
|
||||
|
||||
if ((lflags == LEDGE_LEFT || lflags == LEDGE_LBOUNDARY) &&
|
||||
(rflags == REDGE_RBOUNDARY || rflags == REDGE_RIGHT)) {
|
||||
retval = SPL_CONTAINED;
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* same_netobj: Compares the apprpriate bits of a netobj for identity
|
||||
*/
|
||||
@ -676,27 +896,67 @@ delete_nfslock(struct file_lock *fl)
|
||||
}
|
||||
|
||||
enum split_status
|
||||
split_nfslock(exist_lock, unlock_lock, right_lock)
|
||||
const struct file_lock *exist_lock, *unlock_lock, *right_lock;
|
||||
split_nfslock(exist_lock, unlock_lock, left_lock, right_lock)
|
||||
const struct file_lock *exist_lock, *unlock_lock;
|
||||
struct file_lock **left_lock, **right_lock;
|
||||
{
|
||||
u_int64_t start1, len1, start2, len2;
|
||||
enum split_status spstatus;
|
||||
|
||||
spstatus = region_compare(exist_lock->client.l_offset, exist_lock->client.l_len,
|
||||
unlock_lock->client.l_offset, unlock_lock->client.l_len,
|
||||
&start1, &len1, &start2, &len2);
|
||||
|
||||
if ((spstatus & SPL_LOCK1) != 0) {
|
||||
*left_lock = allocate_file_lock(&exist_lock->client.oh, &exist_lock->client_cookie);
|
||||
if (*left_lock == NULL) {
|
||||
debuglog("Unable to allocate resource for split 1\n");
|
||||
return SPL_RESERR;
|
||||
}
|
||||
|
||||
fill_file_lock(*left_lock, &exist_lock->filehandle, exist_lock->addr,
|
||||
exist_lock->client.exclusive, exist_lock->client.svid,
|
||||
start1, len1,
|
||||
exist_lock->client_name, exist_lock->nsm_status,
|
||||
exist_lock->status, exist_lock->flags, exist_lock->blocking);
|
||||
}
|
||||
|
||||
if ((spstatus & SPL_LOCK2) != 0) {
|
||||
*right_lock = allocate_file_lock(&exist_lock->client.oh, &exist_lock->client_cookie);
|
||||
if (*right_lock == NULL) {
|
||||
debuglog("Unable to allocate resource for split 1\n");
|
||||
if (*left_lock != NULL) {
|
||||
deallocate_file_lock(*left_lock);
|
||||
}
|
||||
return SPL_RESERR;
|
||||
}
|
||||
|
||||
fill_file_lock(*right_lock, &exist_lock->filehandle, exist_lock->addr,
|
||||
exist_lock->client.exclusive, exist_lock->client.svid,
|
||||
start2, len2,
|
||||
exist_lock->client_name, exist_lock->nsm_status,
|
||||
exist_lock->status, exist_lock->flags, exist_lock->blocking);
|
||||
}
|
||||
|
||||
return spstatus;
|
||||
}
|
||||
|
||||
enum nfslock_status
|
||||
unlock_nfslock(fl, released_lock, left_lock, right_lock)
|
||||
const struct file_lock *fl;
|
||||
struct file_lock **released_lock;
|
||||
struct file_lock *left_lock;
|
||||
struct file_lock *right_lock;
|
||||
struct file_lock **left_lock;
|
||||
struct file_lock **right_lock;
|
||||
{
|
||||
struct file_lock *mfl; /* Matching file lock */
|
||||
enum nfslock_status retval;
|
||||
enum split_status spstatus;
|
||||
|
||||
debuglog("Entering unlock_nfslock\n");
|
||||
|
||||
*released_lock = NULL;
|
||||
left_lock = NULL;
|
||||
right_lock = NULL;
|
||||
*left_lock = NULL;
|
||||
*right_lock = NULL;
|
||||
|
||||
retval = NFS_DENIED_NOLOCK;
|
||||
|
||||
@ -704,29 +964,49 @@ unlock_nfslock(fl, released_lock, left_lock, right_lock)
|
||||
mfl = get_lock_matching_unlock(fl);
|
||||
|
||||
if (mfl != NULL) {
|
||||
debuglog("Unlock matched\n");
|
||||
debuglog("Unlock matched. Querying for split\n");
|
||||
|
||||
spstatus = split_nfslock(mfl, fl, left_lock, right_lock);
|
||||
|
||||
debuglog("Split returned %d %p %p %p %p\n",spstatus,mfl,fl,*left_lock,*right_lock);
|
||||
debuglog("********Split dumps********");
|
||||
dump_filelock(mfl);
|
||||
dump_filelock(fl);
|
||||
dump_filelock(*left_lock);
|
||||
dump_filelock(*right_lock);
|
||||
debuglog("********End Split dumps********");
|
||||
|
||||
if (spstatus == SPL_RESERR) {
|
||||
if (*left_lock != NULL) {
|
||||
deallocate_file_lock(*left_lock);
|
||||
*left_lock = NULL;
|
||||
}
|
||||
|
||||
if (*right_lock != NULL) {
|
||||
deallocate_file_lock(*right_lock);
|
||||
*right_lock = NULL;
|
||||
}
|
||||
|
||||
return NFS_RESERR;
|
||||
}
|
||||
|
||||
/* Insert new locks from split if required */
|
||||
if (*left_lock != NULL) {
|
||||
debuglog("Split left activated\n");
|
||||
LIST_INSERT_HEAD(&nfslocklist_head, *left_lock, nfslocklist);
|
||||
}
|
||||
|
||||
if (*right_lock != NULL) {
|
||||
debuglog("Split right activated\n");
|
||||
LIST_INSERT_HEAD(&nfslocklist_head, *right_lock, nfslocklist);
|
||||
}
|
||||
|
||||
/* Unlock the lock since it matches identity */
|
||||
LIST_REMOVE(mfl, nfslocklist);
|
||||
*released_lock = mfl;
|
||||
retval = NFS_GRANTED;
|
||||
}
|
||||
|
||||
#if 0
|
||||
split_status = split_nfslock(mfl,fl,lfl,rfl);
|
||||
|
||||
if (split_status == SPL_DISJOINT) {
|
||||
/* Shouldn't happen, throw error */
|
||||
} else if (split_status == SPL_LOCK_CONTAINED) {
|
||||
/* Delete entire lock */
|
||||
} else if (split_status == SPL_LOCK_LEFT) {
|
||||
/* Create new lock for left lock and delete old one */
|
||||
} else if (split_status == SPL_LOCK_RIGHT) {
|
||||
/* Create new lock for right lock and delete old one */
|
||||
} else if (split_status == SPL_UNLOCK_CONTAINED) {
|
||||
/* Create new locks for both and then delete old one */
|
||||
}
|
||||
#endif
|
||||
|
||||
debuglog("Exiting unlock_nfslock\n");
|
||||
|
||||
return retval;
|
||||
@ -1129,14 +1409,28 @@ unlock_partialfilelock(const struct file_lock *fl)
|
||||
struct file_lock *lfl,*rfl,*releasedfl,*selffl;
|
||||
enum partialfilelock_status retval;
|
||||
enum nfslock_status unlstatus;
|
||||
enum hwlock_status unlhwstatus;
|
||||
enum hwlock_status unlhwstatus, lhwstatus;
|
||||
|
||||
debuglog("Entering unlock_partialfilelock\n");
|
||||
|
||||
selffl = NULL;
|
||||
lfl = NULL;
|
||||
rfl = NULL;
|
||||
releasedfl = NULL;
|
||||
retval = PFL_DENIED;
|
||||
|
||||
/*
|
||||
* There are significant overlap and atomicity issues
|
||||
* with partially releasing a lock. For example, releasing
|
||||
* part of an NFS shared lock does *not* always release the
|
||||
* corresponding part of the file since there is only one
|
||||
* rpc.lockd UID but multiple users could be requesting it
|
||||
* from NFS. Also, an unlock request should never allow
|
||||
* another process to gain a lock on the remaining parts.
|
||||
* ie. Always apply the new locks before releasing the
|
||||
* old one
|
||||
*/
|
||||
|
||||
/*
|
||||
* Loop is required since multiple little locks
|
||||
* can be allocated and then deallocated with one
|
||||
@ -1149,14 +1443,36 @@ unlock_partialfilelock(const struct file_lock *fl)
|
||||
|
||||
do {
|
||||
debuglog("Value of releasedfl: %p\n",releasedfl);
|
||||
unlstatus = unlock_nfslock(fl, &releasedfl, lfl, rfl);
|
||||
/* lfl&rfl are created *AND* placed into the NFS lock list if required */
|
||||
unlstatus = unlock_nfslock(fl, &releasedfl, &lfl, &rfl);
|
||||
debuglog("Value of releasedfl: %p\n",releasedfl);
|
||||
|
||||
|
||||
/* XXX: This is grungy. It should be refactored to be cleaner */
|
||||
if (lfl != NULL) {
|
||||
lhwstatus = lock_hwlock(lfl);
|
||||
if (lhwstatus != HW_GRANTED &&
|
||||
lhwstatus != HW_GRANTED_DUPLICATE) {
|
||||
debuglog("HW duplicate lock failure for left split\n");
|
||||
}
|
||||
monitor_lock_host(lfl->client_name);
|
||||
}
|
||||
|
||||
if (rfl != NULL) {
|
||||
lhwstatus = lock_hwlock(rfl);
|
||||
if (lhwstatus != HW_GRANTED &&
|
||||
lhwstatus != HW_GRANTED_DUPLICATE) {
|
||||
debuglog("HW duplicate lock failure for right split\n");
|
||||
}
|
||||
monitor_lock_host(rfl->client_name);
|
||||
}
|
||||
|
||||
switch (unlstatus) {
|
||||
case NFS_GRANTED:
|
||||
/* Attempt to unlock on the hardware */
|
||||
debuglog("NFS unlock granted. Attempting hardware unlock\n");
|
||||
|
||||
|
||||
/* This call *MUST NOT* unlock the two newly allocated locks */
|
||||
unlhwstatus = unlock_hwlock(fl);
|
||||
debuglog("HW unlock returned with code %d\n",unlhwstatus);
|
||||
|
||||
@ -1183,13 +1499,6 @@ unlock_partialfilelock(const struct file_lock *fl)
|
||||
|
||||
debuglog("Exiting with status retval: %d\n",retval);
|
||||
|
||||
/*
|
||||
* XXX: this deallocation *still* needs to migrate closer
|
||||
* to the allocation code way up in get_lock or the allocation
|
||||
* code needs to migrate down (violation of "When you write
|
||||
* malloc you must write free")
|
||||
*/
|
||||
|
||||
retry_blockingfilelocklist();
|
||||
break;
|
||||
case NFS_DENIED_NOLOCK:
|
||||
@ -1213,6 +1522,13 @@ unlock_partialfilelock(const struct file_lock *fl)
|
||||
debuglog("Attempt to unlock self\n");
|
||||
selffl = releasedfl;
|
||||
} else {
|
||||
/*
|
||||
* XXX: this deallocation *still* needs to migrate closer
|
||||
* to the allocation code way up in get_lock or the allocation
|
||||
* code needs to migrate down (violation of "When you write
|
||||
* malloc you must write free")
|
||||
*/
|
||||
|
||||
deallocate_file_lock(releasedfl);
|
||||
}
|
||||
}
|
||||
@ -1535,6 +1851,7 @@ testlock(struct nlm4_lock *lock, bool_t exclusive, int flags)
|
||||
* Otherwise try to lock. If we're allowed to block, fork a child which
|
||||
* will do the blocking lock.
|
||||
*/
|
||||
|
||||
enum nlm_stats
|
||||
getlock(nlm4_lockargs *lckarg, struct svc_req *rqstp, const int flags)
|
||||
{
|
||||
@ -1546,11 +1863,11 @@ getlock(nlm4_lockargs *lckarg, struct svc_req *rqstp, const int flags)
|
||||
if (grace_expired == 0 && lckarg->reclaim == 0)
|
||||
return (flags & LOCK_V4) ?
|
||||
nlm4_denied_grace_period : nlm_denied_grace_period;
|
||||
|
||||
|
||||
/* allocate new file_lock for this request */
|
||||
newfl = malloc(sizeof(struct file_lock));
|
||||
newfl = allocate_file_lock(&lckarg->alock.oh, &lckarg->cookie);
|
||||
if (newfl == NULL) {
|
||||
syslog(LOG_NOTICE, "malloc failed: %s", strerror(errno));
|
||||
syslog(LOG_NOTICE, "lock allocate failed: %s", strerror(errno));
|
||||
/* failed */
|
||||
return (flags & LOCK_V4) ?
|
||||
nlm4_denied_nolocks : nlm_denied_nolocks;
|
||||
@ -1561,46 +1878,14 @@ getlock(nlm4_lockargs *lckarg, struct svc_req *rqstp, const int flags)
|
||||
lckarg->alock.fh.n_len, (int)sizeof(fhandle_t));
|
||||
}
|
||||
|
||||
bcopy(lckarg->alock.fh.n_bytes,&newfl->filehandle, sizeof(fhandle_t));
|
||||
newfl->addr = (struct sockaddr *)svc_getrpccaller(rqstp->rq_xprt)->buf;
|
||||
newfl->client.exclusive = lckarg->exclusive;
|
||||
newfl->client.svid = lckarg->alock.svid;
|
||||
newfl->client.oh.n_bytes = malloc(lckarg->alock.oh.n_len);
|
||||
if (newfl->client.oh.n_bytes == NULL) {
|
||||
syslog(LOG_NOTICE, "malloc failed: %s", strerror(errno));
|
||||
free(newfl);
|
||||
return (flags & LOCK_V4) ?
|
||||
nlm4_denied_nolocks : nlm_denied_nolocks;
|
||||
}
|
||||
|
||||
newfl->client.oh.n_len = lckarg->alock.oh.n_len;
|
||||
bcopy(lckarg->alock.oh.n_bytes, newfl->client.oh.n_bytes,
|
||||
lckarg->alock.oh.n_len);
|
||||
newfl->client.l_offset = lckarg->alock.l_offset;
|
||||
newfl->client.l_len = lckarg->alock.l_len;
|
||||
newfl->client_cookie.n_len = lckarg->cookie.n_len;
|
||||
newfl->client_cookie.n_bytes = malloc(lckarg->cookie.n_len);
|
||||
if (newfl->client_cookie.n_bytes == NULL) {
|
||||
syslog(LOG_NOTICE, "malloc failed: %s", strerror(errno));
|
||||
free(newfl->client.oh.n_bytes);
|
||||
free(newfl);
|
||||
return (flags & LOCK_V4) ?
|
||||
nlm4_denied_nolocks : nlm_denied_nolocks;
|
||||
}
|
||||
|
||||
bcopy(lckarg->cookie.n_bytes, newfl->client_cookie.n_bytes,
|
||||
lckarg->cookie.n_len);
|
||||
strncpy(newfl->client_name, lckarg->alock.caller_name, SM_MAXSTRLEN);
|
||||
newfl->nsm_status = lckarg->state;
|
||||
newfl->status = 0;
|
||||
newfl->flags = flags;
|
||||
newfl->blocking = lckarg->block;
|
||||
fill_file_lock(newfl, (fhandle_t *)lckarg->alock.fh.n_bytes,
|
||||
(struct sockaddr *)svc_getrpccaller(rqstp->rq_xprt)->buf,
|
||||
lckarg->exclusive, lckarg->alock.svid, lckarg->alock.l_offset, lckarg->alock.l_len,
|
||||
lckarg->alock.caller_name, lckarg->state, 0, flags, lckarg->block);
|
||||
|
||||
/*
|
||||
* newfl is now fully constructed and deallocate_file_lock
|
||||
* can now be used to delete it
|
||||
* The *only* place which should deallocate a file_lock is
|
||||
* either here (error condition) or the unlock code.
|
||||
*/
|
||||
|
||||
siglock();
|
||||
|
Loading…
Reference in New Issue
Block a user