openbsd-20021120
[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 RCSID("$Header$");
19
20 #include "afs/sysincludes.h"    /* Standard vendor system headers */
21 #include "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"
26
27 /* Static prototypes */
28 static int HandleGetLock(register struct vcache *avc,
29         register struct AFS_FLOCK *af, register struct vrequest *areq, int clid);
30 static int GetFlockCount(struct vcache *avc, struct vrequest *areq);
31 static int lockIdcmp2(struct AFS_FLOCK *flock1, struct vcache *vp, 
32         register struct SimpleLocks *alp, int onlymine, int clid);
33 static void DoLockWarning(void);
34
35 /* int clid;  * non-zero on SGI, OSF, SunOS, Darwin, xBSD ** XXX ptr type */
36 void lockIdSet(struct AFS_FLOCK *flock, struct SimpleLocks *slp, int clid)
37 {
38 #if     defined(AFS_SUN5_ENV)
39     register proc_t *procp = ttoproc(curthread);    
40 #else
41 #if !defined(AFS_AIX41_ENV) && !defined(AFS_LINUX20_ENV) && !defined(AFS_SGI65_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_XBSD_ENV)
42 #ifdef AFS_SGI_ENV
43     struct proc *procp = OSI_GET_CURRENT_PROCP();
44 #else
45     struct proc *procp = u.u_procp;
46 #endif /* AFS_SGI_ENV */
47 #endif
48 #endif
49 #if defined(AFS_SGI65_ENV)
50     flid_t flid;
51     get_current_flid(&flid);
52 #endif
53
54     if (slp) {
55 #ifdef  AFS_AIX32_ENV
56 #ifdef  AFS_AIX41_ENV
57         slp->sysid = 0;
58         slp->pid = getpid();
59 #else
60         slp->sysid = u.u_sysid;
61         slp->pid = u.u_epid;
62 #endif
63 #else
64 #if     defined(AFS_AIX_ENV) || defined(AFS_SUN5_ENV)
65 #ifdef  AFS_SUN53_ENV
66         slp->sysid = 0;
67         slp->pid = procp->p_pid;
68 #else
69         slp->sysid = procp->p_sysid;
70         slp->pid = procp->p_epid;
71 #endif
72 #else
73 #if defined(AFS_SGI_ENV)
74 #ifdef AFS_SGI65_ENV
75         slp->sysid = flid.fl_sysid;
76 #else
77         slp->sysid = OSI_GET_CURRENT_SYSID();
78 #endif
79         slp->pid = clid;
80 #else
81 #if     defined(AFS_SUN_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
82         slp->pid = clid;
83 #else
84 #if defined(AFS_LINUX20_ENV) || defined(AFS_HPUX_ENV)
85         slp->pid = getpid();
86 #else
87         slp->pid  = u.u_procp->p_pid;
88 #endif
89 #endif
90 #endif /* AFS_AIX_ENV */
91 #endif /* AFS_AIX32_ENV */
92 #endif
93     } else {
94 #if     defined(AFS_AIX32_ENV)
95 #ifdef  AFS_AIX41_ENV
96         flock->l_sysid = 0;
97         flock->l_pid = getpid();
98 #else
99         flock->l_sysid = u.u_sysid;
100         flock->l_pid = u.u_epid;
101 #endif
102 #else
103 #if     defined(AFS_AIX_ENV)  || defined(AFS_SUN5_ENV)
104 #ifdef  AFS_SUN53_ENV
105         flock->l_sysid = 0;
106         flock->l_pid = procp->p_pid;
107 #else
108         flock->l_sysid = procp->p_sysid;
109         flock->l_pid = procp->p_epid;
110 #endif
111 #else
112 #if defined(AFS_SGI_ENV)
113 #ifdef AFS_SGI65_ENV
114         flock->l_sysid = flid.fl_sysid;
115 #else
116         flock->l_sysid = OSI_GET_CURRENT_SYSID();
117 #endif
118         flock->l_pid = clid;
119 #else
120 #if     defined(AFS_SUN_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
121         flock->l_pid = clid;
122 #else
123 #if defined(AFS_LINUX20_ENV) || defined(AFS_HPUX_ENV)
124         flock->l_pid = getpid();
125 #else
126         flock->l_pid = u.u_procp->p_pid;
127 #endif
128 #endif
129 #endif
130 #endif /* AFS_AIX_ENV */
131 #endif /* AFS_AIX32_ENV */
132     }   
133 }       
134
135 /* return 1 (true) if specified flock does not match alp (if 
136  * specified), or any of the slp structs (if alp == 0) 
137  */
138 /* I'm not sure that the comparsion of flock->pid to p_ppid
139  * is correct.  Should that be a comparision of alp (or slp) ->pid  
140  * to p_ppid?  Especially in the context of the lower loop, where
141  * the repeated comparison doesn't make much sense...
142  */
143 /* onlymine - don't match any locks which are held by my parent */
144 /* clid - only irix 6.5 */
145
146 static int lockIdcmp2(struct AFS_FLOCK *flock1, struct vcache *vp, 
147         register struct SimpleLocks *alp, int onlymine, int clid)
148 {
149     register struct SimpleLocks *slp;
150 #if     defined(AFS_SUN5_ENV)
151     register proc_t *procp = ttoproc(curthread);    
152 #else
153 #if !defined(AFS_AIX41_ENV) && !defined(AFS_LINUX20_ENV) && !defined(AFS_SGI65_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_XBSD_ENV)
154 #ifdef AFS_SGI64_ENV
155     struct proc *procp = curprocp;
156 #else /* AFS_SGI64_ENV */
157     struct proc *procp = u.u_procp;
158 #endif /* AFS_SGI64_ENV */
159 #endif
160 #endif
161
162     if (alp) {
163 #if     defined(AFS_AIX_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
164       if (flock1->l_sysid != alp->sysid) {
165         return 1;
166       }
167 #endif
168       if ((flock1->l_pid == alp->pid) || 
169 #if defined(AFS_AIX41_ENV) || defined(AFS_LINUX20_ENV) || defined(AFS_HPUX_ENV)
170           (!onlymine && (flock1->l_pid == getppid()))
171 #else
172 #if defined(AFS_SGI65_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
173           /* XXX check this. used to be *only* irix for some reason. */
174           (!onlymine && (flock1->l_pid == clid))
175 #else
176           (!onlymine && (flock1->l_pid == procp->p_ppid))
177 #endif
178 #endif
179           ) {
180         return 0;
181       }
182       return 1;
183     }
184
185     for (slp = vp->slocks; slp; slp = slp->next) {
186 #if     defined(AFS_AIX_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
187         if (flock1->l_sysid != slp->sysid) {
188           continue;
189         }
190 #endif
191         if (flock1->l_pid == slp->pid) {
192             return 0;
193           }
194     }
195     return (1);         /* failure */
196 }
197
198
199 /* we don't send multiple read flocks to the server, but rather just count
200     them up ourselves.  Of course, multiple write locks are incompatible.
201     
202     Note that we should always try to release a lock, even if we have
203     a network problem sending the release command through, since often
204     a lock is released on a close call, when the user can't retry anyway.
205     
206     After we remove it from our structure, the lock will no longer be
207     kept alive, and the server should time it out within a few minutes.
208     
209     94.04.13 add "force" parameter.  If a child explicitly unlocks a
210     file, I guess we'll permit it.  however, we don't want simple,
211     innocent closes by children to unlock files in the parent process.
212 */
213 /* clid - nonzero on sgi sunos osf1 only */
214 int HandleFlock(register struct vcache *avc, int acom, 
215         struct vrequest *areq, pid_t clid, int onlymine)
216 {
217     struct conn *tc;
218     struct SimpleLocks *slp, *tlp, **slpp;
219     afs_int32 code;
220     struct AFSVolSync tsync;
221     afs_int32 lockType;
222     struct AFS_FLOCK flock;
223     XSTATS_DECLS
224
225     AFS_STATCNT(HandleFlock);
226     code = 0;           /* default when we don't make any network calls */
227     lockIdSet(&flock, NULL, clid);
228
229 #if defined(AFS_SGI_ENV)
230     osi_Assert(valusema(&avc->vc_rwlock) <= 0);
231     osi_Assert(OSI_GET_LOCKID() == avc->vc_rwlockid);
232 #endif
233     ObtainWriteLock(&avc->lock,118);
234     if (acom & LOCK_UN) {
235
236 /* defect 3083 */
237
238 #ifdef AFS_AIX_ENV
239         /* If the lock is held exclusive, then only the owning process
240          * or a child can unlock it. Use pid and ppid because they are
241          * unique identifiers.
242          */
243         if ((avc->flockCount < 0) && (getpid() != avc->ownslock)) {
244 #ifdef  AFS_AIX41_ENV
245             if (onlymine || (getppid() != avc->ownslock)) {
246 #else
247             if (onlymine || (u.u_procp->p_ppid != avc->ownslock)) {
248 #endif
249                 ReleaseWriteLock(&avc->lock);
250                 return 0;
251             }
252         }
253 #endif
254         if (lockIdcmp2(&flock, avc, NULL, onlymine, clid)) {
255             ReleaseWriteLock(&avc->lock);           
256             return 0;
257         } 
258 #ifdef AFS_AIX_ENV
259         avc->ownslock = 0; 
260 #endif
261         if (avc->flockCount == 0) {         
262             ReleaseWriteLock(&avc->lock);
263             return 0            /*ENOTTY*/;
264             /* no lock held */
265         }       
266         /* unlock the lock */ 
267         if (avc->flockCount > 0) {
268             slpp = &avc->slocks; 
269             for (slp = *slpp; slp;) {
270                 if (!lockIdcmp2(&flock, avc, slp, onlymine, clid)) {
271                     avc->flockCount--;
272                     tlp = *slpp = slp->next;
273                     osi_FreeSmallSpace(slp);
274                     slp = tlp;
275                 } else {
276                     slpp = &slp->next;
277                     slp = *slpp;
278                 }
279             }
280         }
281         else if (avc->flockCount == -1) {
282             afs_StoreAllSegments(avc, areq, AFS_ASYNC); /* fsync file early */
283             avc->flockCount = 0; 
284             /* And remove the (only) exclusive lock entry from the list... */
285             osi_FreeSmallSpace(avc->slocks);
286             avc->slocks = 0;
287         }
288         if (avc->flockCount == 0) {
289             do {
290                 tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
291                 if (tc) {
292                     XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_RELEASELOCK);
293                     RX_AFS_GUNLOCK();
294                     code = RXAFS_ReleaseLock(tc->id, (struct AFSFid *)
295                                              &avc->fid.Fid, &tsync);
296                     RX_AFS_GLOCK();
297                     XSTATS_END_TIME;
298                 }
299                 else code = -1;
300             } while
301                 (afs_Analyze(tc, code, &avc->fid, areq, 
302                              AFS_STATS_FS_RPCIDX_RELEASELOCK,
303                              SHARED_LOCK, NULL));
304         }
305     }
306     else {
307         while (1) {         /* set a new lock */
308             /*
309              * Upgrading from shared locks to Exclusive and vice versa
310              * is a bit tricky and we don't really support it yet. But
311              * we try to support the common used one which is upgrade
312              * a shared lock to an exclusive for the same process...
313              */
314             if ((avc->flockCount > 0 && (acom & LOCK_EX)) || 
315                 (avc->flockCount == -1 && (acom & LOCK_SH))) {
316                 /*
317                  * Upgrading from shared locks to an exclusive one:
318                  * For now if all the shared locks belong to the
319                  * same process then we unlock them on the server
320                  * and proceed with the upgrade.  Unless we change the
321                  * server's locking interface impl we prohibit from
322                  * unlocking other processes's shared locks...
323                  * Upgrading from an exclusive lock to a shared one:
324                  * Again only allowed to be done by the same process.
325                  */
326                 slpp = &avc->slocks;
327                 for (slp = *slpp; slp;) {
328                     if (!lockIdcmp2(&flock, avc, slp, 1/*!onlymine*/, clid)) {
329                         if (acom & LOCK_EX)
330                             avc->flockCount--;
331                         else
332                             avc->flockCount = 0;
333                         tlp = *slpp = slp->next;
334                         osi_FreeSmallSpace(slp);
335                         slp = tlp;
336                     } else {
337                         code = EWOULDBLOCK;
338                         slpp = &slp->next;
339                         slp = *slpp;
340                     }
341                 }
342                if (!code && avc->flockCount == 0) {
343                     do {
344                         tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
345                         if (tc) {
346                           XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_RELEASELOCK);
347                           RX_AFS_GUNLOCK();
348                           code = RXAFS_ReleaseLock(tc->id,
349                                                    (struct AFSFid *) &avc->fid.Fid,
350                                                    &tsync);
351                           RX_AFS_GLOCK();
352                           XSTATS_END_TIME;
353                         }
354                         else code = -1;
355                     } while
356                       (afs_Analyze(tc, code, &avc->fid, areq,
357                                    AFS_STATS_FS_RPCIDX_RELEASELOCK,
358                                    SHARED_LOCK, NULL));
359                 }
360             } else if (avc->flockCount == -1 && (acom & LOCK_EX)) {
361                 if (lockIdcmp2(&flock, avc, NULL, 1, clid)) {
362                     code = EWOULDBLOCK;
363                 } else
364                     code = 0;
365             }
366             if (code == 0) {
367                 /* compatible here, decide if needs to go to file server.  If
368                    we've already got the file locked (and thus read-locked, since
369                    we've already checked for compatibility), we shouldn't send
370                    the call through to the server again */
371                 if (avc->flockCount == 0) {
372                     /* we're the first on our block, send the call through */
373                     lockType = ((acom & LOCK_EX)? LockWrite : LockRead);
374                     do {
375                         tc = afs_Conn(&avc->fid, areq, SHARED_LOCK);
376                         if (tc) {
377                           XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_SETLOCK);
378                           RX_AFS_GUNLOCK();
379                           code = RXAFS_SetLock(tc->id, (struct AFSFid *)
380                                               &avc->fid.Fid, lockType, &tsync);
381                           RX_AFS_GLOCK();
382                           XSTATS_END_TIME;
383                         }
384                         else code = -1;
385                     } while
386                         (afs_Analyze(tc, code, &avc->fid, areq,
387                                      AFS_STATS_FS_RPCIDX_SETLOCK,
388                                      SHARED_LOCK, NULL));
389                 }
390                 else code = 0;  /* otherwise, pretend things worked */
391             }
392             if (code == 0) {
393                 slp = (struct SimpleLocks *) osi_AllocSmallSpace(sizeof(struct SimpleLocks));
394                 if (acom & LOCK_EX) {
395
396 /* defect 3083 */
397
398 #ifdef AFS_AIX_ENV
399                   /* Record unique id of process owning exclusive lock. */
400                   avc->ownslock = getpid();
401 #endif
402
403                     slp->type = LockWrite;
404                     slp->next = NULL;               
405                     avc->slocks = slp;
406                     avc->flockCount = -1;
407                 } else {
408                     slp->type = LockRead;
409                     slp->next = avc->slocks;
410                     avc->slocks = slp;
411                     avc->flockCount++;
412                 }
413
414                 lockIdSet(&flock, slp, clid);
415                 break;
416             }
417             /* now, if we got EWOULDBLOCK, and we're supposed to wait, we do */
418             if(((code == EWOULDBLOCK)||(code == EAGAIN)) && !(acom & LOCK_NB)) {
419                 /* sleep for a second, allowing interrupts */
420                 ReleaseWriteLock(&avc->lock);
421 #if defined(AFS_SGI_ENV)
422                 AFS_RWUNLOCK((vnode_t *)avc, VRWLOCK_WRITE);
423 #endif
424                 code = afs_osi_Wait(1000, (struct afs_osi_WaitHandle *) 0, 1);
425 #if defined(AFS_SGI_ENV)
426                 AFS_RWLOCK((vnode_t *)avc, VRWLOCK_WRITE);
427 #endif
428                 ObtainWriteLock(&avc->lock,120);
429                 if (code) {
430                     code = EINTR;       /* return this if ^C typed */
431                     break;
432                 }
433             }
434             else break;
435         }       /* while loop */
436     }
437     ReleaseWriteLock(&avc->lock);
438     code = afs_CheckCode(code, areq, 1); /* defeat a buggy AIX optimization */
439     return code;
440 }
441
442
443 /* warn a user that a lock has been ignored */
444 afs_int32 lastWarnTime = 0; /* this is used elsewhere */
445 static void DoLockWarning(void)
446 {
447     register afs_int32 now;
448     now = osi_Time();
449
450     AFS_STATCNT(DoLockWarning);
451     /* check if we've already warned someone recently */
452     if (now < lastWarnTime + 120) return;
453
454     /* otherwise, it is time to nag the user */
455     lastWarnTime = now;
456     afs_warn("afs: byte-range lock/unlock ignored; make sure no one else is running this program.\n");
457 }
458
459
460 #ifdef  AFS_OSF_ENV
461 afs_lockctl(struct vcache *avc, struct eflock *af, int flag, 
462         struct AFS_UCRED *acred, pid_t clid, off_t offset)
463 #else
464 #if defined(AFS_SGI_ENV) || (defined(AFS_SUN_ENV) && !defined(AFS_SUN5_ENV)) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
465 afs_lockctl(struct vcache *avc, struct AFS_FLOCK *af, int acmd, struct AFS_UCRED *acred, pid_t clid)
466 #else
467 u_int clid=0;
468 afs_lockctl(struct vcache *avc, struct AFS_FLOCK *af, int acmd, struct AFS_UCRED *acred)
469 #endif
470 #endif
471 {
472     struct vrequest treq;
473     afs_int32 code;
474 #ifdef  AFS_OSF_ENV
475     int acmd = 0;
476 #endif
477     struct afs_fakestat_state fakestate;
478
479     AFS_STATCNT(afs_lockctl);
480     if ((code = afs_InitReq(&treq, acred))) return code;
481     afs_InitFakeStat(&fakestate);
482     code = afs_EvalFakeStat(&avc, &fakestate, &treq);
483     if (code) {
484         afs_PutFakeStat(&fakestate);
485         return code;
486     }
487 #ifdef  AFS_OSF_ENV
488     if (flag & VNOFLCK) {
489         afs_PutFakeStat(&fakestate);
490         return 0;
491     }
492     if (flag & CLNFLCK) {
493         acmd = LOCK_UN;
494     } else if ((flag & GETFLCK) || (flag & RGETFLCK)) {
495         acmd = F_GETLK;
496     } else if ((flag & SETFLCK) || (flag & RSETFLCK)) {
497         acmd = F_SETLK;
498     }
499 #endif
500 #if (defined(AFS_SUN_ENV) || defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV)) && !defined(AFS_SUN58_ENV)
501     if ((acmd == F_GETLK) || (acmd == F_RGETLK)) {
502 #else
503     if (acmd == F_GETLK) {
504 #endif
505         if (af->l_type == F_UNLCK) {
506             afs_PutFakeStat(&fakestate);
507             return 0;
508         }
509 #ifndef AFS_OSF_ENV     /* getlock is a no-op for osf (for now) */
510         code = HandleGetLock(avc, af, &treq, clid);
511 #endif
512         code = afs_CheckCode(code, &treq, 2); /* defeat buggy AIX optimz */
513         afs_PutFakeStat(&fakestate);
514         return code;
515     }
516     else if ((acmd == F_SETLK) || (acmd == F_SETLKW) 
517 #if (defined(AFS_SUN_ENV) || defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV)) && !defined(AFS_SUN58_ENV)
518              || (acmd == F_RSETLK)|| (acmd == F_RSETLKW)) {
519 #else
520         ) {
521 #endif
522         /* this next check is safer when left out, but more applications work
523            with it in.  However, they fail in race conditions.  The question is
524            what to do for people who don't have source to their application;
525            this way at least, they can get work done */
526 #ifdef AFS_LINUX24_ENV
527        if (af->l_len == OFFSET_MAX)
528            af->l_len = 0;      /* since some systems indicate it as EOF */
529 #else
530         if (af->l_len == 0x7fffffff)
531             af->l_len = 0;      /* since some systems indicate it as EOF */
532 #ifdef AFS_LINUX_64BIT_KERNEL
533         if (af->l_len == LONG_MAX)
534             af->l_len = 0;      /* since some systems indicate it as EOF */
535 #endif
536 #endif
537         /* next line makes byte range locks always succeed,
538            even when they should block */
539         if (af->l_whence != 0 || af->l_start != 0 || af->l_len != 0) {
540             DoLockWarning();
541             afs_PutFakeStat(&fakestate);
542             return 0;
543         }
544         /* otherwise we can turn this into a whole-file flock */
545         if (af->l_type == F_RDLCK) code = LOCK_SH;
546         else if (af->l_type == F_WRLCK) code = LOCK_EX;
547         else if (af->l_type == F_UNLCK) code = LOCK_UN;
548         else {
549             afs_PutFakeStat(&fakestate);
550             return EINVAL; /* unknown lock type */
551         }
552         if (((acmd == F_SETLK) 
553 #if     (defined(AFS_SGI_ENV) || defined(AFS_SUN_ENV)) && !defined(AFS_SUN58_ENV)
554         || (acmd == F_RSETLK) 
555 #endif
556         ) && code != LOCK_UN)
557             code |= LOCK_NB;    /* non-blocking, s.v.p. */
558 #if     defined(AFS_SUN_ENV) && !defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) 
559         code = HandleFlock(avc, code, &treq, clid, 0/*!onlymine*/);
560 #else
561 #if defined(AFS_SGI_ENV)
562         AFS_RWLOCK((vnode_t *)avc, VRWLOCK_WRITE);
563         code = HandleFlock(avc, code, &treq, clid, 0/*!onlymine*/);
564         AFS_RWUNLOCK((vnode_t *)avc, VRWLOCK_WRITE);
565 #else
566         code = HandleFlock(avc, code, &treq, 0, 0/*!onlymine*/);
567 #endif
568 #endif
569         code = afs_CheckCode(code, &treq, 3); /* defeat AIX -O bug */
570         afs_PutFakeStat(&fakestate);
571         return code;
572     }
573     afs_PutFakeStat(&fakestate);
574     return EINVAL;
575 }
576
577
578 /*
579  * Get a description of the first lock which would
580  * block the lock specified.  If the specified lock
581  * would succeed, fill in the lock structure with 'F_UNLCK'.
582  *
583  * To do that, we have to ask the server for the lock
584  * count if:
585  *    1. The file is not locked by this machine.
586  *    2. Asking for write lock, and only the current
587  *       PID has the file read locked.
588  */
589 #ifndef AFS_OSF_ENV     /* getlock is a no-op for osf (for now) */
590 static int HandleGetLock(register struct vcache *avc, 
591         register struct AFS_FLOCK *af, register struct vrequest *areq, int clid)
592 {
593     register afs_int32 code;
594     struct AFS_FLOCK flock;
595
596     lockIdSet(&flock, NULL, clid);
597
598     ObtainWriteLock(&avc->lock,122);
599     if (avc->flockCount == 0) {
600         /* We don't know ourselves, so ask the server. Unfortunately, we don't know the pid.
601          * Not even the server knows the pid.  Besides, the process with the lock is on another machine
602          */
603         code = GetFlockCount(avc, areq);
604         if (code == 0 || (af->l_type == F_RDLCK && code > 0)) {
605             af->l_type = F_UNLCK;
606             goto unlck_leave;
607         }
608         if (code > 0)
609             af->l_type = F_RDLCK;
610         else
611             af->l_type = F_WRLCK;
612
613         af->l_pid = 0;
614 #if     defined(AFS_AIX_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
615         af->l_sysid = 0;
616 #endif
617         goto done;
618     }
619
620     if (af->l_type == F_RDLCK) {
621         /*
622          * We want a read lock.  If there are only
623          * read locks, or we are the one with the
624          * write lock, say it is unlocked.
625          */
626         if (avc->flockCount > 0 ||      /* only read locks */
627             !lockIdcmp2(&flock, avc, NULL, 1, clid)) {
628             af->l_type = F_UNLCK;
629             goto unlck_leave;
630         }
631
632         /* one write lock, but who? */
633         af->l_type = F_WRLCK;           /* not us, so lock would block */
634         if (avc->slocks) {              /* we know who, so tell */
635             af->l_pid = avc->slocks->pid;
636 #if     defined(AFS_AIX_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
637             af->l_sysid = avc->slocks->sysid;
638 #endif
639         } else {
640             af->l_pid = 0;      /* XXX can't happen?? */
641 #if     defined(AFS_AIX_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
642             af->l_sysid = 0;
643 #endif
644         }
645         goto done;
646     }
647
648     /*
649      * Ok, we want a write lock.  If there is a write lock
650      * already, and it is not this process, we fail.
651      */
652     if (avc->flockCount < 0) {
653         if (lockIdcmp2(&flock, avc, NULL, 1, clid)) {
654             af->l_type = F_WRLCK;
655             if (avc->slocks) {
656                 af->l_pid = avc->slocks->pid;
657 #if     defined(AFS_AIX_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
658                 af->l_sysid = avc->slocks->sysid;
659 #endif
660             } else {
661                 af->l_pid = 0;  /* XXX can't happen?? */
662 #if     defined(AFS_AIX_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
663                 af->l_sysid = 0;
664 #endif
665             }
666             goto done;
667         }
668        /* we are the one with the write lock */
669         af->l_type = F_UNLCK;
670         goto unlck_leave;
671     }
672
673     /*
674      * Want a write lock, and we know there are read locks.
675      * If there is more than one, or it isn't us, we cannot lock.
676      */
677     if ((avc->flockCount > 1)
678         || lockIdcmp2(&flock, avc, NULL, 1, clid)) {
679         struct SimpleLocks *slp;
680         
681         af->l_type = F_RDLCK;
682         af->l_pid = 0;
683 #if     defined(AFS_AIX_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
684         af->l_sysid = 0;
685 #endif
686         /* find a pid that isn't our own */
687         for (slp = avc->slocks; slp; slp = slp->next) {
688            if (lockIdcmp2(&flock, NULL, slp, 1, clid)) {
689                af->l_pid = slp->pid;
690 #if     defined(AFS_AIX_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
691                af->l_sysid = avc->slocks->sysid;
692 #endif
693                 break;
694            } 
695        }
696         goto done;
697     }
698
699        /*
700         * Ok, we want a write lock.  If there is a write lock
701         * already, and it is not this process, we fail.
702         */
703         if (avc->flockCount < 0) {
704             if (lockIdcmp2(&flock, avc, NULL, 1, clid)) {
705                 af->l_type = F_WRLCK;
706                 if (avc->slocks) {
707                     af->l_pid = avc->slocks->pid;
708 #if     defined(AFS_AIX_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
709                     af->l_sysid = avc->slocks->sysid;
710 #endif
711                 } else {
712                     af->l_pid = 0;  /* XXX can't happen?? */
713 #if     defined(AFS_AIX_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
714                     af->l_sysid = 0;
715 #endif
716                 }
717                 goto done;
718             }
719             /* we are the one with the write lock */
720             af->l_type = F_UNLCK;
721             goto unlck_leave;
722         }
723
724         /*
725          * Want a write lock, and we know there are read locks.
726          * If there is more than one, or it isn't us, we cannot lock.
727          */
728         if ((avc->flockCount > 1)
729             || lockIdcmp2(&flock, avc, NULL, 1, clid)) {
730             struct SimpleLocks *slp;
731             af->l_type = F_RDLCK;
732             af->l_pid = 0;
733 #if     defined(AFS_AIX_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
734             af->l_sysid = 0;
735 #endif
736             /* find a pid that isn't our own */
737             for (slp = avc->slocks; slp; slp = slp->next) {
738                 if (lockIdcmp2(&flock, NULL, slp, 1, clid)) {
739                     af->l_pid = slp->pid;
740 #if     defined(AFS_AIX_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
741                     af->l_sysid = avc->slocks->sysid;
742 #endif
743                     break;
744                 }
745             }
746             goto done;
747         }
748         
749         /*
750          * Want a write lock, and there is just one read lock, and it
751          * is this process with a read lock.  Ask the server if there
752          * are any more processes with the file locked.
753          */
754         code = GetFlockCount(avc, areq);
755         if (code == 0 || code == 1) {
756             af->l_type = F_UNLCK;
757             goto unlck_leave;
758         }
759         if (code > 0)
760             af->l_type = F_RDLCK;
761         else
762             af->l_type = F_WRLCK;
763         af->l_pid = 0;
764 #if     defined(AFS_AIX_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
765         af->l_sysid = 0;
766 #endif
767
768 done:
769         af->l_whence = 0;
770         af->l_start = 0;
771         af->l_len = 0;    /* to end of file */
772
773 unlck_leave:
774         ReleaseWriteLock(&avc->lock);
775         return 0;
776 }
777
778 /* Get the 'flock' count from the server.  This comes back in a 'spare'
779  * field from a GetStatus RPC.  If we have any problems with the RPC,
780  * we lie and say the file is unlocked.  If we ask any 'old' fileservers,
781  * the spare field will be a zero, saying the file is unlocked.  This is
782  * OK, as a further 'lock' request will do the right thing.
783  */
784 static int GetFlockCount(struct vcache *avc, struct vrequest *areq)
785 {
786     register struct conn *tc;
787     register afs_int32 code;
788     struct AFSFetchStatus OutStatus;
789     struct AFSCallBack CallBack;
790     struct AFSVolSync tsync;
791     int temp;
792     XSTATS_DECLS
793
794     temp = areq->flags & O_NONBLOCK;
795     areq->flags |= O_NONBLOCK;
796
797     do {
798         tc = afs_Conn(&avc->fid, areq, SHARED_LOCK); 
799         if (tc){
800           XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_FETCHSTATUS);
801           RX_AFS_GUNLOCK();
802           code = RXAFS_FetchStatus(tc->id, (struct AFSFid *) &avc->fid.Fid,
803                                      &OutStatus, &CallBack, &tsync);
804           RX_AFS_GLOCK();
805           XSTATS_END_TIME;
806         } else code = -1;
807     } while
808       (afs_Analyze(tc, code, &avc->fid, areq,
809                    AFS_STATS_FS_RPCIDX_FETCHSTATUS,
810                    SHARED_LOCK, NULL));
811
812     if (temp)
813         areq->flags &= ~O_NONBLOCK;
814
815     if (code) {
816         return(0);              /* failed, say it is 'unlocked' */
817     } else {
818         return((int)OutStatus.lockCount);
819     }
820 }
821 #endif
822
823
824 #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_XBSD_ENV)
825 /* Flock not support on System V systems */
826 #ifdef AFS_OSF_ENV
827 extern struct fileops afs_fileops;
828
829 int afs_xflock (struct proc *p, void *args, int *retval) 
830 #else /* AFS_OSF_ENV */
831 int afs_xflock (void)
832 #endif
833 {
834     int code = 0;
835     struct a {
836         int fd;
837         int com;
838     } *uap;
839     struct file *fd;
840     struct vrequest treq;
841     struct vcache *tvc;
842     int flockDone;
843     struct afs_fakestat_state fakestate;
844
845     afs_InitFakeStat(&fakestate);
846     AFS_STATCNT(afs_xflock);
847     flockDone = 0;
848 #ifdef AFS_OSF_ENV
849     uap = (struct a *)args;
850     getf(&fd, uap->fd, FILE_FLAGS_NULL, &u.u_file_state);
851 #else /* AFS_OSF_ENV */
852     uap = (struct a *)u.u_ap;
853     fd = getf(uap->fd);
854 #endif
855     if (!fd) {
856         afs_PutFakeStat(&fakestate);
857         return;
858     }
859
860     if (flockDone = afs_InitReq(&treq, u.u_cred)) {
861         afs_PutFakeStat(&fakestate);
862         return flockDone;
863     }
864     /* first determine whether this is any sort of vnode */
865     if (fd->f_type == DTYPE_VNODE) {
866         /* good, this is a vnode; next see if it is an AFS vnode */
867         tvc = VTOAFS(fd->f_data);       /* valid, given a vnode */
868         if (IsAfsVnode(AFSTOV(tvc))) {
869             /* This is an AFS vnode, so do the work */
870 #ifdef AFS_DEC_ENV
871             /* find real vcache entry; shouldn't be null if gnode ref count
872              * is greater than 0.
873              */
874             tvc = VTOAFS(afs_gntovn)(tvc);
875             if (!tvc) {
876                 u.u_error = ENOENT;
877                 afs_PutFakeStat(&fakestate);
878                 return;
879             }
880 #endif
881             code = afs_EvalFakeStat(&tvc, &fakestate, &treq);
882             if (code) {
883                 afs_PutFakeStat(&fakestate);
884                 return code;
885             }
886             if ((fd->f_flag & (FEXLOCK | FSHLOCK)) && !(uap->com & LOCK_UN)) {
887                 /* First, if fd already has lock, release it for relock path */
888 #if defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || (defined(AFS_SUN_ENV) && !defined(AFS_SUN5_ENV))
889                 HandleFlock(tvc, LOCK_UN, &treq, u.u_procp->p_pid, 0/*!onlymine*/);
890 #else
891                 HandleFlock(tvc, LOCK_UN, &treq, 0, 0/*!onlymine*/);
892 #endif
893                 fd->f_flag &= ~(FEXLOCK | FSHLOCK);
894             }
895             /* now try the requested operation */
896
897 #if defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || (defined(AFS_SUN_ENV) && !defined(AFS_SUN5_ENV))
898             code = HandleFlock(tvc, uap->com, &treq,
899                                u.u_procp->p_pid, 0/*!onlymine*/);
900 #else
901             code = HandleFlock(tvc, uap->com, &treq, 0, 0/*!onlymine*/);
902 #endif
903 #ifndef AFS_OSF_ENV
904             u.u_error = code;
905 #endif
906
907             if (uap->com & LOCK_UN) {
908                 /* gave up lock */
909                 fd->f_flag &= ~(FEXLOCK | FSHLOCK);
910             }
911             else {
912 #ifdef AFS_OSF_ENV
913                 if (!code) {
914 #else /* AFS_OSF_ENV */
915                 if (!u.u_error) {
916 #endif
917                     if (uap->com & LOCK_SH) fd->f_flag |= FSHLOCK;
918                     else if (uap->com & LOCK_EX) fd->f_flag |= FEXLOCK;
919                 }
920             }
921             flockDone = 1;
922             fd->f_ops = &afs_fileops;
923         }
924     }
925 #ifdef  AFS_OSF_ENV
926     if (!flockDone)
927         code = flock(p, args, retval);
928 #ifdef  AFS_OSF30_ENV
929     FP_UNREF_ALWAYS(fd);
930 #else
931     FP_UNREF(fd);
932 #endif
933     afs_PutFakeStat(&fakestate);
934     return code;
935 #else   /* AFS_OSF_ENV */
936     if (!flockDone)
937 #ifdef DYNEL
938         (*afs_longcall_procs.LC_flock)();
939 #else
940         flock();
941 #endif
942     afs_PutFakeStat(&fakestate);
943     return;
944 #endif
945 }
946 #endif /* !defined(AFS_AIX_ENV) && !defined(AFS_HPUX_ENV) && !defined(AFS_SUN5_ENV) && !defined(UKERNEL)  && !defined(AFS_LINUX20_ENV) */
947