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