2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
15 #include <afsconfig.h>
16 #include "../afs/param.h"
20 #include "../afs/sysincludes.h" /* Standard vendor system headers */
21 #include "../afs/afsincludes.h" /* Afs-based standard headers */
22 #include "../afs/afs_stats.h" /* statistics */
23 #include "../afs/afs_cbqueue.h"
24 #include "../afs/nfsclient.h"
25 #include "../afs/afs_osidnlc.h"
27 #if defined(AFS_HPUX102_ENV)
28 #define AFS_FLOCK k_flock
30 #if defined(AFS_SUN56_ENV) || defined(AFS_LINUX24_ENV)
31 #define AFS_FLOCK flock64
33 #define AFS_FLOCK flock
34 #endif /* AFS_SUN65_ENV */
35 #endif /* AFS_HPUX102_ENV */
37 static int GetFlockCount(struct vcache *avc, struct vrequest *areq);
39 void lockIdSet(flock, slp, clid)
40 int clid; /* non-zero on SGI, OSF, SunOS, Darwin, xBSD *//* XXX ptr type */
41 struct SimpleLocks *slp;
42 struct AFS_FLOCK *flock;
44 #if defined(AFS_SUN5_ENV)
45 register proc_t *procp = ttoproc(curthread);
47 #if !defined(AFS_AIX41_ENV) && !defined(AFS_LINUX20_ENV) && !defined(AFS_SGI65_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_FBSD_ENV)
49 struct proc *procp = OSI_GET_CURRENT_PROCP();
51 struct proc *procp = u.u_procp;
52 #endif /* AFS_SGI_ENV */
55 #if defined(AFS_SGI65_ENV)
57 get_current_flid(&flid);
66 slp->sysid = u.u_sysid;
70 #if defined(AFS_AIX_ENV) || defined(AFS_SUN5_ENV)
73 slp->pid = procp->p_pid;
75 slp->sysid = procp->p_sysid;
76 slp->pid = procp->p_epid;
79 #if defined(AFS_SGI_ENV)
81 slp->sysid = flid.fl_sysid;
83 slp->sysid = OSI_GET_CURRENT_SYSID();
87 #if defined(AFS_SUN_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
90 #if defined(AFS_LINUX20_ENV) || defined(AFS_HPUX_ENV)
93 slp->pid = u.u_procp->p_pid;
96 #endif /* AFS_AIX_ENV */
97 #endif /* AFS_AIX32_ENV */
100 #if defined(AFS_AIX32_ENV)
103 flock->l_pid = getpid();
105 flock->l_sysid = u.u_sysid;
106 flock->l_pid = u.u_epid;
109 #if defined(AFS_AIX_ENV) || defined(AFS_SUN5_ENV)
112 flock->l_pid = procp->p_pid;
114 flock->l_sysid = procp->p_sysid;
115 flock->l_pid = procp->p_epid;
118 #if defined(AFS_SGI_ENV)
120 flock->l_sysid = flid.fl_sysid;
122 flock->l_sysid = OSI_GET_CURRENT_SYSID();
126 #if defined(AFS_SUN_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
129 #if defined(AFS_LINUX20_ENV) || defined(AFS_HPUX_ENV)
130 flock->l_pid = getpid();
132 flock->l_pid = u.u_procp->p_pid;
136 #endif /* AFS_AIX_ENV */
137 #endif /* AFS_AIX32_ENV */
141 /* return 1 (true) if specified flock does not match alp (if
142 * specified), or any of the slp structs (if alp == 0)
144 /* I'm not sure that the comparsion of flock->pid to p_ppid
145 * is correct. Should that be a comparision of alp (or slp) ->pid
146 * to p_ppid? Especially in the context of the lower loop, where
147 * the repeated comparison doesn't make much sense...
149 static int lockIdcmp2(flock1, vp, alp, onlymine, clid)
150 struct AFS_FLOCK *flock1;
152 register struct SimpleLocks *alp;
153 int onlymine; /* don't match any locks which are held by my */
155 int clid; /* Only Irix 6.5 for now. */
157 register struct SimpleLocks *slp;
158 #if defined(AFS_SUN5_ENV)
159 register proc_t *procp = ttoproc(curthread);
161 #if !defined(AFS_AIX41_ENV) && !defined(AFS_LINUX20_ENV) && !defined(AFS_SGI65_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_FBSD_ENV)
163 struct proc *procp = curprocp;
164 #else /* AFS_SGI64_ENV */
165 struct proc *procp = u.u_procp;
166 #endif /* AFS_SGI64_ENV */
172 #if defined(AFS_AIX_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
173 if (flock1->l_sysid != alp->sysid) {
177 if ((flock1->l_pid == alp->pid) ||
178 #if defined(AFS_AIX41_ENV) || defined(AFS_LINUX20_ENV) || defined(AFS_HPUX_ENV)
179 (!onlymine && (flock1->l_pid == getppid()))
181 #if defined(AFS_SGI65_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
182 /* XXX check this. used to be *only* irix for some reason. */
183 (!onlymine && (flock1->l_pid == clid))
185 (!onlymine && (flock1->l_pid == procp->p_ppid))
194 for (slp = vp->slocks; slp; slp = slp->next) {
195 #if defined(AFS_AIX_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
196 if (flock1->l_sysid != slp->sysid) {
200 if (flock1->l_pid == slp->pid) {
204 return (1); /* failure */
208 /* we don't send multiple read flocks to the server, but rather just count
209 them up ourselves. Of course, multiple write locks are incompatible.
211 Note that we should always try to release a lock, even if we have
212 a network problem sending the release command through, since often
213 a lock is released on a close call, when the user can't retry anyway.
215 After we remove it from our structure, the lock will no longer be
216 kept alive, and the server should time it out within a few minutes.
218 94.04.13 add "force" parameter. If a child explicitly unlocks a
219 file, I guess we'll permit it. however, we don't want simple,
220 innocent closes by children to unlock files in the parent process.
222 HandleFlock(avc, acom, areq, clid, onlymine)
223 pid_t clid; /* non-zero on SGI, SunOS, OSF1 only */
224 register struct vcache *avc;
225 struct vrequest *areq;
229 struct SimpleLocks *slp, *tlp, **slpp;
231 struct AFSVolSync tsync;
233 struct AFS_FLOCK flock;
236 AFS_STATCNT(HandleFlock);
237 code = 0; /* default when we don't make any network calls */
238 lockIdSet(&flock, (struct SimpleLocks *)0, clid);
240 #if defined(AFS_SGI_ENV)
241 osi_Assert(valusema(&avc->vc_rwlock) <= 0);
242 osi_Assert(OSI_GET_LOCKID() == avc->vc_rwlockid);
244 ObtainWriteLock(&avc->lock,118);
245 if (acom & LOCK_UN) {
250 /* If the lock is held exclusive, then only the owning process
251 * or a child can unlock it. Use pid and ppid because they are
252 * unique identifiers.
254 if ((avc->flockCount < 0) && (getpid() != avc->ownslock)) {
256 if (onlymine || (getppid() != avc->ownslock)) {
258 if (onlymine || (u.u_procp->p_ppid != avc->ownslock)) {
260 ReleaseWriteLock(&avc->lock);
265 if (lockIdcmp2(&flock, avc, (struct SimpleLocks *)0, onlymine, clid)) {
266 ReleaseWriteLock(&avc->lock);
272 if (avc->flockCount == 0) {
273 ReleaseWriteLock(&avc->lock);
277 /* unlock the lock */
278 if (avc->flockCount > 0) {
280 for (slp = *slpp; slp;) {
281 if (!lockIdcmp2(&flock, avc, slp, onlymine, clid)) {
283 tlp = *slpp = slp->next;
284 osi_FreeSmallSpace(slp);
292 else if (avc->flockCount == -1) {
293 afs_StoreAllSegments(avc, areq, AFS_ASYNC); /* fsync file early */
295 /* And remove the (only) exclusive lock entry from the list... */
296 osi_FreeSmallSpace(avc->slocks);
299 if (avc->flockCount == 0) {
301 tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
303 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_RELEASELOCK);
304 #ifdef RX_ENABLE_LOCKS
306 #endif /* RX_ENABLE_LOCKS */
307 code = RXAFS_ReleaseLock(tc->id, (struct AFSFid *)
308 &avc->fid.Fid, &tsync);
309 #ifdef RX_ENABLE_LOCKS
311 #endif /* RX_ENABLE_LOCKS */
316 (afs_Analyze(tc, code, &avc->fid, areq,
317 AFS_STATS_FS_RPCIDX_RELEASELOCK,
318 SHARED_LOCK, (struct cell *)0));
322 while (1) { /* set a new lock */
324 * Upgrading from shared locks to Exclusive and vice versa
325 * is a bit tricky and we don't really support it yet. But
326 * we try to support the common used one which is upgrade
327 * a shared lock to an exclusive for the same process...
329 if ((avc->flockCount > 0 && (acom & LOCK_EX)) ||
330 (avc->flockCount == -1 && (acom & LOCK_SH))) {
332 * Upgrading from shared locks to an exclusive one:
333 * For now if all the shared locks belong to the
334 * same process then we unlock them on the server
335 * and proceed with the upgrade. Unless we change the
336 * server's locking interface impl we prohibit from
337 * unlocking other processes's shared locks...
338 * Upgrading from an exclusive lock to a shared one:
339 * Again only allowed to be done by the same process.
342 for (slp = *slpp; slp;) {
343 if (!lockIdcmp2(&flock, avc, slp, 1/*!onlymine*/, clid)) {
348 tlp = *slpp = slp->next;
349 osi_FreeSmallSpace(slp);
357 if (!code && avc->flockCount == 0) {
359 tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
361 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_RELEASELOCK);
362 #ifdef RX_ENABLE_LOCKS
364 #endif /* RX_ENABLE_LOCKS */
365 code = RXAFS_ReleaseLock(tc->id,
366 (struct AFSFid *) &avc->fid.Fid,
368 #ifdef RX_ENABLE_LOCKS
370 #endif /* RX_ENABLE_LOCKS */
375 (afs_Analyze(tc, code, &avc->fid, areq,
376 AFS_STATS_FS_RPCIDX_RELEASELOCK,
377 SHARED_LOCK, (struct cell *)0));
379 } else if (avc->flockCount == -1 && (acom & LOCK_EX)) {
380 if (lockIdcmp2(&flock, avc, (struct SimpleLocks *)0, 1, clid)) {
386 /* compatible here, decide if needs to go to file server. If
387 we've already got the file locked (and thus read-locked, since
388 we've already checked for compatibility), we shouldn't send
389 the call through to the server again */
390 if (avc->flockCount == 0) {
391 /* we're the first on our block, send the call through */
392 lockType = ((acom & LOCK_EX)? LockWrite : LockRead);
394 tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
396 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_SETLOCK);
397 #ifdef RX_ENABLE_LOCKS
399 #endif /* RX_ENABLE_LOCKS */
400 code = RXAFS_SetLock(tc->id, (struct AFSFid *)
401 &avc->fid.Fid, lockType, &tsync);
402 #ifdef RX_ENABLE_LOCKS
404 #endif /* RX_ENABLE_LOCKS */
409 (afs_Analyze(tc, code, &avc->fid, areq,
410 AFS_STATS_FS_RPCIDX_SETLOCK,
411 SHARED_LOCK, (struct cell *)0));
413 else code = 0; /* otherwise, pretend things worked */
416 slp = (struct SimpleLocks *) osi_AllocSmallSpace(sizeof(struct SimpleLocks));
417 if (acom & LOCK_EX) {
422 /* Record unique id of process owning exclusive lock. */
423 avc->ownslock = getpid();
426 slp->type = LockWrite;
427 slp->next = (struct SimpleLocks *)0;
429 avc->flockCount = -1;
431 slp->type = LockRead;
432 slp->next = avc->slocks;
437 lockIdSet(&flock, slp, clid);
440 /* now, if we got EWOULDBLOCK, and we're supposed to wait, we do */
441 if(((code == EWOULDBLOCK)||(code == EAGAIN)) && !(acom & LOCK_NB)) {
442 /* sleep for a second, allowing interrupts */
443 ReleaseWriteLock(&avc->lock);
444 #if defined(AFS_SGI_ENV)
445 AFS_RWUNLOCK((vnode_t *)avc, VRWLOCK_WRITE);
447 code = afs_osi_Wait(1000, (struct afs_osi_WaitHandle *) 0, 1);
448 #if defined(AFS_SGI_ENV)
449 AFS_RWLOCK((vnode_t *)avc, VRWLOCK_WRITE);
451 ObtainWriteLock(&avc->lock,120);
453 code = EINTR; /* return this if ^C typed */
460 ReleaseWriteLock(&avc->lock);
461 code = afs_CheckCode(code, areq, 1); /* defeat a buggy AIX optimization */
466 /* warn a user that a lock has been ignored */
467 afs_int32 lastWarnTime = 0;
468 static void DoLockWarning() {
469 register afs_int32 now;
472 AFS_STATCNT(DoLockWarning);
473 /* check if we've already warned someone recently */
474 if (now < lastWarnTime + 120) return;
476 /* otherwise, it is time to nag the user */
478 afs_warn("afs: byte-range lock/unlock ignored; make sure no one else is running this program.\n");
483 afs_lockctl(avc, af, flag, acred, clid, offset)
489 #if defined(AFS_SGI_ENV) || (defined(AFS_SUN_ENV) && !defined(AFS_SUN5_ENV)) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
490 afs_lockctl(avc, af, acmd, acred, clid)
494 afs_lockctl(avc, af, acmd, acred)
496 struct AFS_FLOCK *af;
500 struct AFS_UCRED *acred; {
501 struct vrequest treq;
507 AFS_STATCNT(afs_lockctl);
508 if (code = afs_InitReq(&treq, acred)) return code;
510 if (flag & VNOFLCK) return 0;
511 if (flag & CLNFLCK) {
513 } else if ((flag & GETFLCK) || (flag & RGETFLCK)) {
515 } else if ((flag & SETFLCK) || (flag & RSETFLCK)) {
519 #if (defined(AFS_SUN_ENV) || defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV)) && !defined(AFS_SUN58_ENV)
520 if ((acmd == F_GETLK) || (acmd == F_RGETLK)) {
522 if (acmd == F_GETLK) {
524 if (af->l_type == F_UNLCK)
526 #ifndef AFS_OSF_ENV /* getlock is a no-op for osf (for now) */
527 code = HandleGetLock(avc, af, &treq, clid);
529 code = afs_CheckCode(code, &treq, 2); /* defeat buggy AIX optimz */
532 else if ((acmd == F_SETLK) || (acmd == F_SETLKW)
533 #if (defined(AFS_SUN_ENV) || defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV)) && !defined(AFS_SUN58_ENV)
534 || (acmd == F_RSETLK)|| (acmd == F_RSETLKW)) {
538 /* this next check is safer when left out, but more applications work
539 with it in. However, they fail in race conditions. The question is
540 what to do for people who don't have source to their application;
541 this way at least, they can get work done */
542 #ifdef AFS_LINUX24_ENV
543 if (af->l_len == OFFSET_MAX)
544 af->l_len = 0; /* since some systems indicate it as EOF */
546 if (af->l_len == 0x7fffffff)
547 af->l_len = 0; /* since some systems indicate it as EOF */
548 #ifdef AFS_LINUX_64BIT_KERNEL
549 if (af->l_len == LONG_MAX)
550 af->l_len = 0; /* since some systems indicate it as EOF */
553 /* next line makes byte range locks always succeed,
554 even when they should block */
555 if (af->l_whence != 0 || af->l_start != 0 || af->l_len != 0) {
559 /* otherwise we can turn this into a whole-file flock */
560 if (af->l_type == F_RDLCK) code = LOCK_SH;
561 else if (af->l_type == F_WRLCK) code = LOCK_EX;
562 else if (af->l_type == F_UNLCK) code = LOCK_UN;
563 else return EINVAL; /* unknown lock type */
564 if (((acmd == F_SETLK)
565 #if (defined(AFS_SGI_ENV) || defined(AFS_SUN_ENV)) && !defined(AFS_SUN58_ENV)
566 || (acmd == F_RSETLK)
568 ) && code != LOCK_UN)
569 code |= LOCK_NB; /* non-blocking, s.v.p. */
570 #if defined(AFS_SUN_ENV) && !defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV)
571 code = HandleFlock(avc, code, &treq, clid, 0/*!onlymine*/);
573 #if defined(AFS_SGI_ENV)
574 AFS_RWLOCK((vnode_t *)avc, VRWLOCK_WRITE);
575 code = HandleFlock(avc, code, &treq, clid, 0/*!onlymine*/);
576 AFS_RWUNLOCK((vnode_t *)avc, VRWLOCK_WRITE);
578 code = HandleFlock(avc, code, &treq, 0, 0/*!onlymine*/);
581 code = afs_CheckCode(code, &treq, 3); /* defeat AIX -O bug */
589 * Get a description of the first lock which would
590 * block the lock specified. If the specified lock
591 * would succeed, fill in the lock structure with 'F_UNLCK'.
593 * To do that, we have to ask the server for the lock
595 * 1. The file is not locked by this machine.
596 * 2. Asking for write lock, and only the current
597 * PID has the file read locked.
599 #ifndef AFS_OSF_ENV /* getlock is a no-op for osf (for now) */
600 HandleGetLock(avc, af, areq, clid)
601 int clid; /* not used by some OSes */
602 register struct vcache *avc;
603 register struct vrequest *areq;
604 register struct AFS_FLOCK *af;
606 register afs_int32 code;
607 struct AFS_FLOCK flock;
609 lockIdSet(&flock, (struct SimpleLocks *)0, clid);
611 ObtainWriteLock(&avc->lock,122);
612 if (avc->flockCount == 0) {
613 /* We don't know ourselves, so ask the server. Unfortunately, we don't know the pid.
614 * Not even the server knows the pid. Besides, the process with the lock is on another machine
616 code = GetFlockCount(avc, areq);
617 if (code == 0 || (af->l_type == F_RDLCK && code > 0)) {
618 af->l_type = F_UNLCK;
622 af->l_type = F_RDLCK;
624 af->l_type = F_WRLCK;
627 #if defined(AFS_AIX_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
633 if (af->l_type == F_RDLCK) {
635 * We want a read lock. If there are only
636 * read locks, or we are the one with the
637 * write lock, say it is unlocked.
639 if (avc->flockCount > 0 || /* only read locks */
640 !lockIdcmp2(&flock, avc, (struct SimpleLocks *)0, 1, clid)) {
641 af->l_type = F_UNLCK;
645 /* one write lock, but who? */
646 af->l_type = F_WRLCK; /* not us, so lock would block */
647 if (avc->slocks) { /* we know who, so tell */
648 af->l_pid = avc->slocks->pid;
649 #if defined(AFS_AIX_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
650 af->l_sysid = avc->slocks->sysid;
653 af->l_pid = 0; /* XXX can't happen?? */
654 #if defined(AFS_AIX_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
662 * Ok, we want a write lock. If there is a write lock
663 * already, and it is not this process, we fail.
665 if (avc->flockCount < 0) {
666 if (lockIdcmp2(&flock, avc, (struct SimpleLocks *)0, 1, clid)) {
667 af->l_type = F_WRLCK;
669 af->l_pid = avc->slocks->pid;
670 #if defined(AFS_AIX_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
671 af->l_sysid = avc->slocks->sysid;
674 af->l_pid = 0; /* XXX can't happen?? */
675 #if defined(AFS_AIX_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
681 /* we are the one with the write lock */
682 af->l_type = F_UNLCK;
687 * Want a write lock, and we know there are read locks.
688 * If there is more than one, or it isn't us, we cannot lock.
690 if ((avc->flockCount > 1)
691 || lockIdcmp2(&flock, avc, (struct SimpleLocks *)0, 1, clid)) {
692 struct SimpleLocks *slp;
694 af->l_type = F_RDLCK;
696 #if defined(AFS_AIX_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
699 /* find a pid that isn't our own */
700 for (slp = avc->slocks; slp; slp = slp->next) {
701 if (lockIdcmp2(&flock, (struct vcache *)0, slp, 1, clid)) {
702 af->l_pid = slp->pid;
703 #if defined(AFS_AIX_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
704 af->l_sysid = avc->slocks->sysid;
713 * Ok, we want a write lock. If there is a write lock
714 * already, and it is not this process, we fail.
716 if (avc->flockCount < 0) {
717 if (lockIdcmp2(&flock, avc, (struct SimpleLocks *)0, 1, clid)) {
718 af->l_type = F_WRLCK;
720 af->l_pid = avc->slocks->pid;
721 #if defined(AFS_AIX_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
722 af->l_sysid = avc->slocks->sysid;
725 af->l_pid = 0; /* XXX can't happen?? */
726 #if defined(AFS_AIX_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
732 /* we are the one with the write lock */
733 af->l_type = F_UNLCK;
738 * Want a write lock, and we know there are read locks.
739 * If there is more than one, or it isn't us, we cannot lock.
741 if ((avc->flockCount > 1)
742 || lockIdcmp2(&flock, avc, (struct SimpleLocks *)0, 1, clid)) {
743 struct SimpleLocks *slp;
744 af->l_type = F_RDLCK;
746 #if defined(AFS_AIX_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
749 /* find a pid that isn't our own */
750 for (slp = avc->slocks; slp; slp = slp->next) {
751 if (lockIdcmp2(&flock, (struct vcache *)0, slp, 1, clid)) {
752 af->l_pid = slp->pid;
753 #if defined(AFS_AIX_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
754 af->l_sysid = avc->slocks->sysid;
763 * Want a write lock, and there is just one read lock, and it
764 * is this process with a read lock. Ask the server if there
765 * are any more processes with the file locked.
767 code = GetFlockCount(avc, areq);
768 if (code == 0 || code == 1) {
769 af->l_type = F_UNLCK;
773 af->l_type = F_RDLCK;
775 af->l_type = F_WRLCK;
777 #if defined(AFS_AIX_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
784 af->l_len = 0; /* to end of file */
787 ReleaseWriteLock(&avc->lock);
791 /* Get the 'flock' count from the server. This comes back in a 'spare'
792 * field from a GetStatus RPC. If we have any problems with the RPC,
793 * we lie and say the file is unlocked. If we ask any 'old' fileservers,
794 * the spare field will be a zero, saying the file is unlocked. This is
795 * OK, as a further 'lock' request will do the right thing.
797 static int GetFlockCount(struct vcache *avc, struct vrequest *areq)
799 register struct conn *tc;
800 register afs_int32 code;
801 struct AFSFetchStatus OutStatus;
802 struct AFSCallBack CallBack;
803 struct AFSVolSync tsync;
807 temp = areq->flags & O_NONBLOCK;
808 areq->flags |= O_NONBLOCK;
811 tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
813 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_FETCHSTATUS);
814 #ifdef RX_ENABLE_LOCKS
816 #endif /* RX_ENABLE_LOCKS */
817 code = RXAFS_FetchStatus(tc->id, (struct AFSFid *) &avc->fid.Fid,
818 &OutStatus, &CallBack, &tsync);
819 #ifdef RX_ENABLE_LOCKS
821 #endif /* RX_ENABLE_LOCKS */
825 (afs_Analyze(tc, code, &avc->fid, areq,
826 AFS_STATS_FS_RPCIDX_FETCHSTATUS,
827 SHARED_LOCK, (struct cell *)0));
830 areq->flags &= ~O_NONBLOCK;
833 return(0); /* failed, say it is 'unlocked' */
835 return((int)OutStatus.lockCount);
841 #if !defined(AFS_AIX_ENV) && !defined(AFS_HPUX_ENV) && !defined(AFS_SUN5_ENV) && !defined(AFS_SGI_ENV) && !defined(UKERNEL) && !defined(AFS_LINUX20_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_FBSD_ENV)
842 /* Flock not support on System V systems */
844 extern struct fileops afs_fileops;
845 afs_xflock (p, args, retval)
850 #else /* AFS_OSF_ENV */
859 struct vrequest treq;
863 AFS_STATCNT(afs_xflock);
866 uap = (struct a *)args;
867 getf(&fd, uap->fd, FILE_FLAGS_NULL, &u.u_file_state);
868 #else /* AFS_OSF_ENV */
869 uap = (struct a *)u.u_ap;
874 if (flockDone = afs_InitReq(&treq, u.u_cred)) return flockDone;
875 /* first determine whether this is any sort of vnode */
876 if (fd->f_type == DTYPE_VNODE) {
877 /* good, this is a vnode; next see if it is an AFS vnode */
878 tvc = VTOAFS(fd->f_data); /* valid, given a vnode */
879 if (IsAfsVnode(AFSTOV(tvc))) {
880 /* This is an AFS vnode, so do the work */
882 /* find real vcache entry; shouldn't be null if gnode ref count
885 tvc = VTOAFS(afs_gntovn)(tvc);
891 if ((fd->f_flag & (FEXLOCK | FSHLOCK)) && !(uap->com & LOCK_UN)) {
892 /* First, if fd already has lock, release it for relock path */
893 #if defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || (defined(AFS_SUN_ENV) && !defined(AFS_SUN5_ENV))
894 HandleFlock(tvc, LOCK_UN, &treq, u.u_procp->p_pid, 0/*!onlymine*/);
896 HandleFlock(tvc, LOCK_UN, &treq, 0, 0/*!onlymine*/);
898 fd->f_flag &= ~(FEXLOCK | FSHLOCK);
900 /* now try the requested operation */
902 #if defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || (defined(AFS_SUN_ENV) && !defined(AFS_SUN5_ENV))
903 code = HandleFlock(tvc, uap->com, &treq,
904 u.u_procp->p_pid, 0/*!onlymine*/);
906 code = HandleFlock(tvc, uap->com, &treq, 0, 0/*!onlymine*/);
912 if (uap->com & LOCK_UN) {
914 fd->f_flag &= ~(FEXLOCK | FSHLOCK);
919 #else /* AFS_OSF_ENV */
922 if (uap->com & LOCK_SH) fd->f_flag |= FSHLOCK;
923 else if (uap->com & LOCK_EX) fd->f_flag |= FEXLOCK;
927 fd->f_ops = &afs_fileops;
932 code = flock(p, args, retval);
939 #else /* AFS_OSF_ENV */
942 (*afs_longcall_procs.LC_flock)();
949 #endif /* !defined(AFS_AIX_ENV) && !defined(AFS_HPUX_ENV) && !defined(AFS_SUN5_ENV) && !defined(UKERNEL) && !defined(AFS_LINUX20_ENV) */