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"
19 #include "afs/sysincludes.h" /* Standard vendor system headers */
20 #include "afsincludes.h" /* Afs-based standard headers */
21 #include "afs/afs_stats.h" /* statistics */
22 #include "afs/afs_cbqueue.h"
23 #include "afs/nfsclient.h"
24 #include "afs/afs_osidnlc.h"
25 #include "afs/unified_afs.h"
31 /* Static prototypes */
32 static int HandleGetLock(register struct vcache *avc,
33 register struct AFS_FLOCK *af,
34 register struct vrequest *areq, int clid);
35 static int GetFlockCount(struct vcache *avc, struct vrequest *areq);
36 static int lockIdcmp2(struct AFS_FLOCK *flock1, struct vcache *vp,
37 register struct SimpleLocks *alp, int onlymine,
39 static void DoLockWarning(afs_ucred_t * acred);
41 /* int clid; * non-zero on SGI, OSF, SunOS, Darwin, xBSD ** XXX ptr type */
43 #if defined(AFS_SUN5_ENV)
45 lockIdSet(struct AFS_FLOCK *flock, struct SimpleLocks *slp, int clid)
47 proc_t *procp = ttoproc(curthread);
52 slp->pid = procp->p_pid;
54 slp->sysid = procp->p_sysid;
55 slp->pid = procp->p_epid;
60 flock->l_pid = procp->p_pid;
62 flock->l_sysid = procp->p_sysid;
63 flock->l_pid = procp->p_epid;
67 #elif defined(AFS_SGI_ENV)
69 lockIdSet(struct AFS_FLOCK *flock, struct SimpleLocks *slp, int clid)
71 # if defined(AFS_SGI65_ENV)
73 get_current_flid(&flid);
75 afs_proc_t *procp = OSI_GET_CURRENT_PROCP();
80 slp->sysid = flid.fl_sysid;
82 slp->sysid = OSI_GET_CURRENT_SYSID();
87 flock->l_sysid = flid.fl_sysid;
89 flock->l_sysid = OSI_GET_CURRENT_SYSID();
94 #elif defined(AFS_AIX_ENV)
96 lockIdSet(struct AFS_FLOCK *flock, struct SimpleLocks *slp, int clid)
98 # if !defined(AFS_AIX32_ENV)
99 afs_proc_t *procp = u.u_procp;
103 # if defined(AFS_AIX41_ENV)
106 # elif defined(AFS_AIX32_ENV)
107 slp->sysid = u.u_sysid;
110 slp->sysid = procp->p_sysid;
111 slp->pid = prcop->p_epid;
114 # if defined(AFS_AIX41_ENV)
116 flock->l_pid = getpid();
117 # elif defined(AFS_AIX32_ENV)
118 flock->l_sysid = u.u_sysid;
119 flock->l_pid = u.u_epid;
121 flock->l_sysid = procp->p_sysid;
122 flock->l_pid = procp->p_epid;
126 #elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
128 lockIdSet(struct AFS_FLOCK *flock, struct SimpleLocks *slp, int clid)
136 #elif defined(AFS_LINUX20_ENV) || defined(AFS_HPUX_ENV)
138 lockIdSet(struct AFS_FLOCK *flock, struct SimpleLocks *slp, int clid)
143 flock->l_pid = getpid();
146 #elif defined(UKERNEL)
148 lockIdSet(struct AFS_FLOCK *flock, struct SimpleLocks *slp, int clid)
151 slp->pid = get_user_struct()->u_procp->p_pid;
153 flock->l_pid = get_user_struct()->u_procp->p_pid;
158 lockIdSet(struct AFS_FLOCK *flock, struct SimpleLocks *slp, int clid)
161 slp->pid = u.u_procp->p_pid;
163 flock->l_pid = u.u_procp->p_pid;
168 /* return 1 (true) if specified flock does not match alp (if
169 * specified), or any of the slp structs (if alp == 0)
171 /* I'm not sure that the comparsion of flock->pid to p_ppid
172 * is correct. Should that be a comparision of alp (or slp) ->pid
173 * to p_ppid? Especially in the context of the lower loop, where
174 * the repeated comparison doesn't make much sense...
176 /* onlymine - don't match any locks which are held by my parent */
177 /* clid - only irix 6.5 */
180 lockIdcmp2(struct AFS_FLOCK *flock1, struct vcache *vp,
181 register struct SimpleLocks *alp, int onlymine, int clid)
183 register struct SimpleLocks *slp;
184 #if defined(AFS_SUN5_ENV)
185 register proc_t *procp = ttoproc(curthread);
187 #if !defined(AFS_AIX41_ENV) && !defined(AFS_LINUX20_ENV) && !defined(AFS_SGI65_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_XBSD_ENV)
189 afs_proc_t *procp = curprocp;
190 #elif defined(UKERNEL)
191 afs_proc_t *procp = get_user_struct()->u_procp;
193 afs_proc_t *procp = u.u_procp;
194 #endif /* AFS_SGI64_ENV */
199 #if defined(AFS_AIX_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
200 if (flock1->l_sysid != alp->sysid) {
204 if ((flock1->l_pid == alp->pid) ||
205 #if defined(AFS_AIX41_ENV) || defined(AFS_LINUX20_ENV) || defined(AFS_HPUX_ENV)
206 (!onlymine && (flock1->l_pid == getppid()))
208 #if defined(AFS_SGI65_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
209 /* XXX check this. used to be *only* irix for some reason. */
210 (!onlymine && (flock1->l_pid == clid))
212 (!onlymine && (flock1->l_pid == procp->p_ppid))
221 for (slp = vp->slocks; slp; slp = slp->next) {
222 #if defined(AFS_HAVE_FLOCK_SYSID)
223 if (flock1->l_sysid != slp->sysid) {
227 if (flock1->l_pid == slp->pid) {
231 return (1); /* failure */
235 /* we don't send multiple read flocks to the server, but rather just count
236 them up ourselves. Of course, multiple write locks are incompatible.
238 Note that we should always try to release a lock, even if we have
239 a network problem sending the release command through, since often
240 a lock is released on a close call, when the user can't retry anyway.
242 After we remove it from our structure, the lock will no longer be
243 kept alive, and the server should time it out within a few minutes.
245 94.04.13 add "force" parameter. If a child explicitly unlocks a
246 file, I guess we'll permit it. however, we don't want simple,
247 innocent closes by children to unlock files in the parent process.
249 If called when disconnected support is unabled, the discon_lock must
252 /* clid - nonzero on sgi sunos osf1 only */
254 HandleFlock(register struct vcache *avc, int acom, struct vrequest *areq,
255 pid_t clid, int onlymine)
258 struct SimpleLocks *slp, *tlp, **slpp;
260 struct AFSVolSync tsync;
262 struct AFS_FLOCK flock;
264 AFS_STATCNT(HandleFlock);
265 code = 0; /* default when we don't make any network calls */
266 lockIdSet(&flock, NULL, clid);
268 #if defined(AFS_SGI_ENV)
269 osi_Assert(valusema(&avc->vc_rwlock) <= 0);
270 osi_Assert(OSI_GET_LOCKID() == avc->vc_rwlockid);
272 ObtainWriteLock(&avc->lock, 118);
273 if (acom & LOCK_UN) {
278 /* If the lock is held exclusive, then only the owning process
279 * or a child can unlock it. Use pid and ppid because they are
280 * unique identifiers.
282 if ((avc->flockCount < 0) && (getpid() != avc->ownslock)) {
284 if (onlymine || (getppid() != avc->ownslock)) {
286 if (onlymine || (u.u_procp->p_ppid != avc->ownslock)) {
288 ReleaseWriteLock(&avc->lock);
293 if (lockIdcmp2(&flock, avc, NULL, onlymine, clid)) {
294 ReleaseWriteLock(&avc->lock);
300 if (avc->flockCount == 0) {
301 ReleaseWriteLock(&avc->lock);
305 /* unlock the lock */
306 if (avc->flockCount > 0) {
308 for (slp = *slpp; slp;) {
309 if (!lockIdcmp2(&flock, avc, slp, onlymine, clid)) {
311 tlp = *slpp = slp->next;
312 osi_FreeSmallSpace(slp);
319 } else if (avc->flockCount == -1) {
320 afs_StoreAllSegments(avc, areq, AFS_SYNC | AFS_VMSYNC); /* fsync file early */
322 /* And remove the (only) exclusive lock entry from the list... */
323 osi_FreeSmallSpace(avc->slocks);
326 if (avc->flockCount == 0) {
327 if (!AFS_IS_DISCONNECTED) {
329 tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
331 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_RELEASELOCK);
333 code = RXAFS_ReleaseLock(tc->id, (struct AFSFid *)
334 &avc->f.fid.Fid, &tsync);
340 (tc, code, &avc->f.fid, areq,
341 AFS_STATS_FS_RPCIDX_RELEASELOCK, SHARED_LOCK, NULL));
343 /*printf("Network is dooooooowwwwwwwnnnnnnn\n");*/
348 while (1) { /* set a new lock */
350 * Upgrading from shared locks to Exclusive and vice versa
351 * is a bit tricky and we don't really support it yet. But
352 * we try to support the common used one which is upgrade
353 * a shared lock to an exclusive for the same process...
355 if ((avc->flockCount > 0 && (acom & LOCK_EX))
356 || (avc->flockCount == -1 && (acom & LOCK_SH))) {
358 * Upgrading from shared locks to an exclusive one:
359 * For now if all the shared locks belong to the
360 * same process then we unlock them on the server
361 * and proceed with the upgrade. Unless we change the
362 * server's locking interface impl we prohibit from
363 * unlocking other processes's shared locks...
364 * Upgrading from an exclusive lock to a shared one:
365 * Again only allowed to be done by the same process.
368 for (slp = *slpp; slp;) {
370 (&flock, avc, slp, 1 /*!onlymine */ , clid)) {
375 tlp = *slpp = slp->next;
376 osi_FreeSmallSpace(slp);
384 if (!code && avc->flockCount == 0) {
385 if (!AFS_IS_DISCONNECTED) {
387 tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
390 (AFS_STATS_FS_RPCIDX_RELEASELOCK);
393 RXAFS_ReleaseLock(tc->id,
394 (struct AFSFid *)&avc->
401 (tc, code, &avc->f.fid, areq,
402 AFS_STATS_FS_RPCIDX_RELEASELOCK, SHARED_LOCK,
406 } else if (avc->flockCount == -1 && (acom & LOCK_EX)) {
407 if (lockIdcmp2(&flock, avc, NULL, 1, clid)) {
413 /* compatible here, decide if needs to go to file server. If
414 * we've already got the file locked (and thus read-locked, since
415 * we've already checked for compatibility), we shouldn't send
416 * the call through to the server again */
417 if (avc->flockCount == 0) {
418 /* we're the first on our block, send the call through */
419 lockType = ((acom & LOCK_EX) ? LockWrite : LockRead);
420 if (!AFS_IS_DISCONNECTED) {
422 tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
424 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_SETLOCK);
426 code = RXAFS_SetLock(tc->id, (struct AFSFid *)
427 &avc->f.fid.Fid, lockType,
434 (tc, code, &avc->f.fid, areq,
435 AFS_STATS_FS_RPCIDX_SETLOCK, SHARED_LOCK,
437 if ((LockType == LockWrite) && (code == VREADONLY))
438 code = EBADF; /* per POSIX; VREADONLY == EROFS */
440 /* XXX - Should probably try and log this when we're
441 * XXX - running with logging enabled. But it's horrid
443 code = 0; /* pretend we worked - ick!!! */
445 code = 0; /* otherwise, pretend things worked */
448 slp = (struct SimpleLocks *)
449 osi_AllocSmallSpace(sizeof(struct SimpleLocks));
450 if (acom & LOCK_EX) {
455 /* Record unique id of process owning exclusive lock. */
456 avc->ownslock = getpid();
459 slp->type = LockWrite;
462 avc->flockCount = -1;
464 slp->type = LockRead;
465 slp->next = avc->slocks;
470 lockIdSet(&flock, slp, clid);
473 /* now, if we got EWOULDBLOCK, and we're supposed to wait, we do */
474 if (((code == EWOULDBLOCK) || (code == EAGAIN) ||
475 (code == UAEWOULDBLOCK) || (code == UAEAGAIN))
476 && !(acom & LOCK_NB)) {
477 /* sleep for a second, allowing interrupts */
478 ReleaseWriteLock(&avc->lock);
479 #if defined(AFS_SGI_ENV)
480 AFS_RWUNLOCK((vnode_t *) avc, VRWLOCK_WRITE);
482 code = afs_osi_Wait(1000, NULL, 1);
483 #if defined(AFS_SGI_ENV)
484 AFS_RWLOCK((vnode_t *) avc, VRWLOCK_WRITE);
486 ObtainWriteLock(&avc->lock, 120);
488 code = EINTR; /* return this if ^C typed */
495 ReleaseWriteLock(&avc->lock);
496 code = afs_CheckCode(code, areq, 1); /* defeat a buggy AIX optimization */
501 /* warn a user that a lock has been ignored */
502 afs_int32 lastWarnTime = 0; /* this is used elsewhere */
503 static afs_int32 lastWarnPid = 0;
505 DoLockWarning(afs_ucred_t * acred)
507 register afs_int32 now;
508 pid_t pid = MyPidxx2Pid(MyPidxx);
513 AFS_STATCNT(DoLockWarning);
514 /* check if we've already warned this user recently */
515 if (!((now < lastWarnTime + 120) && (lastWarnPid == pid))) {
516 procname = afs_osi_Alloc(256);
521 /* Copies process name to allocated procname, see osi_machdeps for details of macro */
522 osi_procname(procname, 256);
523 procname[255] = '\0';
525 /* otherwise, it is time to nag the user */
528 #ifdef AFS_LINUX26_ENV
530 ("afs: byte-range locks only enforced for processes on this machine (pid %d (%s), user %ld).\n", pid, procname, (long)afs_cr_uid(acred));
533 ("afs: byte-range lock/unlock ignored; make sure no one else is running this program (pid %d (%s), user %ld).\n", pid, procname, afs_cr_uid(acred));
535 afs_osi_Free(procname, 256);
541 #if defined(AFS_SGI_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
542 int afs_lockctl(struct vcache * avc, struct AFS_FLOCK * af, int acmd,
543 afs_ucred_t * acred, pid_t clid)
546 int afs_lockctl(struct vcache * avc, struct AFS_FLOCK * af, int acmd,
550 struct vrequest treq;
552 struct afs_fakestat_state fakestate;
554 AFS_STATCNT(afs_lockctl);
555 if ((code = afs_InitReq(&treq, acred)))
557 afs_InitFakeStat(&fakestate);
561 code = afs_EvalFakeStat(&avc, &fakestate, &treq);
565 #if (defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV)) && !defined(AFS_SUN58_ENV)
566 if ((acmd == F_GETLK) || (acmd == F_RGETLK)) {
568 if (acmd == F_GETLK) {
570 if (af->l_type == F_UNLCK) {
574 code = HandleGetLock(avc, af, &treq, clid);
575 code = afs_CheckCode(code, &treq, 2); /* defeat buggy AIX optimz */
577 } else if ((acmd == F_SETLK) || (acmd == F_SETLKW)
578 #if (defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV)) && !defined(AFS_SUN58_ENV)
579 || (acmd == F_RSETLK) || (acmd == F_RSETLKW)) {
583 /* Java VMs ask for l_len=(long)-1 regardless of OS/CPU */
584 if ((sizeof(af->l_len) == 8) && (af->l_len == 0x7fffffffffffffffLL))
586 /* next line makes byte range locks always succeed,
587 * even when they should block */
588 if (af->l_whence != 0 || af->l_start != 0 || af->l_len != 0) {
589 DoLockWarning(acred);
593 /* otherwise we can turn this into a whole-file flock */
594 if (af->l_type == F_RDLCK)
596 else if (af->l_type == F_WRLCK)
598 else if (af->l_type == F_UNLCK)
601 afs_PutFakeStat(&fakestate);
602 return EINVAL; /* unknown lock type */
604 if (((acmd == F_SETLK)
605 #if (defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV)) && !defined(AFS_SUN58_ENV)
606 || (acmd == F_RSETLK)
608 ) && code != LOCK_UN)
609 code |= LOCK_NB; /* non-blocking, s.v.p. */
610 #if defined(AFS_DARWIN_ENV)
611 code = HandleFlock(avc, code, &treq, clid, 0 /*!onlymine */ );
612 #elif defined(AFS_SGI_ENV)
613 AFS_RWLOCK((vnode_t *) avc, VRWLOCK_WRITE);
614 code = HandleFlock(avc, code, &treq, clid, 0 /*!onlymine */ );
615 AFS_RWUNLOCK((vnode_t *) avc, VRWLOCK_WRITE);
617 code = HandleFlock(avc, code, &treq, 0, 0 /*!onlymine */ );
619 code = afs_CheckCode(code, &treq, 3); /* defeat AIX -O bug */
624 afs_PutFakeStat(&fakestate);
631 * Get a description of the first lock which would
632 * block the lock specified. If the specified lock
633 * would succeed, fill in the lock structure with 'F_UNLCK'.
635 * To do that, we have to ask the server for the lock
637 * 1. The file is not locked by this machine.
638 * 2. Asking for write lock, and only the current
639 * PID has the file read locked.
642 HandleGetLock(register struct vcache *avc, register struct AFS_FLOCK *af,
643 register struct vrequest *areq, int clid)
645 register afs_int32 code;
646 struct AFS_FLOCK flock;
648 lockIdSet(&flock, NULL, clid);
650 ObtainWriteLock(&avc->lock, 122);
651 if (avc->flockCount == 0) {
653 * We don't know ourselves, so ask the server. Unfortunately, we
654 * don't know the pid. Not even the server knows the pid. Besides,
655 * the process with the lock is on another machine
657 code = GetFlockCount(avc, areq);
658 if (code == 0 || (af->l_type == F_RDLCK && code > 0)) {
659 af->l_type = F_UNLCK;
663 af->l_type = F_RDLCK;
665 af->l_type = F_WRLCK;
668 #if defined(AFS_HAVE_FLOCK_SYSID)
674 if (af->l_type == F_RDLCK) {
676 * We want a read lock. If there are only
677 * read locks, or we are the one with the
678 * write lock, say it is unlocked.
680 if (avc->flockCount > 0 || /* only read locks */
681 !lockIdcmp2(&flock, avc, NULL, 1, clid)) {
682 af->l_type = F_UNLCK;
686 /* one write lock, but who? */
687 af->l_type = F_WRLCK; /* not us, so lock would block */
688 if (avc->slocks) { /* we know who, so tell */
689 af->l_pid = avc->slocks->pid;
690 #if defined(AFS_HAVE_FLOCK_SYSID)
691 af->l_sysid = avc->slocks->sysid;
694 af->l_pid = 0; /* XXX can't happen?? */
695 #if defined(AFS_HAVE_FLOCK_SYSID)
703 * Ok, we want a write lock. If there is a write lock
704 * already, and it is not this process, we fail.
706 if (avc->flockCount < 0) {
707 if (lockIdcmp2(&flock, avc, NULL, 1, clid)) {
708 af->l_type = F_WRLCK;
710 af->l_pid = avc->slocks->pid;
711 #if defined(AFS_HAVE_FLOCK_SYSID)
712 af->l_sysid = avc->slocks->sysid;
715 af->l_pid = 0; /* XXX can't happen?? */
716 #if defined(AFS_HAVE_FLOCK_SYSID)
722 /* we are the one with the write lock */
723 af->l_type = F_UNLCK;
728 * Want a write lock, and we know there are read locks.
729 * If there is more than one, or it isn't us, we cannot lock.
731 if ((avc->flockCount > 1)
732 || lockIdcmp2(&flock, avc, NULL, 1, clid)) {
733 struct SimpleLocks *slp;
735 af->l_type = F_RDLCK;
737 #if defined(AFS_HAVE_FLOCK_SYSID)
740 /* find a pid that isn't our own */
741 for (slp = avc->slocks; slp; slp = slp->next) {
742 if (lockIdcmp2(&flock, NULL, slp, 1, clid)) {
743 af->l_pid = slp->pid;
744 #if defined(AFS_HAVE_FLOCK_SYSID)
745 af->l_sysid = avc->slocks->sysid;
754 * Ok, we want a write lock. If there is a write lock
755 * already, and it is not this process, we fail.
757 if (avc->flockCount < 0) {
758 if (lockIdcmp2(&flock, avc, NULL, 1, clid)) {
759 af->l_type = F_WRLCK;
761 af->l_pid = avc->slocks->pid;
762 #if defined(AFS_HAVE_FLOCK_SYSID)
763 af->l_sysid = avc->slocks->sysid;
766 af->l_pid = 0; /* XXX can't happen?? */
767 #if defined(AFS_HAVE_FLOCK_SYSID)
773 /* we are the one with the write lock */
774 af->l_type = F_UNLCK;
779 * Want a write lock, and we know there are read locks.
780 * If there is more than one, or it isn't us, we cannot lock.
782 if ((avc->flockCount > 1)
783 || lockIdcmp2(&flock, avc, NULL, 1, clid)) {
784 struct SimpleLocks *slp;
785 af->l_type = F_RDLCK;
787 #if defined(AFS_HAVE_FLOCK_SYSID)
790 /* find a pid that isn't our own */
791 for (slp = avc->slocks; slp; slp = slp->next) {
792 if (lockIdcmp2(&flock, NULL, slp, 1, clid)) {
793 af->l_pid = slp->pid;
794 #if defined(AFS_HAVE_FLOCK_SYSID)
795 af->l_sysid = avc->slocks->sysid;
804 * Want a write lock, and there is just one read lock, and it
805 * is this process with a read lock. Ask the server if there
806 * are any more processes with the file locked.
808 code = GetFlockCount(avc, areq);
809 if (code == 0 || code == 1) {
810 af->l_type = F_UNLCK;
814 af->l_type = F_RDLCK;
816 af->l_type = F_WRLCK;
818 #if defined(AFS_HAVE_FLOCK_SYSID)
825 af->l_len = 0; /* to end of file */
828 ReleaseWriteLock(&avc->lock);
832 /* Get the 'flock' count from the server. This comes back in a 'spare'
833 * field from a GetStatus RPC. If we have any problems with the RPC,
834 * we lie and say the file is unlocked. If we ask any 'old' fileservers,
835 * the spare field will be a zero, saying the file is unlocked. This is
836 * OK, as a further 'lock' request will do the right thing.
839 GetFlockCount(struct vcache *avc, struct vrequest *areq)
841 register struct afs_conn *tc;
842 register afs_int32 code;
843 struct AFSFetchStatus OutStatus;
844 struct AFSCallBack CallBack;
845 struct AFSVolSync tsync;
848 temp = areq->flags & O_NONBLOCK;
849 areq->flags |= O_NONBLOCK;
851 /* If we're disconnected, lie and say that we've got no locks. Ick */
852 if (AFS_IS_DISCONNECTED)
856 tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
858 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_FETCHSTATUS);
861 RXAFS_FetchStatus(tc->id, (struct AFSFid *)&avc->f.fid.Fid,
862 &OutStatus, &CallBack, &tsync);
868 (tc, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_FETCHSTATUS,
872 areq->flags &= ~O_NONBLOCK;
875 return (0); /* failed, say it is 'unlocked' */
877 return ((int)OutStatus.lockCount);