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