pull-prototypes-to-head-20020821
[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 "../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"
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_FBSD_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_FBSD_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_FBSD_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_FBSD_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_FBSD_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_FBSD_ENV)
465 afs_lockctl(struct vcache *avc, struct AFS_FLOCK *af, int acmd, struct AFS_UCRED *acred, pid_t clid)
466 pid_t clid;
467 #else
468 u_int clid=0;
469 afs_lockctl(struct vcache *avc, struct AFS_FLOCK *af, int acmd, struct AFS_UCRED *acred)
470 #endif
471 #endif
472 {
473     struct vrequest treq;
474     afs_int32 code;
475 #ifdef  AFS_OSF_ENV
476     int acmd = 0;
477 #endif
478     struct afs_fakestat_state fakestate;
479
480     AFS_STATCNT(afs_lockctl);
481     if ((code = afs_InitReq(&treq, acred))) return code;
482     afs_InitFakeStat(&fakestate);
483     code = afs_EvalFakeStat(&avc, &fakestate, &treq);
484     if (code) {
485         afs_PutFakeStat(&fakestate);
486         return code;
487     }
488 #ifdef  AFS_OSF_ENV
489     if (flag & VNOFLCK) {
490         afs_PutFakeStat(&fakestate);
491         return 0;
492     }
493     if (flag & CLNFLCK) {
494         acmd = LOCK_UN;
495     } else if ((flag & GETFLCK) || (flag & RGETFLCK)) {
496         acmd = F_GETLK;
497     } else if ((flag & SETFLCK) || (flag & RSETFLCK)) {
498         acmd = F_SETLK;
499     }
500 #endif
501 #if (defined(AFS_SUN_ENV) || defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV)) && !defined(AFS_SUN58_ENV)
502     if ((acmd == F_GETLK) || (acmd == F_RGETLK)) {
503 #else
504     if (acmd == F_GETLK) {
505 #endif
506         if (af->l_type == F_UNLCK) {
507             afs_PutFakeStat(&fakestate);
508             return 0;
509         }
510 #ifndef AFS_OSF_ENV     /* getlock is a no-op for osf (for now) */
511         code = HandleGetLock(avc, af, &treq, clid);
512 #endif
513         code = afs_CheckCode(code, &treq, 2); /* defeat buggy AIX optimz */
514         afs_PutFakeStat(&fakestate);
515         return code;
516     }
517     else if ((acmd == F_SETLK) || (acmd == F_SETLKW) 
518 #if (defined(AFS_SUN_ENV) || defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV)) && !defined(AFS_SUN58_ENV)
519              || (acmd == F_RSETLK)|| (acmd == F_RSETLKW)) {
520 #else
521         ) {
522 #endif
523         /* this next check is safer when left out, but more applications work
524            with it in.  However, they fail in race conditions.  The question is
525            what to do for people who don't have source to their application;
526            this way at least, they can get work done */
527 #ifdef AFS_LINUX24_ENV
528        if (af->l_len == OFFSET_MAX)
529            af->l_len = 0;      /* since some systems indicate it as EOF */
530 #else
531         if (af->l_len == 0x7fffffff)
532             af->l_len = 0;      /* since some systems indicate it as EOF */
533 #ifdef AFS_LINUX_64BIT_KERNEL
534         if (af->l_len == LONG_MAX)
535             af->l_len = 0;      /* since some systems indicate it as EOF */
536 #endif
537 #endif
538         /* next line makes byte range locks always succeed,
539            even when they should block */
540         if (af->l_whence != 0 || af->l_start != 0 || af->l_len != 0) {
541             DoLockWarning();
542             afs_PutFakeStat(&fakestate);
543             return 0;
544         }
545         /* otherwise we can turn this into a whole-file flock */
546         if (af->l_type == F_RDLCK) code = LOCK_SH;
547         else if (af->l_type == F_WRLCK) code = LOCK_EX;
548         else if (af->l_type == F_UNLCK) code = LOCK_UN;
549         else {
550             afs_PutFakeStat(&fakestate);
551             return EINVAL; /* unknown lock type */
552         }
553         if (((acmd == F_SETLK) 
554 #if     (defined(AFS_SGI_ENV) || defined(AFS_SUN_ENV)) && !defined(AFS_SUN58_ENV)
555         || (acmd == F_RSETLK) 
556 #endif
557         ) && code != LOCK_UN)
558             code |= LOCK_NB;    /* non-blocking, s.v.p. */
559 #if     defined(AFS_SUN_ENV) && !defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV) 
560         code = HandleFlock(avc, code, &treq, clid, 0/*!onlymine*/);
561 #else
562 #if defined(AFS_SGI_ENV)
563         AFS_RWLOCK((vnode_t *)avc, VRWLOCK_WRITE);
564         code = HandleFlock(avc, code, &treq, clid, 0/*!onlymine*/);
565         AFS_RWUNLOCK((vnode_t *)avc, VRWLOCK_WRITE);
566 #else
567         code = HandleFlock(avc, code, &treq, 0, 0/*!onlymine*/);
568 #endif
569 #endif
570         code = afs_CheckCode(code, &treq, 3); /* defeat AIX -O bug */
571         afs_PutFakeStat(&fakestate);
572         return code;
573     }
574     afs_PutFakeStat(&fakestate);
575     return EINVAL;
576 }
577
578
579 /*
580  * Get a description of the first lock which would
581  * block the lock specified.  If the specified lock
582  * would succeed, fill in the lock structure with 'F_UNLCK'.
583  *
584  * To do that, we have to ask the server for the lock
585  * count if:
586  *    1. The file is not locked by this machine.
587  *    2. Asking for write lock, and only the current
588  *       PID has the file read locked.
589  */
590 #ifndef AFS_OSF_ENV     /* getlock is a no-op for osf (for now) */
591 static int HandleGetLock(register struct vcache *avc, 
592         register struct AFS_FLOCK *af, register struct vrequest *areq, int clid)
593 {
594     register afs_int32 code;
595     struct AFS_FLOCK flock;
596
597     lockIdSet(&flock, NULL, clid);
598
599     ObtainWriteLock(&avc->lock,122);
600     if (avc->flockCount == 0) {
601         /* We don't know ourselves, so ask the server. Unfortunately, we don't know the pid.
602          * Not even the server knows the pid.  Besides, the process with the lock is on another machine
603          */
604         code = GetFlockCount(avc, areq);
605         if (code == 0 || (af->l_type == F_RDLCK && code > 0)) {
606             af->l_type = F_UNLCK;
607             goto unlck_leave;
608         }
609         if (code > 0)
610             af->l_type = F_RDLCK;
611         else
612             af->l_type = F_WRLCK;
613
614         af->l_pid = 0;
615 #if     defined(AFS_AIX_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
616         af->l_sysid = 0;
617 #endif
618         goto done;
619     }
620
621     if (af->l_type == F_RDLCK) {
622         /*
623          * We want a read lock.  If there are only
624          * read locks, or we are the one with the
625          * write lock, say it is unlocked.
626          */
627         if (avc->flockCount > 0 ||      /* only read locks */
628             !lockIdcmp2(&flock, avc, NULL, 1, clid)) {
629             af->l_type = F_UNLCK;
630             goto unlck_leave;
631         }
632
633         /* one write lock, but who? */
634         af->l_type = F_WRLCK;           /* not us, so lock would block */
635         if (avc->slocks) {              /* we know who, so tell */
636             af->l_pid = avc->slocks->pid;
637 #if     defined(AFS_AIX_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
638             af->l_sysid = avc->slocks->sysid;
639 #endif
640         } else {
641             af->l_pid = 0;      /* XXX can't happen?? */
642 #if     defined(AFS_AIX_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
643             af->l_sysid = 0;
644 #endif
645         }
646         goto done;
647     }
648
649     /*
650      * Ok, we want a write lock.  If there is a write lock
651      * already, and it is not this process, we fail.
652      */
653     if (avc->flockCount < 0) {
654         if (lockIdcmp2(&flock, avc, NULL, 1, clid)) {
655             af->l_type = F_WRLCK;
656             if (avc->slocks) {
657                 af->l_pid = avc->slocks->pid;
658 #if     defined(AFS_AIX_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
659                 af->l_sysid = avc->slocks->sysid;
660 #endif
661             } else {
662                 af->l_pid = 0;  /* XXX can't happen?? */
663 #if     defined(AFS_AIX_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
664                 af->l_sysid = 0;
665 #endif
666             }
667             goto done;
668         }
669        /* we are the one with the write lock */
670         af->l_type = F_UNLCK;
671         goto unlck_leave;
672     }
673
674     /*
675      * Want a write lock, and we know there are read locks.
676      * If there is more than one, or it isn't us, we cannot lock.
677      */
678     if ((avc->flockCount > 1)
679         || lockIdcmp2(&flock, avc, NULL, 1, clid)) {
680         struct SimpleLocks *slp;
681         
682         af->l_type = F_RDLCK;
683         af->l_pid = 0;
684 #if     defined(AFS_AIX_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
685         af->l_sysid = 0;
686 #endif
687         /* find a pid that isn't our own */
688         for (slp = avc->slocks; slp; slp = slp->next) {
689            if (lockIdcmp2(&flock, NULL, slp, 1, clid)) {
690                af->l_pid = slp->pid;
691 #if     defined(AFS_AIX_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
692                af->l_sysid = avc->slocks->sysid;
693 #endif
694                 break;
695            } 
696        }
697         goto done;
698     }
699
700        /*
701         * Ok, we want a write lock.  If there is a write lock
702         * already, and it is not this process, we fail.
703         */
704         if (avc->flockCount < 0) {
705             if (lockIdcmp2(&flock, avc, NULL, 1, clid)) {
706                 af->l_type = F_WRLCK;
707                 if (avc->slocks) {
708                     af->l_pid = avc->slocks->pid;
709 #if     defined(AFS_AIX_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
710                     af->l_sysid = avc->slocks->sysid;
711 #endif
712                 } else {
713                     af->l_pid = 0;  /* XXX can't happen?? */
714 #if     defined(AFS_AIX_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
715                     af->l_sysid = 0;
716 #endif
717                 }
718                 goto done;
719             }
720             /* we are the one with the write lock */
721             af->l_type = F_UNLCK;
722             goto unlck_leave;
723         }
724
725         /*
726          * Want a write lock, and we know there are read locks.
727          * If there is more than one, or it isn't us, we cannot lock.
728          */
729         if ((avc->flockCount > 1)
730             || lockIdcmp2(&flock, avc, NULL, 1, clid)) {
731             struct SimpleLocks *slp;
732             af->l_type = F_RDLCK;
733             af->l_pid = 0;
734 #if     defined(AFS_AIX_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
735             af->l_sysid = 0;
736 #endif
737             /* find a pid that isn't our own */
738             for (slp = avc->slocks; slp; slp = slp->next) {
739                 if (lockIdcmp2(&flock, NULL, slp, 1, clid)) {
740                     af->l_pid = slp->pid;
741 #if     defined(AFS_AIX_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
742                     af->l_sysid = avc->slocks->sysid;
743 #endif
744                     break;
745                 }
746             }
747             goto done;
748         }
749         
750         /*
751          * Want a write lock, and there is just one read lock, and it
752          * is this process with a read lock.  Ask the server if there
753          * are any more processes with the file locked.
754          */
755         code = GetFlockCount(avc, areq);
756         if (code == 0 || code == 1) {
757             af->l_type = F_UNLCK;
758             goto unlck_leave;
759         }
760         if (code > 0)
761             af->l_type = F_RDLCK;
762         else
763             af->l_type = F_WRLCK;
764         af->l_pid = 0;
765 #if     defined(AFS_AIX_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
766         af->l_sysid = 0;
767 #endif
768
769 done:
770         af->l_whence = 0;
771         af->l_start = 0;
772         af->l_len = 0;    /* to end of file */
773
774 unlck_leave:
775         ReleaseWriteLock(&avc->lock);
776         return 0;
777 }
778
779 /* Get the 'flock' count from the server.  This comes back in a 'spare'
780  * field from a GetStatus RPC.  If we have any problems with the RPC,
781  * we lie and say the file is unlocked.  If we ask any 'old' fileservers,
782  * the spare field will be a zero, saying the file is unlocked.  This is
783  * OK, as a further 'lock' request will do the right thing.
784  */
785 static int GetFlockCount(struct vcache *avc, struct vrequest *areq)
786 {
787     register struct conn *tc;
788     register afs_int32 code;
789     struct AFSFetchStatus OutStatus;
790     struct AFSCallBack CallBack;
791     struct AFSVolSync tsync;
792     int temp;
793     XSTATS_DECLS
794
795     temp = areq->flags & O_NONBLOCK;
796     areq->flags |= O_NONBLOCK;
797
798     do {
799         tc = afs_Conn(&avc->fid, areq, SHARED_LOCK); 
800         if (tc){
801           XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_FETCHSTATUS);
802           RX_AFS_GUNLOCK();
803           code = RXAFS_FetchStatus(tc->id, (struct AFSFid *) &avc->fid.Fid,
804                                      &OutStatus, &CallBack, &tsync);
805           RX_AFS_GLOCK();
806           XSTATS_END_TIME;
807         } else code = -1;
808     } while
809       (afs_Analyze(tc, code, &avc->fid, areq,
810                    AFS_STATS_FS_RPCIDX_FETCHSTATUS,
811                    SHARED_LOCK, NULL));
812
813     if (temp)
814         areq->flags &= ~O_NONBLOCK;
815
816     if (code) {
817         return(0);              /* failed, say it is 'unlocked' */
818     } else {
819         return((int)OutStatus.lockCount);
820     }
821 }
822 #endif
823
824
825 #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)
826 /* Flock not support on System V systems */
827 #ifdef AFS_OSF_ENV
828 extern struct fileops afs_fileops;
829
830 int afs_xflock (struct proc *p, void *args, int *retval) 
831 #else /* AFS_OSF_ENV */
832 int afs_xflock (void)
833 #endif
834 {
835     int code = 0;
836     struct a {
837         int fd;
838         int com;
839     } *uap;
840     struct file *fd;
841     struct vrequest treq;
842     struct vcache *tvc;
843     int flockDone;
844     struct afs_fakestat_state fakestate;
845
846     afs_InitFakeStat(&fakestate);
847     AFS_STATCNT(afs_xflock);
848     flockDone = 0;
849 #ifdef AFS_OSF_ENV
850     uap = (struct a *)args;
851     getf(&fd, uap->fd, FILE_FLAGS_NULL, &u.u_file_state);
852 #else /* AFS_OSF_ENV */
853     uap = (struct a *)u.u_ap;
854     fd = getf(uap->fd);
855 #endif
856     if (!fd) {
857         afs_PutFakeStat(&fakestate);
858         return;
859     }
860
861     if (flockDone = afs_InitReq(&treq, u.u_cred)) {
862         afs_PutFakeStat(&fakestate);
863         return flockDone;
864     }
865     /* first determine whether this is any sort of vnode */
866     if (fd->f_type == DTYPE_VNODE) {
867         /* good, this is a vnode; next see if it is an AFS vnode */
868         tvc = VTOAFS(fd->f_data);       /* valid, given a vnode */
869         if (IsAfsVnode(AFSTOV(tvc))) {
870             /* This is an AFS vnode, so do the work */
871 #ifdef AFS_DEC_ENV
872             /* find real vcache entry; shouldn't be null if gnode ref count
873              * is greater than 0.
874              */
875             tvc = VTOAFS(afs_gntovn)(tvc);
876             if (!tvc) {
877                 u.u_error = ENOENT;
878                 afs_PutFakeStat(&fakestate);
879                 return;
880             }
881 #endif
882             code = afs_EvalFakeStat(&tvc, &fakestate, &treq);
883             if (code) {
884                 afs_PutFakeStat(&fakestate);
885                 return code;
886             }
887             if ((fd->f_flag & (FEXLOCK | FSHLOCK)) && !(uap->com & LOCK_UN)) {
888                 /* First, if fd already has lock, release it for relock path */
889 #if defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || (defined(AFS_SUN_ENV) && !defined(AFS_SUN5_ENV))
890                 HandleFlock(tvc, LOCK_UN, &treq, u.u_procp->p_pid, 0/*!onlymine*/);
891 #else
892                 HandleFlock(tvc, LOCK_UN, &treq, 0, 0/*!onlymine*/);
893 #endif
894                 fd->f_flag &= ~(FEXLOCK | FSHLOCK);
895             }
896             /* now try the requested operation */
897
898 #if defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || (defined(AFS_SUN_ENV) && !defined(AFS_SUN5_ENV))
899             code = HandleFlock(tvc, uap->com, &treq,
900                                u.u_procp->p_pid, 0/*!onlymine*/);
901 #else
902             code = HandleFlock(tvc, uap->com, &treq, 0, 0/*!onlymine*/);
903 #endif
904 #ifndef AFS_OSF_ENV
905             u.u_error = code;
906 #endif
907
908             if (uap->com & LOCK_UN) {
909                 /* gave up lock */
910                 fd->f_flag &= ~(FEXLOCK | FSHLOCK);
911             }
912             else {
913 #ifdef AFS_OSF_ENV
914                 if (!code) {
915 #else /* AFS_OSF_ENV */
916                 if (!u.u_error) {
917 #endif
918                     if (uap->com & LOCK_SH) fd->f_flag |= FSHLOCK;
919                     else if (uap->com & LOCK_EX) fd->f_flag |= FEXLOCK;
920                 }
921             }
922             flockDone = 1;
923             fd->f_ops = &afs_fileops;
924         }
925     }
926 #ifdef  AFS_OSF_ENV
927     if (!flockDone)
928         code = flock(p, args, retval);
929 #ifdef  AFS_OSF30_ENV
930     FP_UNREF_ALWAYS(fd);
931 #else
932     FP_UNREF(fd);
933 #endif
934     afs_PutFakeStat(&fakestate);
935     return code;
936 #else   /* AFS_OSF_ENV */
937     if (!flockDone)
938 #ifdef DYNEL
939         (*afs_longcall_procs.LC_flock)();
940 #else
941         flock();
942 #endif
943     afs_PutFakeStat(&fakestate);
944     return;
945 #endif
946 }
947 #endif /* !defined(AFS_AIX_ENV) && !defined(AFS_HPUX_ENV) && !defined(AFS_SUN5_ENV) && !defined(UKERNEL)  && !defined(AFS_LINUX20_ENV) */
948