Adjust afs_lockctl to compensate for byte-range lock fixes
[openafs.git] / src / afs / VNOPS / afs_vnop_flock.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
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
8  */
9
10 /*
11  * Implements:
12  *
13  */
14
15 #include <afsconfig.h>
16 #include "afs/param.h"
17
18
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"
26
27
28
29
30
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,
38                       int clid);
39 static void DoLockWarning(void);
40
41 /* int clid;  * non-zero on SGI, OSF, SunOS, Darwin, xBSD ** XXX ptr type */
42
43 #if defined(AFS_SUN5_ENV)
44 void
45 lockIdSet(struct AFS_FLOCK *flock, struct SimpleLocks *slp, int clid)
46 {
47     proc_t *procp = ttoproc(curthread);
48
49     if (slp) {
50 # ifdef AFS_SUN53_ENV
51         slp->sysid = 0;
52         slp->pid = procp->p_pid;
53 # else
54         slp->sysid = procp->p_sysid;
55         slp->pid = procp->p_epid;
56 # endif
57     } else {
58 # ifdef AFS_SUN53_ENV
59         flock->l_sysid = 0;
60         flock->l_pid = procp->p_pid;
61 # else
62         flock->l_sysid = procp->p_sysid;
63         flock->l_pid = procp->p_epid;
64 # endif
65     }
66 }
67 #elif defined(AFS_SGI_ENV)
68 void
69 lockIdSet(struct AFS_FLOCK *flock, struct SimpleLocks *slp, int clid)
70 {
71 # if defined(AFS_SGI65_ENV)
72     flid_t flid;
73     get_current_flid(&flid);
74 # else
75     afs_proc_t *procp = OSI_GET_CURRENT_PROCP();
76 # endif
77
78     if (slp) {
79 # ifdef AFS_SGI65_ENV
80         slp->sysid = flid.fl_sysid;
81 # else
82         slp->sysid = OSI_GET_CURRENT_SYSID();
83 # endif
84         slp->pid = clid;
85     } else {
86 # ifdef AFS_SGI65_ENV
87         flock->l_sysid = flid.fl_sysid;
88 # else
89         flock->l_sysid = OSI_GET_CURRENT_SYSID();
90 # endif
91         flock->l_pid = clid;
92     }
93 }
94 #elif defined(AFS_AIX_ENV)
95 void
96 lockIdSet(struct AFS_FLOCK *flock, struct SimpleLocks *slp, int clid)
97 {
98 # if !defined(AFS_AIX32_ENV)
99     afs_proc_t *procp = u.u_procp;
100 # endif
101
102     if (slp) {
103 # if defined(AFS_AIX41_ENV)
104         slp->sysid = 0;
105         slp->pid = getpid();
106 # elif defined(AFS_AIX32_ENV)
107         slp->sysid = u.u_sysid;
108         slp->pid = u.u_epid;
109 # else
110         slp->sysid = procp->p_sysid;
111         slp->pid = prcop->p_epid;
112 # endif
113     } else {
114 # if defined(AFS_AIX41_ENV)
115         flock->l_sysid = 0;
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;
120 # else
121         flock->l_sysid = procp->p_sysid;
122         flock->l_pid = procp->p_epid;
123 # endif
124     }
125 }
126 #elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
127 void
128 lockIdSet(struct AFS_FLOCK *flock, struct SimpleLocks *slp, int clid)
129 {
130     if (slp) {
131         slp->pid = clid;
132     } else {
133         flock->l_pid = clid;
134     }
135 }
136 #elif defined(AFS_LINUX20_ENV) || defined(AFS_HPUX_ENV)
137 void
138 lockIdSet(struct AFS_FLOCK *flock, struct SimpleLocks *slp, int clid)
139 {
140     if (slp) {
141         slp->pid = getpid();
142     } else {
143         flock->l_pid = getpid();
144     }
145 }
146 #elif defined(UKERNEL)
147 void
148 lockIdSet(struct AFS_FLOCK *flock, struct SimpleLocks *slp, int clid)
149 {
150     if (slp) {
151         slp->pid = get_user_struct()->u_procp->p_pid;
152     } else {
153         flock->l_pid = get_user_struct()->u_procp->p_pid;
154     }
155 }
156 #else
157 void
158 lockIdSet(struct AFS_FLOCK *flock, struct SimpleLocks *slp, int clid)
159 {
160     if (slp) {
161         slp->pid = u.u_procp->p_pid;
162     } else {
163         flock->l_pid = u.u_procp->p_pid;
164     }
165 }
166 #endif
167
168 /* return 1 (true) if specified flock does not match alp (if 
169  * specified), or any of the slp structs (if alp == 0) 
170  */
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...
175  */
176 /* onlymine - don't match any locks which are held by my parent */
177 /* clid - only irix 6.5 */
178
179 static int
180 lockIdcmp2(struct AFS_FLOCK *flock1, struct vcache *vp,
181            register struct SimpleLocks *alp, int onlymine, int clid)
182 {
183     register struct SimpleLocks *slp;
184 #if     defined(AFS_SUN5_ENV)
185     register proc_t *procp = ttoproc(curthread);
186 #else
187 #if !defined(AFS_AIX41_ENV) && !defined(AFS_LINUX20_ENV) && !defined(AFS_SGI65_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_XBSD_ENV)
188 #ifdef AFS_SGI64_ENV
189     afs_proc_t *procp = curprocp;
190 #elif defined(UKERNEL)
191     afs_proc_t *procp = get_user_struct()->u_procp;
192 #else
193     afs_proc_t *procp = u.u_procp;
194 #endif /* AFS_SGI64_ENV */
195 #endif
196 #endif
197
198     if (alp) {
199 #if     defined(AFS_AIX_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
200         if (flock1->l_sysid != alp->sysid) {
201             return 1;
202         }
203 #endif
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()))
207 #else
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))
211 #else
212             (!onlymine && (flock1->l_pid == procp->p_ppid))
213 #endif
214 #endif
215             ) {
216             return 0;
217         }
218         return 1;
219     }
220
221     for (slp = vp->slocks; slp; slp = slp->next) {
222 #if defined(AFS_HAVE_FLOCK_SYSID)
223         if (flock1->l_sysid != slp->sysid) {
224             continue;
225         }
226 #endif
227         if (flock1->l_pid == slp->pid) {
228             return 0;
229         }
230     }
231     return (1);                 /* failure */
232 }
233
234
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.
237     
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.
241     
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.
244     
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.
248
249     If called when disconnected support is unabled, the discon_lock must
250     be held
251 */
252 /* clid - nonzero on sgi sunos osf1 only */
253 int
254 HandleFlock(register struct vcache *avc, int acom, struct vrequest *areq,
255             pid_t clid, int onlymine)
256 {
257     struct afs_conn *tc;
258     struct SimpleLocks *slp, *tlp, **slpp;
259     afs_int32 code;
260     struct AFSVolSync tsync;
261     afs_int32 lockType;
262     struct AFS_FLOCK flock;
263     XSTATS_DECLS;
264     AFS_STATCNT(HandleFlock);
265     code = 0;                   /* default when we don't make any network calls */
266     lockIdSet(&flock, NULL, clid);
267
268 #if defined(AFS_SGI_ENV)
269     osi_Assert(valusema(&avc->vc_rwlock) <= 0);
270     osi_Assert(OSI_GET_LOCKID() == avc->vc_rwlockid);
271 #endif
272     ObtainWriteLock(&avc->lock, 118);
273     if (acom & LOCK_UN) {
274
275 /* defect 3083 */
276
277 #ifdef AFS_AIX_ENV
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.
281          */
282         if ((avc->flockCount < 0) && (getpid() != avc->ownslock)) {
283 #ifdef  AFS_AIX41_ENV
284             if (onlymine || (getppid() != avc->ownslock)) {
285 #else
286             if (onlymine || (u.u_procp->p_ppid != avc->ownslock)) {
287 #endif
288                 ReleaseWriteLock(&avc->lock);
289                 return 0;
290             }
291         }
292 #endif
293         if (lockIdcmp2(&flock, avc, NULL, onlymine, clid)) {
294             ReleaseWriteLock(&avc->lock);
295             return 0;
296         }
297 #ifdef AFS_AIX_ENV
298         avc->ownslock = 0;
299 #endif
300         if (avc->flockCount == 0) {
301             ReleaseWriteLock(&avc->lock);
302             return 0 /*ENOTTY*/;
303             /* no lock held */
304         }
305         /* unlock the lock */
306         if (avc->flockCount > 0) {
307             slpp = &avc->slocks;
308             for (slp = *slpp; slp;) {
309                 if (!lockIdcmp2(&flock, avc, slp, onlymine, clid)) {
310                     avc->flockCount--;
311                     tlp = *slpp = slp->next;
312                     osi_FreeSmallSpace(slp);
313                     slp = tlp;
314                 } else {
315                     slpp = &slp->next;
316                     slp = *slpp;
317                 }
318             }
319         } else if (avc->flockCount == -1) {
320             afs_StoreAllSegments(avc, areq, AFS_ASYNC); /* fsync file early */
321             avc->flockCount = 0;
322             /* And remove the (only) exclusive lock entry from the list... */
323             osi_FreeSmallSpace(avc->slocks);
324             avc->slocks = 0;
325         }
326         if (avc->flockCount == 0) {
327             if (!AFS_IS_DISCONNECTED) {
328                 do {
329                     tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
330                     if (tc) {
331                         XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_RELEASELOCK);
332                         RX_AFS_GUNLOCK();
333                         code = RXAFS_ReleaseLock(tc->id, (struct AFSFid *)
334                                                  &avc->f.fid.Fid, &tsync);
335                         RX_AFS_GLOCK();
336                         XSTATS_END_TIME;
337                     } else
338                     code = -1;
339                 } while (afs_Analyze
340                          (tc, code, &avc->f.fid, areq,
341                           AFS_STATS_FS_RPCIDX_RELEASELOCK, SHARED_LOCK, NULL));
342             } else {
343                 /*printf("Network is dooooooowwwwwwwnnnnnnn\n");*/
344                code = ENETDOWN;
345             }
346         }
347     } else {
348         while (1) {             /* set a new lock */
349             /*
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...
354              */
355             if ((avc->flockCount > 0 && (acom & LOCK_EX))
356                 || (avc->flockCount == -1 && (acom & LOCK_SH))) {
357                 /*
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.
366                  */
367                 slpp = &avc->slocks;
368                 for (slp = *slpp; slp;) {
369                     if (!lockIdcmp2
370                         (&flock, avc, slp, 1 /*!onlymine */ , clid)) {
371                         if (acom & LOCK_EX)
372                             avc->flockCount--;
373                         else
374                             avc->flockCount = 0;
375                         tlp = *slpp = slp->next;
376                         osi_FreeSmallSpace(slp);
377                         slp = tlp;
378                     } else {
379                         code = EWOULDBLOCK;
380                         slpp = &slp->next;
381                         slp = *slpp;
382                     }
383                 }
384                 if (!code && avc->flockCount == 0) {
385                     if (!AFS_IS_DISCONNECTED) {
386                         do {
387                             tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
388                             if (tc) {
389                                 XSTATS_START_TIME
390                                     (AFS_STATS_FS_RPCIDX_RELEASELOCK);
391                                 RX_AFS_GUNLOCK();
392                                 code =
393                                     RXAFS_ReleaseLock(tc->id,
394                                                       (struct AFSFid *)&avc->
395                                                       f.fid.Fid, &tsync);
396                                 RX_AFS_GLOCK();
397                                XSTATS_END_TIME;
398                             } else
399                                 code = -1;
400                         } while (afs_Analyze
401                                  (tc, code, &avc->f.fid, areq,
402                                   AFS_STATS_FS_RPCIDX_RELEASELOCK, SHARED_LOCK,
403                                   NULL));
404                     }
405                 }
406             } else if (avc->flockCount == -1 && (acom & LOCK_EX)) {
407                 if (lockIdcmp2(&flock, avc, NULL, 1, clid)) {
408                     code = EWOULDBLOCK;
409                 } else
410                     code = 0;
411             }
412             if (code == 0) {
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) {
421                         do {
422                             tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
423                             if (tc) {
424                                 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_SETLOCK);
425                                 RX_AFS_GUNLOCK();
426                                 code = RXAFS_SetLock(tc->id, (struct AFSFid *)
427                                                      &avc->f.fid.Fid, lockType,
428                                                      &tsync);
429                                 RX_AFS_GLOCK();
430                                 XSTATS_END_TIME;
431                             } else
432                                 code = -1;
433                         } while (afs_Analyze
434                                  (tc, code, &avc->f.fid, areq,
435                                   AFS_STATS_FS_RPCIDX_SETLOCK, SHARED_LOCK,
436                                   NULL));
437                     } else
438                         /* XXX - Should probably try and log this when we're
439                          * XXX - running with logging enabled. But it's horrid
440                          */
441                         code = 0; /* pretend we worked - ick!!! */
442                 } else
443                     code = 0;   /* otherwise, pretend things worked */
444             }
445             if (code == 0) {
446                 slp = (struct SimpleLocks *)
447                     osi_AllocSmallSpace(sizeof(struct SimpleLocks));
448                 if (acom & LOCK_EX) {
449
450 /* defect 3083 */
451
452 #ifdef AFS_AIX_ENV
453                     /* Record unique id of process owning exclusive lock. */
454                     avc->ownslock = getpid();
455 #endif
456
457                     slp->type = LockWrite;
458                     slp->next = NULL;
459                     avc->slocks = slp;
460                     avc->flockCount = -1;
461                 } else {
462                     slp->type = LockRead;
463                     slp->next = avc->slocks;
464                     avc->slocks = slp;
465                     avc->flockCount++;
466                 }
467
468                 lockIdSet(&flock, slp, clid);
469                 break;
470             }
471             /* now, if we got EWOULDBLOCK, and we're supposed to wait, we do */
472             if (((code == EWOULDBLOCK) || (code == EAGAIN) || 
473                  (code == UAEWOULDBLOCK) || (code == UAEAGAIN))
474                 && !(acom & LOCK_NB)) {
475                 /* sleep for a second, allowing interrupts */
476                 ReleaseWriteLock(&avc->lock);
477 #if defined(AFS_SGI_ENV)
478                 AFS_RWUNLOCK((vnode_t *) avc, VRWLOCK_WRITE);
479 #endif
480                 code = afs_osi_Wait(1000, NULL, 1);
481 #if defined(AFS_SGI_ENV)
482                 AFS_RWLOCK((vnode_t *) avc, VRWLOCK_WRITE);
483 #endif
484                 ObtainWriteLock(&avc->lock, 120);
485                 if (code) {
486                     code = EINTR;       /* return this if ^C typed */
487                     break;
488                 }
489             } else
490                 break;
491         }                       /* while loop */
492     }
493     ReleaseWriteLock(&avc->lock);
494     code = afs_CheckCode(code, areq, 1);        /* defeat a buggy AIX optimization */
495     return code;
496 }
497
498
499 /* warn a user that a lock has been ignored */
500 afs_int32 lastWarnTime = 0;     /* this is used elsewhere */
501 static void
502 DoLockWarning(void)
503 {
504     register afs_int32 now;
505     now = osi_Time();
506
507     AFS_STATCNT(DoLockWarning);
508     /* check if we've already warned someone recently */
509     if (now < lastWarnTime + 120)
510         return;
511
512     /* otherwise, it is time to nag the user */
513     lastWarnTime = now;
514 #ifdef AFS_LINUX26_ENV
515     afs_warn
516         ("afs: byte-range locks only enforced for processes on this machine.\n");
517 #else
518     afs_warn
519         ("afs: byte-range lock/unlock ignored; make sure no one else is running this program.\n");
520 #endif
521 }
522
523
524 #if defined(AFS_SGI_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
525 int afs_lockctl(struct vcache * avc, struct AFS_FLOCK * af, int acmd,
526                 afs_ucred_t * acred, pid_t clid)
527 #else
528 u_int clid = 0;
529 int afs_lockctl(struct vcache * avc, struct AFS_FLOCK * af, int acmd,
530                 afs_ucred_t * acred)
531 #endif
532 {
533     struct vrequest treq;
534     afs_int32 code;
535     struct afs_fakestat_state fakestate;
536
537     AFS_STATCNT(afs_lockctl);
538     if ((code = afs_InitReq(&treq, acred)))
539         return code;
540     afs_InitFakeStat(&fakestate);
541
542     AFS_DISCON_LOCK();
543
544     code = afs_EvalFakeStat(&avc, &fakestate, &treq);
545     if (code) {
546         goto done;
547     }
548 #if (defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV)) && !defined(AFS_SUN58_ENV)
549     if ((acmd == F_GETLK) || (acmd == F_RGETLK)) {
550 #else
551     if (acmd == F_GETLK) {
552 #endif
553         if (af->l_type == F_UNLCK) {
554             code = 0;
555             goto done;
556         }
557         code = HandleGetLock(avc, af, &treq, clid);
558         code = afs_CheckCode(code, &treq, 2);   /* defeat buggy AIX optimz */
559         goto done;
560     } else if ((acmd == F_SETLK) || (acmd == F_SETLKW)
561 #if (defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV)) && !defined(AFS_SUN58_ENV)
562                || (acmd == F_RSETLK) || (acmd == F_RSETLKW)) {
563 #else
564         ) {
565 #endif
566     /* Java VMs ask for l_len=(long)-1 regardless of OS/CPU */
567     if ((sizeof(af->l_len) == 8) && (af->l_len == 0x7fffffffffffffffLL))
568         af->l_len = 0;
569     /* next line makes byte range locks always succeed,
570      * even when they should block */
571     if (af->l_whence != 0 || af->l_start != 0 || af->l_len != 0) {
572         DoLockWarning();
573         code = 0;
574         goto done;
575     }
576     /* otherwise we can turn this into a whole-file flock */
577     if (af->l_type == F_RDLCK)
578         code = LOCK_SH;
579     else if (af->l_type == F_WRLCK)
580         code = LOCK_EX;
581     else if (af->l_type == F_UNLCK)
582         code = LOCK_UN;
583     else {
584         afs_PutFakeStat(&fakestate);
585         return EINVAL;          /* unknown lock type */
586     }
587     if (((acmd == F_SETLK)
588 #if     (defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV)) && !defined(AFS_SUN58_ENV)
589          || (acmd == F_RSETLK)
590 #endif
591         ) && code != LOCK_UN)
592         code |= LOCK_NB;        /* non-blocking, s.v.p. */
593 #if defined(AFS_DARWIN_ENV)
594     code = HandleFlock(avc, code, &treq, clid, 0 /*!onlymine */ );
595 #elif defined(AFS_SGI_ENV)
596     AFS_RWLOCK((vnode_t *) avc, VRWLOCK_WRITE);
597     code = HandleFlock(avc, code, &treq, clid, 0 /*!onlymine */ );
598     AFS_RWUNLOCK((vnode_t *) avc, VRWLOCK_WRITE);
599 #else
600     code = HandleFlock(avc, code, &treq, 0, 0 /*!onlymine */ );
601 #endif
602     code = afs_CheckCode(code, &treq, 3);       /* defeat AIX -O bug */
603     goto done;
604     }
605     code = EINVAL;
606 done:
607     afs_PutFakeStat(&fakestate);
608     AFS_DISCON_UNLOCK();
609     return code;
610 }
611
612
613 /*
614  * Get a description of the first lock which would
615  * block the lock specified.  If the specified lock
616  * would succeed, fill in the lock structure with 'F_UNLCK'.
617  *
618  * To do that, we have to ask the server for the lock
619  * count if:
620  *    1. The file is not locked by this machine.
621  *    2. Asking for write lock, and only the current
622  *       PID has the file read locked.
623  */
624 static int
625 HandleGetLock(register struct vcache *avc, register struct AFS_FLOCK *af,
626               register struct vrequest *areq, int clid)
627 {
628     register afs_int32 code;
629     struct AFS_FLOCK flock;
630
631     lockIdSet(&flock, NULL, clid);
632
633     ObtainWriteLock(&avc->lock, 122);
634     if (avc->flockCount == 0) {
635         /*
636          * We don't know ourselves, so ask the server. Unfortunately, we
637          * don't know the pid.  Not even the server knows the pid.  Besides,
638          * the process with the lock is on another machine
639          */
640         code = GetFlockCount(avc, areq);
641         if (code == 0 || (af->l_type == F_RDLCK && code > 0)) {
642             af->l_type = F_UNLCK;
643             goto unlck_leave;
644         }
645         if (code > 0)
646             af->l_type = F_RDLCK;
647         else
648             af->l_type = F_WRLCK;
649
650         af->l_pid = 0;
651 #if defined(AFS_HAVE_FLOCK_SYSID)
652         af->l_sysid = 0;
653 #endif
654         goto done;
655     }
656
657     if (af->l_type == F_RDLCK) {
658         /*
659          * We want a read lock.  If there are only
660          * read locks, or we are the one with the
661          * write lock, say it is unlocked.
662          */
663         if (avc->flockCount > 0 ||      /* only read locks */
664             !lockIdcmp2(&flock, avc, NULL, 1, clid)) {
665             af->l_type = F_UNLCK;
666             goto unlck_leave;
667         }
668
669         /* one write lock, but who? */
670         af->l_type = F_WRLCK;   /* not us, so lock would block */
671         if (avc->slocks) {      /* we know who, so tell */
672             af->l_pid = avc->slocks->pid;
673 #if defined(AFS_HAVE_FLOCK_SYSID)
674             af->l_sysid = avc->slocks->sysid;
675 #endif
676         } else {
677             af->l_pid = 0;      /* XXX can't happen?? */
678 #if defined(AFS_HAVE_FLOCK_SYSID)
679             af->l_sysid = 0;
680 #endif
681         }
682         goto done;
683     }
684
685     /*
686      * Ok, we want a write lock.  If there is a write lock
687      * already, and it is not this process, we fail.
688      */
689     if (avc->flockCount < 0) {
690         if (lockIdcmp2(&flock, avc, NULL, 1, clid)) {
691             af->l_type = F_WRLCK;
692             if (avc->slocks) {
693                 af->l_pid = avc->slocks->pid;
694 #if defined(AFS_HAVE_FLOCK_SYSID)
695                 af->l_sysid = avc->slocks->sysid;
696 #endif
697             } else {
698                 af->l_pid = 0;  /* XXX can't happen?? */
699 #if defined(AFS_HAVE_FLOCK_SYSID)
700                 af->l_sysid = 0;
701 #endif
702             }
703             goto done;
704         }
705         /* we are the one with the write lock */
706         af->l_type = F_UNLCK;
707         goto unlck_leave;
708     }
709
710     /*
711      * Want a write lock, and we know there are read locks.
712      * If there is more than one, or it isn't us, we cannot lock.
713      */
714     if ((avc->flockCount > 1)
715         || lockIdcmp2(&flock, avc, NULL, 1, clid)) {
716         struct SimpleLocks *slp;
717
718         af->l_type = F_RDLCK;
719         af->l_pid = 0;
720 #if defined(AFS_HAVE_FLOCK_SYSID)
721         af->l_sysid = 0;
722 #endif
723         /* find a pid that isn't our own */
724         for (slp = avc->slocks; slp; slp = slp->next) {
725             if (lockIdcmp2(&flock, NULL, slp, 1, clid)) {
726                 af->l_pid = slp->pid;
727 #if defined(AFS_HAVE_FLOCK_SYSID)
728                 af->l_sysid = avc->slocks->sysid;
729 #endif
730                 break;
731             }
732         }
733         goto done;
734     }
735
736     /*
737      * Ok, we want a write lock.  If there is a write lock
738      * already, and it is not this process, we fail.
739      */
740     if (avc->flockCount < 0) {
741         if (lockIdcmp2(&flock, avc, NULL, 1, clid)) {
742             af->l_type = F_WRLCK;
743             if (avc->slocks) {
744                 af->l_pid = avc->slocks->pid;
745 #if defined(AFS_HAVE_FLOCK_SYSID)
746                 af->l_sysid = avc->slocks->sysid;
747 #endif
748             } else {
749                 af->l_pid = 0;  /* XXX can't happen?? */
750 #if defined(AFS_HAVE_FLOCK_SYSID)
751                 af->l_sysid = 0;
752 #endif
753             }
754             goto done;
755         }
756         /* we are the one with the write lock */
757         af->l_type = F_UNLCK;
758         goto unlck_leave;
759     }
760
761     /*
762      * Want a write lock, and we know there are read locks.
763      * If there is more than one, or it isn't us, we cannot lock.
764      */
765     if ((avc->flockCount > 1)
766         || lockIdcmp2(&flock, avc, NULL, 1, clid)) {
767         struct SimpleLocks *slp;
768         af->l_type = F_RDLCK;
769         af->l_pid = 0;
770 #if defined(AFS_HAVE_FLOCK_SYSID)
771         af->l_sysid = 0;
772 #endif
773         /* find a pid that isn't our own */
774         for (slp = avc->slocks; slp; slp = slp->next) {
775             if (lockIdcmp2(&flock, NULL, slp, 1, clid)) {
776                 af->l_pid = slp->pid;
777 #if defined(AFS_HAVE_FLOCK_SYSID)
778                 af->l_sysid = avc->slocks->sysid;
779 #endif
780                 break;
781             }
782         }
783         goto done;
784     }
785
786     /*
787      * Want a write lock, and there is just one read lock, and it
788      * is this process with a read lock.  Ask the server if there
789      * are any more processes with the file locked.
790      */
791     code = GetFlockCount(avc, areq);
792     if (code == 0 || code == 1) {
793         af->l_type = F_UNLCK;
794         goto unlck_leave;
795     }
796     if (code > 0)
797         af->l_type = F_RDLCK;
798     else
799         af->l_type = F_WRLCK;
800     af->l_pid = 0;
801 #if defined(AFS_HAVE_FLOCK_SYSID)
802     af->l_sysid = 0;
803 #endif
804
805   done:
806     af->l_whence = 0;
807     af->l_start = 0;
808     af->l_len = 0;              /* to end of file */
809
810   unlck_leave:
811     ReleaseWriteLock(&avc->lock);
812     return 0;
813 }
814
815 /* Get the 'flock' count from the server.  This comes back in a 'spare'
816  * field from a GetStatus RPC.  If we have any problems with the RPC,
817  * we lie and say the file is unlocked.  If we ask any 'old' fileservers,
818  * the spare field will be a zero, saying the file is unlocked.  This is
819  * OK, as a further 'lock' request will do the right thing.
820  */
821 static int
822 GetFlockCount(struct vcache *avc, struct vrequest *areq)
823 {
824     register struct afs_conn *tc;
825     register afs_int32 code;
826     struct AFSFetchStatus OutStatus;
827     struct AFSCallBack CallBack;
828     struct AFSVolSync tsync;
829     int temp;
830     XSTATS_DECLS;
831     temp = areq->flags & O_NONBLOCK;
832     areq->flags |= O_NONBLOCK;
833
834     /* If we're disconnected, lie and say that we've got no locks. Ick */
835     if (AFS_IS_DISCONNECTED)
836         return 0;
837         
838     do {
839         tc = afs_Conn(&avc->f.fid, areq, SHARED_LOCK);
840         if (tc) {
841             XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_FETCHSTATUS);
842             RX_AFS_GUNLOCK();
843             code =
844                 RXAFS_FetchStatus(tc->id, (struct AFSFid *)&avc->f.fid.Fid,
845                                   &OutStatus, &CallBack, &tsync);
846             RX_AFS_GLOCK();
847             XSTATS_END_TIME;
848         } else
849             code = -1;
850     } while (afs_Analyze
851              (tc, code, &avc->f.fid, areq, AFS_STATS_FS_RPCIDX_FETCHSTATUS,
852               SHARED_LOCK, NULL));
853
854     if (temp)
855         areq->flags &= ~O_NONBLOCK;
856
857     if (code) {
858         return (0);             /* failed, say it is 'unlocked' */
859     } else {
860         return ((int)OutStatus.lockCount);
861     }
862 }
863