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