linux-pagelaunder-avoid-deadlock-20041012
[openafs.git] / src / afs / LINUX / osi_vnodeops.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  * Linux specific vnodeops. Also includes the glue routines required to call
12  * AFS vnodeops.
13  *
14  * So far the only truly scary part is that Linux relies on the inode cache
15  * to be up to date. Don't you dare break a callback and expect an fstat
16  * to give you meaningful information. This appears to be fixed in the 2.1
17  * development kernels. As it is we can fix this now by intercepting the 
18  * stat calls.
19  */
20
21 #include <afsconfig.h>
22 #include "afs/param.h"
23
24 RCSID
25     ("$Header$");
26
27 #include "afs/sysincludes.h"
28 #include "afsincludes.h"
29 #include "afs/afs_stats.h"
30 #include "afs/afs_osidnlc.h"
31 #include "h/mm.h"
32 #ifdef HAVE_MM_INLINE_H
33 #include "h/mm_inline.h"
34 #endif
35 #include "h/pagemap.h"
36 #if defined(AFS_LINUX24_ENV)
37 #include "h/smp_lock.h"
38 #endif
39
40 #ifdef pgoff2loff
41 #define pageoff(pp) pgoff2loff((pp)->index)
42 #else
43 #define pageoff(pp) pp->offset
44 #endif
45
46 #if defined(AFS_LINUX26_ENV)
47 #define UnlockPage(pp) unlock_page(pp)
48 #endif
49
50 extern struct vcache *afs_globalVp;
51 extern afs_rwlock_t afs_xvcache;
52
53 #if defined(AFS_LINUX24_ENV)
54 extern struct inode_operations afs_file_iops;
55 extern struct address_space_operations afs_file_aops;
56 struct address_space_operations afs_symlink_aops;
57 #endif
58 extern struct inode_operations afs_dir_iops;
59 extern struct inode_operations afs_symlink_iops;
60
61
62 static ssize_t
63 afs_linux_read(struct file *fp, char *buf, size_t count, loff_t * offp)
64 {
65     ssize_t code;
66     struct vcache *vcp = ITOAFS(fp->f_dentry->d_inode);
67     cred_t *credp = crref();
68     struct vrequest treq;
69
70     AFS_GLOCK();
71     afs_Trace4(afs_iclSetp, CM_TRACE_READOP, ICL_TYPE_POINTER, vcp,
72                ICL_TYPE_OFFSET, offp, ICL_TYPE_INT32, count, ICL_TYPE_INT32,
73                99999);
74
75     /* get a validated vcache entry */
76     code = afs_InitReq(&treq, credp);
77     if (!code)
78         code = afs_VerifyVCache(vcp, &treq);
79
80     if (code)
81         code = -code;
82     else {
83 #ifdef AFS_64BIT_CLIENT
84         if (*offp + count > afs_vmMappingEnd) {
85             uio_t tuio;
86             struct iovec iov;
87             afs_size_t oldOffset = *offp;
88             afs_int32 xfered = 0;
89
90             if (*offp < afs_vmMappingEnd) {
91                 /* special case of a buffer crossing the VM mapping end */
92                 afs_int32 tcount = afs_vmMappingEnd - *offp;
93                 count -= tcount;
94                 osi_FlushPages(vcp, credp);     /* ensure stale pages are gone */
95                 AFS_GUNLOCK();
96                 code = generic_file_read(fp, buf, tcount, offp);
97                 AFS_GLOCK();
98                 if (code != tcount) {
99                     goto done;
100                 }
101                 xfered = tcount;
102             }
103             setup_uio(&tuio, &iov, buf + xfered, (afs_offs_t) * offp, count,
104                       UIO_READ, AFS_UIOSYS);
105             code = afs_read(vcp, &tuio, credp, 0, 0, 0);
106             xfered += count - tuio.uio_resid;
107             if (code != 0) {
108                 afs_Trace4(afs_iclSetp, CM_TRACE_READOP, ICL_TYPE_POINTER,
109                            vcp, ICL_TYPE_OFFSET, offp, ICL_TYPE_INT32, -1,
110                            ICL_TYPE_INT32, code);
111                 code = xfered;
112                 *offp += count - tuio.uio_resid;
113             } else {
114                 code = xfered;
115                 *offp += count;
116             }
117           done:
118                 ;
119         } else {
120 #endif /* AFS_64BIT_CLIENT */
121             osi_FlushPages(vcp, credp); /* ensure stale pages are gone */
122             AFS_GUNLOCK();
123             code = generic_file_read(fp, buf, count, offp);
124             AFS_GLOCK();
125 #ifdef AFS_64BIT_CLIENT
126         }
127 #endif /* AFS_64BIT_CLIENT */
128     }
129
130     afs_Trace4(afs_iclSetp, CM_TRACE_READOP, ICL_TYPE_POINTER, vcp,
131                ICL_TYPE_OFFSET, offp, ICL_TYPE_INT32, count, ICL_TYPE_INT32,
132                code);
133
134     AFS_GUNLOCK();
135     crfree(credp);
136     return code;
137 }
138
139
140 /* Now we have integrated VM for writes as well as reads. generic_file_write
141  * also takes care of re-positioning the pointer if file is open in append
142  * mode. Call fake open/close to ensure we do writes of core dumps.
143  */
144 static ssize_t
145 afs_linux_write(struct file *fp, const char *buf, size_t count, loff_t * offp)
146 {
147     ssize_t code = 0;
148     int code2;
149     struct vcache *vcp = ITOAFS(fp->f_dentry->d_inode);
150     struct vrequest treq;
151     cred_t *credp = crref();
152     afs_offs_t toffs;
153
154     AFS_GLOCK();
155
156     afs_Trace4(afs_iclSetp, CM_TRACE_WRITEOP, ICL_TYPE_POINTER, vcp,
157                ICL_TYPE_OFFSET, offp, ICL_TYPE_INT32, count, ICL_TYPE_INT32,
158                (fp->f_flags & O_APPEND) ? 99998 : 99999);
159
160
161     /* get a validated vcache entry */
162     code = (ssize_t) afs_InitReq(&treq, credp);
163     if (!code)
164         code = (ssize_t) afs_VerifyVCache(vcp, &treq);
165
166     ObtainWriteLock(&vcp->lock, 529);
167     afs_FakeOpen(vcp);
168     ReleaseWriteLock(&vcp->lock);
169     if (code)
170         code = -code;
171     else {
172 #ifdef AFS_64BIT_CLIENT
173         toffs = *offp;
174         if (fp->f_flags & O_APPEND)
175             toffs += vcp->m.Length;
176         if (toffs + count > afs_vmMappingEnd) {
177             uio_t tuio;
178             struct iovec iov;
179             afs_size_t oldOffset = *offp;
180             afs_int32 xfered = 0;
181
182             if (toffs < afs_vmMappingEnd) {
183                 /* special case of a buffer crossing the VM mapping end */
184                 afs_int32 tcount = afs_vmMappingEnd - *offp;
185                 count -= tcount;
186                 AFS_GUNLOCK();
187                 code = generic_file_write(fp, buf, tcount, offp);
188                 AFS_GLOCK();
189                 if (code != tcount) {
190                     goto done;
191                 }
192                 xfered = tcount;
193                 toffs += tcount;
194             }
195             setup_uio(&tuio, &iov, buf + xfered, (afs_offs_t) toffs, count,
196                       UIO_WRITE, AFS_UIOSYS);
197             code = afs_write(vcp, &tuio, fp->f_flags, credp, 0);
198             xfered += count - tuio.uio_resid;
199             if (code != 0) {
200                 code = xfered;
201                 *offp += count - tuio.uio_resid;
202             } else {
203                 /* Purge dirty chunks of file if there are too many dirty chunks.
204                  * Inside the write loop, we only do this at a chunk boundary.
205                  * Clean up partial chunk if necessary at end of loop.
206                  */
207                 if (AFS_CHUNKBASE(tuio.afsio_offset) !=
208                     AFS_CHUNKBASE(oldOffset)) {
209                     ObtainWriteLock(&vcp->lock, 402);
210                     code = afs_DoPartialWrite(vcp, &treq);
211                     vcp->states |= CDirty;
212                     ReleaseWriteLock(&vcp->lock);
213                 }
214                 code = xfered;
215                 *offp += count;
216                 toffs += count;
217                 ObtainWriteLock(&vcp->lock, 400);
218                 vcp->m.Date = osi_Time();       /* Set file date (for ranlib) */
219                 /* extend file */
220                 if (!(fp->f_flags & O_APPEND) && toffs > vcp->m.Length) {
221                     vcp->m.Length = toffs;
222                 }
223                 ReleaseWriteLock(&vcp->lock);
224             }
225           done:
226                 ;
227         } else {
228 #endif /* AFS_64BIT_CLIENT */
229             AFS_GUNLOCK();
230             code = generic_file_write(fp, buf, count, offp);
231             AFS_GLOCK();
232 #ifdef AFS_64BIT_CLIENT
233         }
234 #endif /* AFS_64BIT_CLIENT */
235     }
236
237     ObtainWriteLock(&vcp->lock, 530);
238     vcp->m.Date = osi_Time();   /* set modification time */
239     afs_FakeClose(vcp, credp);
240     if (code >= 0)
241         code2 = afs_DoPartialWrite(vcp, &treq);
242     if (code2 && code >= 0)
243         code = (ssize_t) - code2;
244     ReleaseWriteLock(&vcp->lock);
245
246     afs_Trace4(afs_iclSetp, CM_TRACE_WRITEOP, ICL_TYPE_POINTER, vcp,
247                ICL_TYPE_OFFSET, offp, ICL_TYPE_INT32, count, ICL_TYPE_INT32,
248                code);
249
250     AFS_GUNLOCK();
251     crfree(credp);
252     return code;
253 }
254
255 /* This is a complete rewrite of afs_readdir, since we can make use of
256  * filldir instead of afs_readdir_move. Note that changes to vcache/dcache
257  * handling and use of bulkstats will need to be reflected here as well.
258  */
259 static int
260 afs_linux_readdir(struct file *fp, void *dirbuf, filldir_t filldir)
261 {
262     extern struct DirEntry *afs_dir_GetBlob();
263     struct vcache *avc = ITOAFS(FILE_INODE(fp));
264     struct vrequest treq;
265     register struct dcache *tdc;
266     int code;
267     int offset;
268     int dirpos;
269     struct DirEntry *de;
270     ino_t ino;
271     int len;
272     afs_size_t origOffset, tlen;
273     cred_t *credp = crref();
274     struct afs_fakestat_state fakestat;
275
276 #if defined(AFS_LINUX26_ENV)
277     lock_kernel();
278 #endif
279     AFS_GLOCK();
280     AFS_STATCNT(afs_readdir);
281
282     code = afs_InitReq(&treq, credp);
283     crfree(credp);
284     if (code)
285         goto out1;
286
287     afs_InitFakeStat(&fakestat);
288     code = afs_EvalFakeStat(&avc, &fakestat, &treq);
289     if (code)
290         goto out;
291
292     /* update the cache entry */
293   tagain:
294     code = afs_VerifyVCache(avc, &treq);
295     if (code)
296         goto out;
297
298     /* get a reference to the entire directory */
299     tdc = afs_GetDCache(avc, (afs_size_t) 0, &treq, &origOffset, &tlen, 1);
300     len = tlen;
301     if (!tdc) {
302         code = -ENOENT;
303         goto out;
304     }
305     ObtainReadLock(&avc->lock);
306     ObtainReadLock(&tdc->lock);
307     /*
308      * Make sure that the data in the cache is current. There are two
309      * cases we need to worry about:
310      * 1. The cache data is being fetched by another process.
311      * 2. The cache data is no longer valid
312      */
313     while ((avc->states & CStatd)
314            && (tdc->dflags & DFFetching)
315            && hsame(avc->m.DataVersion, tdc->f.versionNo)) {
316         ReleaseReadLock(&tdc->lock);
317         ReleaseReadLock(&avc->lock);
318         afs_osi_Sleep(&tdc->validPos);
319         ObtainReadLock(&avc->lock);
320         ObtainReadLock(&tdc->lock);
321     }
322     if (!(avc->states & CStatd)
323         || !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
324         ReleaseReadLock(&tdc->lock);
325         ReleaseReadLock(&avc->lock);
326         afs_PutDCache(tdc);
327         goto tagain;
328     }
329
330     /* Fill in until we get an error or we're done. This implementation
331      * takes an offset in units of blobs, rather than bytes.
332      */
333     code = 0;
334     offset = (int) fp->f_pos;
335     while (1) {
336         dirpos = BlobScan(&tdc->f, offset);
337         if (!dirpos)
338             break;
339
340         de = afs_dir_GetBlob(&tdc->f, dirpos);
341         if (!de)
342             break;
343
344         ino = (avc->fid.Fid.Volume << 16) + ntohl(de->fid.vnode);
345         ino &= 0x7fffffff;      /* Assumes 32 bit ino_t ..... */
346         if (de->name)
347             len = strlen(de->name);
348         else {
349             printf("afs_linux_readdir: afs_dir_GetBlob failed, null name (inode %x, dirpos %d)\n", 
350                    &tdc->f.inode, dirpos);
351             DRelease((struct buffer *) de, 0);
352             afs_PutDCache(tdc);
353             ReleaseReadLock(&avc->lock);
354             code = -ENOENT;
355             goto out;
356         }
357
358         /* filldir returns -EINVAL when the buffer is full. */
359 #if defined(AFS_LINUX26_ENV) || ((defined(AFS_LINUX24_ENV) || defined(pgoff2loff)) && defined(DECLARE_FSTYPE))
360         {
361             unsigned int type = DT_UNKNOWN;
362             struct VenusFid afid;
363             struct vcache *tvc;
364             int vtype;
365             afid.Cell = avc->fid.Cell;
366             afid.Fid.Volume = avc->fid.Fid.Volume;
367             afid.Fid.Vnode = ntohl(de->fid.vnode);
368             afid.Fid.Unique = ntohl(de->fid.vunique);
369             if ((avc->states & CForeign) == 0 && (ntohl(de->fid.vnode) & 1)) {
370                 type = DT_DIR;
371             } else if ((tvc = afs_FindVCache(&afid, 0, 0))) {
372                 if (tvc->mvstat) {
373                     type = DT_DIR;
374                 } else if (((tvc->states) & (CStatd | CTruth))) {
375                     /* CTruth will be set if the object has
376                      *ever* been statd */
377                     vtype = vType(tvc);
378                     if (vtype == VDIR)
379                         type = DT_DIR;
380                     else if (vtype == VREG)
381                         type = DT_REG;
382                     /* Don't do this until we're sure it can't be a mtpt */
383                     /* else if (vtype == VLNK)
384                      * type=DT_LNK; */
385                     /* what other types does AFS support? */
386                 }
387                 /* clean up from afs_FindVCache */
388                 afs_PutVCache(tvc);
389             }
390             code = (*filldir) (dirbuf, de->name, len, offset, ino, type);
391         }
392 #else
393         code = (*filldir) (dirbuf, de->name, len, offset, ino);
394 #endif
395         DRelease((struct buffer *)de, 0);
396         if (code)
397             break;
398         offset = dirpos + 1 + ((len + 16) >> 5);
399     }
400     /* If filldir didn't fill in the last one this is still pointing to that
401      * last attempt.
402      */
403     fp->f_pos = (loff_t) offset;
404
405     ReleaseReadLock(&tdc->lock);
406     afs_PutDCache(tdc);
407     ReleaseReadLock(&avc->lock);
408     code = 0;
409
410 out:
411     afs_PutFakeStat(&fakestat);
412 out1:
413     AFS_GUNLOCK();
414 #if defined(AFS_LINUX26_ENV)
415     unlock_kernel();
416 #endif
417     return code;
418 }
419
420
421 /* in afs_pioctl.c */
422 extern int afs_xioctl(struct inode *ip, struct file *fp, unsigned int com,
423                       unsigned long arg);
424
425
426 /* We need to detect unmap's after close. To do that, we need our own
427  * vm_operations_struct's. And we need to set them up for both the
428  * private and shared mappings. The fun part is that these are all static
429  * so we'll have to initialize on the fly!
430  */
431 static struct vm_operations_struct afs_private_mmap_ops;
432 static int afs_private_mmap_ops_inited = 0;
433 static struct vm_operations_struct afs_shared_mmap_ops;
434 static int afs_shared_mmap_ops_inited = 0;
435
436 void
437 afs_linux_vma_close(struct vm_area_struct *vmap)
438 {
439     struct vcache *vcp;
440     cred_t *credp;
441     int need_unlock = 0;
442
443     if (!vmap->vm_file)
444         return;
445
446     vcp = ITOAFS(FILE_INODE(vmap->vm_file));
447     if (!vcp)
448         return;
449
450     AFS_GLOCK();
451     afs_Trace4(afs_iclSetp, CM_TRACE_VM_CLOSE, ICL_TYPE_POINTER, vcp,
452                ICL_TYPE_INT32, vcp->mapcnt, ICL_TYPE_INT32, vcp->opens,
453                ICL_TYPE_INT32, vcp->execsOrWriters);
454     if ((&vcp->lock)->excl_locked == 0 || (&vcp->lock)->pid_writer == MyPidxx) {
455         ObtainWriteLock(&vcp->lock, 532);
456         need_unlock = 1;
457     } else
458         printk("AFS_VMA_CLOSE(%d): Skipping Already locked vcp=%p vmap=%p\n",
459                MyPidxx, &vcp, &vmap);
460     if (vcp->mapcnt) {
461         vcp->mapcnt--;
462         if (need_unlock)
463             ReleaseWriteLock(&vcp->lock);
464         if (!vcp->mapcnt) {
465             if (need_unlock && vcp->execsOrWriters < 2) {
466                 credp = crref();
467                 (void)afs_close(vcp, vmap->vm_file->f_flags, credp);
468                 /* only decrement the execsOrWriters flag if this is not a
469                  * writable file. */
470                 if (!(vcp->states & CRO) )
471                     if (! (vmap->vm_file->f_flags & (FWRITE | FTRUNC)))
472                         vcp->execsOrWriters--;
473                 vcp->states &= ~CMAPPED;
474                 crfree(credp);
475             } else if ((vmap->vm_file->f_flags & (FWRITE | FTRUNC)))
476                 vcp->execsOrWriters--;
477             /* If we did not have the lock */
478             if (!need_unlock) {
479                 vcp->mapcnt++;
480                 if (!vcp->execsOrWriters)
481                     vcp->execsOrWriters = 1;
482             }
483         }
484     } else {
485         if (need_unlock)
486             ReleaseWriteLock(&vcp->lock);
487     }
488
489   unlock_exit:
490     AFS_GUNLOCK();
491 }
492
493 static int
494 afs_linux_mmap(struct file *fp, struct vm_area_struct *vmap)
495 {
496     struct vcache *vcp = ITOAFS(FILE_INODE(fp));
497     cred_t *credp = crref();
498     struct vrequest treq;
499     int code;
500
501     AFS_GLOCK();
502 #if defined(AFS_LINUX24_ENV)
503     afs_Trace3(afs_iclSetp, CM_TRACE_GMAP, ICL_TYPE_POINTER, vcp,
504                ICL_TYPE_POINTER, vmap->vm_start, ICL_TYPE_INT32,
505                vmap->vm_end - vmap->vm_start);
506 #else
507     afs_Trace4(afs_iclSetp, CM_TRACE_GMAP, ICL_TYPE_POINTER, vcp,
508                ICL_TYPE_POINTER, vmap->vm_start, ICL_TYPE_INT32,
509                vmap->vm_end - vmap->vm_start, ICL_TYPE_INT32,
510                vmap->vm_offset);
511 #endif
512
513     /* get a validated vcache entry */
514     code = afs_InitReq(&treq, credp);
515     if (!code)
516         code = afs_VerifyVCache(vcp, &treq);
517
518
519     if (code)
520         code = -code;
521     else {
522         osi_FlushPages(vcp, credp);     /* ensure stale pages are gone */
523
524         AFS_GUNLOCK();
525         code = generic_file_mmap(fp, vmap);
526         AFS_GLOCK();
527     }
528
529     if (code == 0) {
530         ObtainWriteLock(&vcp->lock, 531);
531         /* Set out vma ops so we catch the close. The following test should be
532          * the same as used in generic_file_mmap.
533          */
534         if ((vmap->vm_flags & VM_SHARED) && (vmap->vm_flags & VM_MAYWRITE)) {
535             if (!afs_shared_mmap_ops_inited) {
536                 afs_shared_mmap_ops_inited = 1;
537                 afs_shared_mmap_ops = *vmap->vm_ops;
538                 afs_shared_mmap_ops.close = afs_linux_vma_close;
539             }
540             vmap->vm_ops = &afs_shared_mmap_ops;
541         } else {
542             if (!afs_private_mmap_ops_inited) {
543                 afs_private_mmap_ops_inited = 1;
544                 afs_private_mmap_ops = *vmap->vm_ops;
545                 afs_private_mmap_ops.close = afs_linux_vma_close;
546             }
547             vmap->vm_ops = &afs_private_mmap_ops;
548         }
549
550
551         /* Add an open reference on the first mapping. */
552         if (vcp->mapcnt == 0) {
553             if (!(vcp->states & CRO))
554                 vcp->execsOrWriters++;
555             vcp->opens++;
556             vcp->states |= CMAPPED;
557         }
558         ReleaseWriteLock(&vcp->lock);
559         vcp->mapcnt++;
560     }
561
562     AFS_GUNLOCK();
563     crfree(credp);
564     return code;
565 }
566
567 int
568 afs_linux_open(struct inode *ip, struct file *fp)
569 {
570     int code;
571     cred_t *credp = crref();
572
573 #ifdef AFS_LINUX24_ENV
574     lock_kernel();
575 #endif
576     AFS_GLOCK();
577     code = afs_open((struct vcache **)&ip, fp->f_flags, credp);
578     AFS_GUNLOCK();
579 #ifdef AFS_LINUX24_ENV
580     unlock_kernel();
581 #endif
582
583     crfree(credp);
584     return -code;
585 }
586
587 /* afs_Close is called from release, since release is used to handle all
588  * file closings. In addition afs_linux_flush is called from sys_close to
589  * handle flushing the data back to the server. The kicker is that we could
590  * ignore flush completely if only sys_close took it's return value from
591  * fput. See afs_linux_flush for notes on interactions between release and
592  * flush.
593  */
594 static int
595 afs_linux_release(struct inode *ip, struct file *fp)
596 {
597     int code = 0;
598     cred_t *credp = crref();
599     struct vcache *vcp = ITOAFS(ip);
600
601 #ifdef AFS_LINUX24_ENV
602     lock_kernel();
603 #endif
604     AFS_GLOCK();
605     if (vcp->flushcnt) {
606         vcp->flushcnt--;        /* protected by AFS global lock. */
607     } else {
608         code = afs_close(vcp, fp->f_flags, credp);
609     }
610     AFS_GUNLOCK();
611 #ifdef AFS_LINUX24_ENV
612     unlock_kernel();
613 #endif
614
615     crfree(credp);
616     return -code;
617 }
618
619 #if defined(AFS_LINUX24_ENV)
620 static int
621 afs_linux_fsync(struct file *fp, struct dentry *dp, int datasync)
622 #else
623 static int
624 afs_linux_fsync(struct file *fp, struct dentry *dp)
625 #endif
626 {
627     int code;
628     struct inode *ip = FILE_INODE(fp);
629     cred_t *credp = crref();
630
631 #ifdef AFS_LINUX24_ENV
632     lock_kernel();
633 #endif
634     AFS_GLOCK();
635     code = afs_fsync(ITOAFS(ip), credp);
636     AFS_GUNLOCK();
637 #ifdef AFS_LINUX24_ENV
638     unlock_kernel();
639 #endif
640     crfree(credp);
641     return -code;
642
643 }
644
645
646 static int
647 afs_linux_lock(struct file *fp, int cmd, struct file_lock *flp)
648 {
649     int code = 0;
650     struct vcache *vcp = ITOAFS(FILE_INODE(fp));
651     cred_t *credp = crref();
652     struct AFS_FLOCK flock;
653     /* Convert to a lock format afs_lockctl understands. */
654     memset((char *)&flock, 0, sizeof(flock));
655     flock.l_type = flp->fl_type;
656     flock.l_pid = flp->fl_pid;
657     flock.l_whence = 0;
658     flock.l_start = flp->fl_start;
659     flock.l_len = flp->fl_end - flp->fl_start;
660
661     /* Safe because there are no large files, yet */
662 #if defined(F_GETLK64) && (F_GETLK != F_GETLK64)
663     if (cmd == F_GETLK64)
664         cmd = F_GETLK;
665     else if (cmd == F_SETLK64)
666         cmd = F_SETLK;
667     else if (cmd == F_SETLKW64)
668         cmd = F_SETLKW;
669 #endif /* F_GETLK64 && F_GETLK != F_GETLK64 */
670
671     AFS_GLOCK();
672     code = afs_lockctl(vcp, &flock, cmd, credp);
673     AFS_GUNLOCK();
674
675     /* Convert flock back to Linux's file_lock */
676     flp->fl_type = flock.l_type;
677     flp->fl_pid = flock.l_pid;
678     flp->fl_start = flock.l_start;
679     flp->fl_end = flock.l_start + flock.l_len;
680
681     crfree(credp);
682     return -code;
683
684 }
685
686 /* afs_linux_flush
687  * flush is called from sys_close. We could ignore it, but sys_close return
688  * code comes from flush, not release. We need to use release to keep
689  * the vcache open count correct. Note that flush is called before release
690  * (via fput) in sys_close. vcp->flushcnt is a bit of ugliness to avoid
691  * races and also avoid calling afs_close twice when closing the file.
692  * If we merely checked for opens > 0 in afs_linux_release, then if an
693  * new open occurred when storing back the file, afs_linux_release would
694  * incorrectly close the file and decrement the opens count. Calling afs_close
695  * on the just flushed file is wasteful, since the background daemon will
696  * execute the code that finally decides there is nothing to do.
697  */
698 int
699 afs_linux_flush(struct file *fp)
700 {
701     struct vcache *vcp = ITOAFS(FILE_INODE(fp));
702     int code = 0;
703     cred_t *credp;
704
705     /* Only do this on the last close of the file pointer. */
706 #if defined(AFS_LINUX24_ENV)
707     if (atomic_read(&fp->f_count) > 1)
708 #else
709     if (fp->f_count > 1)
710 #endif
711         return 0;
712
713     credp = crref();
714
715     AFS_GLOCK();
716     code = afs_close(vcp, fp->f_flags, credp);
717     vcp->flushcnt++;            /* protected by AFS global lock. */
718     AFS_GUNLOCK();
719
720     crfree(credp);
721     return -code;
722 }
723
724 #if !defined(AFS_LINUX24_ENV)
725 /* Not allowed to directly read a directory. */
726 ssize_t
727 afs_linux_dir_read(struct file * fp, char *buf, size_t count, loff_t * ppos)
728 {
729     return -EISDIR;
730 }
731 #endif
732
733
734
735 struct file_operations afs_dir_fops = {
736 #if !defined(AFS_LINUX24_ENV)
737   .read =       afs_linux_dir_read,
738   .lock =       afs_linux_lock,
739   .fsync =      afs_linux_fsync,
740 #else
741   .read =       generic_read_dir,
742 #endif
743   .readdir =    afs_linux_readdir,
744   .ioctl =      afs_xioctl,
745   .open =       afs_linux_open,
746   .release =    afs_linux_release,
747 };
748
749 struct file_operations afs_file_fops = {
750   .read =       afs_linux_read,
751   .write =      afs_linux_write,
752   .ioctl =      afs_xioctl,
753   .mmap =       afs_linux_mmap,
754   .open =       afs_linux_open,
755   .flush =      afs_linux_flush,
756   .release =    afs_linux_release,
757   .fsync =      afs_linux_fsync,
758   .lock =       afs_linux_lock,
759 };
760
761
762 /**********************************************************************
763  * AFS Linux dentry operations
764  **********************************************************************/
765
766 /* afs_linux_revalidate
767  * Ensure vcache is stat'd before use. Return 0 if entry is valid.
768  */
769 static int
770 afs_linux_revalidate(struct dentry *dp)
771 {
772     int code;
773     cred_t *credp;
774     struct vrequest treq;
775     struct vcache *vcp = ITOAFS(dp->d_inode);
776     struct vcache *rootvp = NULL;
777
778 #ifdef AFS_LINUX24_ENV
779     lock_kernel();
780 #endif
781     AFS_GLOCK();
782
783     if (afs_fakestat_enable && vcp->mvstat == 1 && vcp->mvid
784         && (vcp->states & CMValid) && (vcp->states & CStatd)) {
785         ObtainSharedLock(&afs_xvcache, 680);
786         rootvp = afs_FindVCache(vcp->mvid, 0, 0);
787         ReleaseSharedLock(&afs_xvcache);
788     }
789
790     /* Make this a fast path (no crref), since it's called so often. */
791     if (vcp->states & CStatd) {
792         if (*dp->d_name.name != '/' && vcp->mvstat == 2)        /* root vnode */
793             check_bad_parent(dp);       /* check and correct mvid */
794         if (rootvp)
795             vcache2fakeinode(rootvp, vcp);
796         else
797             vcache2inode(vcp);
798         if (rootvp)
799             afs_PutVCache(rootvp);
800         AFS_GUNLOCK();
801 #ifdef AFS_LINUX24_ENV
802         unlock_kernel();
803 #endif
804         return 0;
805     }
806
807     credp = crref();
808     code = afs_InitReq(&treq, credp);
809     if (!code)
810         code = afs_VerifyVCache(vcp, &treq);
811
812     AFS_GUNLOCK();
813 #ifdef AFS_LINUX24_ENV
814     unlock_kernel();
815 #endif
816     crfree(credp);
817
818     return -code;
819 }
820
821 #if defined(AFS_LINUX26_ENV)
822 static int
823 afs_linux_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
824 {
825         int err = afs_linux_revalidate(dentry);
826         if (!err)
827                 generic_fillattr(dentry->d_inode, stat);
828         return err;
829 }
830 #endif
831
832 /* Validate a dentry. Return 1 if unchanged, 0 if VFS layer should re-evaluate.
833  * In kernels 2.2.10 and above, we are passed an additional flags var which
834  * may have either the LOOKUP_FOLLOW OR LOOKUP_DIRECTORY set in which case
835  * we are advised to follow the entry if it is a link or to make sure that 
836  * it is a directory. But since the kernel itself checks these possibilities
837  * later on, we shouldn't have to do it until later. Perhaps in the future..
838  */
839 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,10)
840 static int
841 afs_linux_dentry_revalidate(struct dentry *dp, int flags)
842 #else
843 static int
844 afs_linux_dentry_revalidate(struct dentry *dp)
845 #endif
846 {
847     char *name;
848     cred_t *credp = crref();
849     struct vrequest treq;
850     struct vcache *lookupvcp = NULL;
851     int code, bad_dentry = 1;
852     struct sysname_info sysState;
853     struct vcache *vcp, *parentvcp;
854
855     sysState.allocked = 0;
856
857 #ifdef AFS_LINUX24_ENV
858     lock_kernel();
859 #endif
860     AFS_GLOCK();
861
862     vcp = ITOAFS(dp->d_inode);
863     parentvcp = ITOAFS(dp->d_parent->d_inode);
864
865     /* If it's a negative dentry, then there's nothing to do. */
866     if (!vcp || !parentvcp)
867         goto done;
868
869     /* If it is the AFS root, then there's no chance it needs 
870      * revalidating */
871     if (vcp == afs_globalVp) {
872         bad_dentry = 0;
873         goto done;
874     }
875
876     if ((code = afs_InitReq(&treq, credp)))
877         goto done;
878
879     Check_AtSys(parentvcp, dp->d_name.name, &sysState, &treq);
880     name = sysState.name;
881
882     /* First try looking up the DNLC */
883     if ((lookupvcp = osi_dnlc_lookup(parentvcp, name, WRITE_LOCK))) {
884         /* Verify that the dentry does not point to an old inode */
885         if (vcp != lookupvcp)
886             goto done;
887         /* Check and correct mvid */
888         if (*name != '/' && vcp->mvstat == 2)
889             check_bad_parent(dp);
890         vcache2inode(vcp);
891         bad_dentry = 0;
892         goto done;
893     }
894
895     /* A DNLC lookup failure cannot be trusted. Try a real lookup. 
896        Make sure to try the real name and not the @sys expansion; 
897        afs_lookup will expand @sys itself. */
898   
899     code = afs_lookup(parentvcp, dp->d_name.name, &lookupvcp, credp);
900
901     /* Verify that the dentry does not point to an old inode */
902     if (vcp != lookupvcp)
903         goto done;
904
905     bad_dentry = 0;
906
907   done:
908     /* Clean up */
909     if (lookupvcp)
910         afs_PutVCache(lookupvcp);
911     if (sysState.allocked)
912         osi_FreeLargeSpace(name);
913
914     AFS_GUNLOCK();
915
916     if (bad_dentry) {
917         shrink_dcache_parent(dp);
918         d_drop(dp);
919     }
920
921 #ifdef AFS_LINUX24_ENV
922     unlock_kernel();
923 #endif
924     crfree(credp);
925
926     return !bad_dentry;
927 }
928
929 #if !defined(AFS_LINUX26_ENV)
930 /* afs_dentry_iput */
931 static void
932 afs_dentry_iput(struct dentry *dp, struct inode *ip)
933 {
934     int isglock;
935
936     if (ICL_SETACTIVE(afs_iclSetp)) {
937         isglock = ISAFS_GLOCK();
938         if (!isglock) AFS_GLOCK();
939         afs_Trace3(afs_iclSetp, CM_TRACE_DENTRYIPUT, ICL_TYPE_POINTER, ip,
940                    ICL_TYPE_STRING, dp->d_parent->d_name.name,
941                    ICL_TYPE_STRING, dp->d_name.name);
942         if (!isglock) AFS_GUNLOCK();
943     }
944
945     osi_iput(ip);
946 }
947 #endif
948
949 static int
950 afs_dentry_delete(struct dentry *dp)
951 {
952     int isglock;
953     if (ICL_SETACTIVE(afs_iclSetp)) {
954         isglock = ISAFS_GLOCK();
955         if (!isglock) AFS_GLOCK();
956         afs_Trace3(afs_iclSetp, CM_TRACE_DENTRYDELETE, ICL_TYPE_POINTER,
957                    dp->d_inode, ICL_TYPE_STRING, dp->d_parent->d_name.name,
958                    ICL_TYPE_STRING, dp->d_name.name);
959         if (!isglock) AFS_GUNLOCK();
960     }
961
962     if (dp->d_inode && (ITOAFS(dp->d_inode)->states & CUnlinked))
963         return 1;               /* bad inode? */
964
965     return 0;
966 }
967
968 struct dentry_operations afs_dentry_operations = {
969   .d_revalidate =       afs_linux_dentry_revalidate,
970   .d_delete =           afs_dentry_delete,
971 #if !defined(AFS_LINUX26_ENV)
972   .d_iput =             afs_dentry_iput,
973 #endif
974 };
975
976 /**********************************************************************
977  * AFS Linux inode operations
978  **********************************************************************/
979
980 /* afs_linux_create
981  *
982  * Merely need to set enough of vattr to get us through the create. Note
983  * that the higher level code (open_namei) will take care of any tuncation
984  * explicitly. Exclusive open is also taken care of in open_namei.
985  *
986  * name is in kernel space at this point.
987  */
988 int
989 afs_linux_create(struct inode *dip, struct dentry *dp, int mode)
990 {
991     int code;
992     cred_t *credp = crref();
993     struct vattr vattr;
994     enum vcexcl excl;
995     const char *name = dp->d_name.name;
996     struct inode *ip;
997
998     VATTR_NULL(&vattr);
999     vattr.va_mode = mode;
1000
1001 #if defined(AFS_LINUX26_ENV)
1002     lock_kernel();
1003 #endif
1004     AFS_GLOCK();
1005     code =
1006         afs_create(ITOAFS(dip), name, &vattr, NONEXCL, mode,
1007                    (struct vcache **)&ip, credp);
1008
1009     if (!code) {
1010         vattr2inode(ip, &vattr);
1011         /* Reset ops if symlink or directory. */
1012 #if defined(AFS_LINUX24_ENV)
1013         if (S_ISREG(ip->i_mode)) {
1014             ip->i_op = &afs_file_iops;
1015             ip->i_fop = &afs_file_fops;
1016             ip->i_data.a_ops = &afs_file_aops;
1017         } else if (S_ISDIR(ip->i_mode)) {
1018             ip->i_op = &afs_dir_iops;
1019             ip->i_fop = &afs_dir_fops;
1020         } else if (S_ISLNK(ip->i_mode)) {
1021             ip->i_op = &afs_symlink_iops;
1022             ip->i_data.a_ops = &afs_symlink_aops;
1023             ip->i_mapping = &ip->i_data;
1024         } else
1025             printk("afs_linux_create: FIXME\n");
1026 #else
1027         if (S_ISDIR(ip->i_mode))
1028             ip->i_op = &afs_dir_iops;
1029         else if (S_ISLNK(ip->i_mode))
1030             ip->i_op = &afs_symlink_iops;
1031 #endif
1032
1033         dp->d_op = &afs_dentry_operations;
1034         dp->d_time = jiffies;
1035         d_instantiate(dp, ip);
1036     }
1037
1038     AFS_GUNLOCK();
1039 #if defined(AFS_LINUX26_ENV)
1040     unlock_kernel();
1041 #endif
1042     crfree(credp);
1043     return -code;
1044 }
1045
1046 /* afs_linux_lookup */
1047 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,10)
1048 struct dentry *
1049 afs_linux_lookup(struct inode *dip, struct dentry *dp)
1050 #else
1051 int
1052 afs_linux_lookup(struct inode *dip, struct dentry *dp)
1053 #endif
1054 {
1055     int code = 0;
1056     cred_t *credp = crref();
1057     struct vcache *vcp = NULL;
1058     const char *comp = dp->d_name.name;
1059
1060 #if defined(AFS_LINUX26_ENV)
1061     lock_kernel();
1062 #endif
1063     AFS_GLOCK();
1064     code = afs_lookup(ITOAFS(dip), comp, &vcp, credp);
1065     AFS_GUNLOCK();
1066     
1067     if (vcp) {
1068         struct inode *ip = AFSTOI(vcp);
1069         /* Reset ops if symlink or directory. */
1070 #if defined(AFS_LINUX24_ENV)
1071         if (S_ISREG(ip->i_mode)) {
1072             ip->i_op = &afs_file_iops;
1073             ip->i_fop = &afs_file_fops;
1074             ip->i_data.a_ops = &afs_file_aops;
1075         } else if (S_ISDIR(ip->i_mode)) {
1076             ip->i_op = &afs_dir_iops;
1077             ip->i_fop = &afs_dir_fops;
1078         } else if (S_ISLNK(ip->i_mode)) {
1079             ip->i_op = &afs_symlink_iops;
1080             ip->i_data.a_ops = &afs_symlink_aops;
1081             ip->i_mapping = &ip->i_data;
1082         } else
1083             printk
1084                 ("afs_linux_lookup: ip->i_mode 0x%x  dp->d_name.name %s  code %d\n",
1085                  ip->i_mode, dp->d_name.name, code);
1086 #ifdef STRUCT_INODE_HAS_I_SECURITY
1087        if (ip->i_security == NULL) {
1088            if (security_inode_alloc(ip))
1089                panic("afs_linux_lookup: Cannot allocate inode security");
1090        }
1091 #endif
1092 #else
1093         if (S_ISDIR(ip->i_mode))
1094             ip->i_op = &afs_dir_iops;
1095         else if (S_ISLNK(ip->i_mode))
1096             ip->i_op = &afs_symlink_iops;
1097 #endif
1098     }
1099     dp->d_time = jiffies;
1100     dp->d_op = &afs_dentry_operations;
1101     d_add(dp, AFSTOI(vcp));
1102
1103 #if defined(AFS_LINUX26_ENV)
1104     unlock_kernel();
1105 #endif
1106     crfree(credp);
1107
1108     /* It's ok for the file to not be found. That's noted by the caller by
1109      * seeing that the dp->d_inode field is NULL.
1110      */
1111 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,10)
1112     if (code == ENOENT)
1113         return ERR_PTR(0);
1114     else
1115         return ERR_PTR(-code);
1116 #else
1117     if (code == ENOENT)
1118         code = 0;
1119     return -code;
1120 #endif
1121 }
1122
1123 int
1124 afs_linux_link(struct dentry *olddp, struct inode *dip, struct dentry *newdp)
1125 {
1126     int code;
1127     cred_t *credp = crref();
1128     const char *name = newdp->d_name.name;
1129     struct inode *oldip = olddp->d_inode;
1130
1131     /* If afs_link returned the vnode, we could instantiate the
1132      * dentry. Since it's not, we drop this one and do a new lookup.
1133      */
1134     d_drop(newdp);
1135
1136     AFS_GLOCK();
1137     code = afs_link(ITOAFS(oldip), ITOAFS(dip), name, credp);
1138
1139     AFS_GUNLOCK();
1140     crfree(credp);
1141     return -code;
1142 }
1143
1144 int
1145 afs_linux_unlink(struct inode *dip, struct dentry *dp)
1146 {
1147     int code;
1148     cred_t *credp = crref();
1149     const char *name = dp->d_name.name;
1150
1151 #if defined(AFS_LINUX26_ENV)
1152     lock_kernel();
1153 #endif
1154     AFS_GLOCK();
1155     code = afs_remove(ITOAFS(dip), name, credp);
1156     AFS_GUNLOCK();
1157     if (!code)
1158         d_drop(dp);
1159 #if defined(AFS_LINUX26_ENV)
1160     unlock_kernel();
1161 #endif
1162     crfree(credp);
1163     return -code;
1164 }
1165
1166
1167 int
1168 afs_linux_symlink(struct inode *dip, struct dentry *dp, const char *target)
1169 {
1170     int code;
1171     cred_t *credp = crref();
1172     struct vattr vattr;
1173     const char *name = dp->d_name.name;
1174
1175     /* If afs_symlink returned the vnode, we could instantiate the
1176      * dentry. Since it's not, we drop this one and do a new lookup.
1177      */
1178     d_drop(dp);
1179
1180     AFS_GLOCK();
1181     VATTR_NULL(&vattr);
1182     code = afs_symlink(ITOAFS(dip), name, &vattr, target, credp);
1183     AFS_GUNLOCK();
1184     crfree(credp);
1185     return -code;
1186 }
1187
1188 int
1189 afs_linux_mkdir(struct inode *dip, struct dentry *dp, int mode)
1190 {
1191     int code;
1192     cred_t *credp = crref();
1193     struct vcache *tvcp = NULL;
1194     struct vattr vattr;
1195     const char *name = dp->d_name.name;
1196
1197 #if defined(AFS_LINUX26_ENV)
1198     lock_kernel();
1199 #endif
1200     AFS_GLOCK();
1201     VATTR_NULL(&vattr);
1202     vattr.va_mask = ATTR_MODE;
1203     vattr.va_mode = mode;
1204     code = afs_mkdir(ITOAFS(dip), name, &vattr, &tvcp, credp);
1205     AFS_GUNLOCK();
1206
1207     if (tvcp) {
1208         tvcp->v.v_op = &afs_dir_iops;
1209 #if defined(AFS_LINUX24_ENV)
1210         tvcp->v.v_fop = &afs_dir_fops;
1211 #endif
1212         dp->d_op = &afs_dentry_operations;
1213         dp->d_time = jiffies;
1214         d_instantiate(dp, AFSTOI(tvcp));
1215     }
1216
1217 #if defined(AFS_LINUX26_ENV)
1218     unlock_kernel();
1219 #endif
1220     crfree(credp);
1221     return -code;
1222 }
1223
1224 int
1225 afs_linux_rmdir(struct inode *dip, struct dentry *dp)
1226 {
1227     int code;
1228     cred_t *credp = crref();
1229     const char *name = dp->d_name.name;
1230
1231 #if defined(AFS_LINUX26_ENV)
1232     lock_kernel();
1233 #endif
1234     AFS_GLOCK();
1235     code = afs_rmdir(ITOAFS(dip), name, credp);
1236     AFS_GUNLOCK();
1237
1238     /* Linux likes to see ENOTEMPTY returned from an rmdir() syscall
1239      * that failed because a directory is not empty. So, we map
1240      * EEXIST to ENOTEMPTY on linux.
1241      */
1242     if (code == EEXIST) {
1243         code = ENOTEMPTY;
1244     }
1245
1246     if (!code) {
1247         d_drop(dp);
1248     }
1249
1250 #if defined(AFS_LINUX26_ENV)
1251     unlock_kernel();
1252 #endif
1253     crfree(credp);
1254     return -code;
1255 }
1256
1257
1258
1259 int
1260 afs_linux_rename(struct inode *oldip, struct dentry *olddp,
1261                  struct inode *newip, struct dentry *newdp)
1262 {
1263     int code;
1264     cred_t *credp = crref();
1265     const char *oldname = olddp->d_name.name;
1266     const char *newname = newdp->d_name.name;
1267
1268 #if defined(AFS_LINUX26_ENV)
1269     lock_kernel();
1270 #endif
1271     /* Remove old and new entries from name hash. New one will change below.
1272      * While it's optimal to catch failures and re-insert newdp into hash,
1273      * it's also error prone and in that case we're already dealing with error
1274      * cases. Let another lookup put things right, if need be.
1275      */
1276 #if defined(AFS_LINUX26_ENV)
1277     if (!d_unhashed(olddp))
1278         d_drop(olddp);
1279     if (!d_unhashed(newdp))
1280         d_drop(newdp);
1281 #else
1282     if (!list_empty(&olddp->d_hash))
1283         d_drop(olddp);
1284     if (!list_empty(&newdp->d_hash))
1285         d_drop(newdp);
1286 #endif
1287     AFS_GLOCK();
1288     code = afs_rename(ITOAFS(oldip), oldname, ITOAFS(newip), newname, credp);
1289     AFS_GUNLOCK();
1290
1291     if (!code) {
1292         /* update time so it doesn't expire immediately */
1293         newdp->d_time = jiffies;
1294         d_move(olddp, newdp);
1295     }
1296
1297 #if defined(AFS_LINUX26_ENV)
1298     unlock_kernel();
1299 #endif
1300
1301     crfree(credp);
1302     return -code;
1303 }
1304
1305
1306 /* afs_linux_ireadlink 
1307  * Internal readlink which can return link contents to user or kernel space.
1308  * Note that the buffer is NOT supposed to be null-terminated.
1309  */
1310 static int
1311 afs_linux_ireadlink(struct inode *ip, char *target, int maxlen, uio_seg_t seg)
1312 {
1313     int code;
1314     cred_t *credp = crref();
1315     uio_t tuio;
1316     struct iovec iov;
1317
1318     setup_uio(&tuio, &iov, target, (afs_offs_t) 0, maxlen, UIO_READ, seg);
1319     code = afs_readlink(ITOAFS(ip), &tuio, credp);
1320     crfree(credp);
1321
1322     if (!code)
1323         return maxlen - tuio.uio_resid;
1324     else
1325         return -code;
1326 }
1327
1328 #if !defined(AFS_LINUX24_ENV)
1329 /* afs_linux_readlink 
1330  * Fill target (which is in user space) with contents of symlink.
1331  */
1332 int
1333 afs_linux_readlink(struct dentry *dp, char *target, int maxlen)
1334 {
1335     int code;
1336     struct inode *ip = dp->d_inode;
1337
1338     AFS_GLOCK();
1339     code = afs_linux_ireadlink(ip, target, maxlen, AFS_UIOUSER);
1340     AFS_GUNLOCK();
1341     return code;
1342 }
1343
1344
1345 /* afs_linux_follow_link
1346  * a file system dependent link following routine.
1347  */
1348 struct dentry *
1349 afs_linux_follow_link(struct dentry *dp, struct dentry *basep,
1350                       unsigned int follow)
1351 {
1352     int code = 0;
1353     char *name;
1354     struct dentry *res;
1355
1356
1357     AFS_GLOCK();
1358     name = osi_Alloc(PATH_MAX + 1);
1359     if (!name) {
1360         AFS_GUNLOCK();
1361         dput(basep);
1362         return ERR_PTR(-EIO);
1363     }
1364
1365     code = afs_linux_ireadlink(dp->d_inode, name, PATH_MAX, AFS_UIOSYS);
1366     AFS_GUNLOCK();
1367
1368     if (code < 0) {
1369         dput(basep);
1370         res = ERR_PTR(code);
1371     } else {
1372         name[code] = '\0';
1373         res = lookup_dentry(name, basep, follow);
1374     }
1375
1376     AFS_GLOCK();
1377     osi_Free(name, PATH_MAX + 1);
1378     AFS_GUNLOCK();
1379     return res;
1380 }
1381 #endif
1382
1383 /* afs_linux_readpage
1384  * all reads come through here. A strategy-like read call.
1385  */
1386 int
1387 afs_linux_readpage(struct file *fp, struct page *pp)
1388 {
1389     int code;
1390     cred_t *credp = crref();
1391 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
1392     char *address;
1393     afs_offs_t offset = pp->index << PAGE_CACHE_SHIFT;
1394 #else
1395     ulong address = afs_linux_page_address(pp);
1396     afs_offs_t offset = pageoff(pp);
1397 #endif
1398     uio_t tuio;
1399     struct iovec iovec;
1400     struct inode *ip = FILE_INODE(fp);
1401     int cnt = page_count(pp);
1402     struct vcache *avc = ITOAFS(ip);
1403
1404
1405 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
1406     address = kmap(pp);
1407     ClearPageError(pp);
1408 #else
1409     atomic_add(1, &pp->count);
1410     set_bit(PG_locked, &pp->flags);     /* other bits? See mm.h */
1411     clear_bit(PG_error, &pp->flags);
1412 #endif
1413
1414     setup_uio(&tuio, &iovec, (char *)address, offset, PAGESIZE, UIO_READ,
1415               AFS_UIOSYS);
1416 #ifdef AFS_LINUX24_ENV
1417     lock_kernel();
1418 #endif
1419     AFS_GLOCK();
1420     afs_Trace4(afs_iclSetp, CM_TRACE_READPAGE, ICL_TYPE_POINTER, ip, ICL_TYPE_POINTER, pp, ICL_TYPE_INT32, cnt, ICL_TYPE_INT32, 99999); /* not a possible code value */
1421     code = afs_rdwr(avc, &tuio, UIO_READ, 0, credp);
1422     afs_Trace4(afs_iclSetp, CM_TRACE_READPAGE, ICL_TYPE_POINTER, ip,
1423                ICL_TYPE_POINTER, pp, ICL_TYPE_INT32, cnt, ICL_TYPE_INT32,
1424                code);
1425     AFS_GUNLOCK();
1426 #ifdef AFS_LINUX24_ENV
1427     unlock_kernel();
1428 #endif
1429
1430     if (!code) {
1431         if (tuio.uio_resid)     /* zero remainder of page */
1432             memset((void *)(address + (PAGESIZE - tuio.uio_resid)), 0,
1433                    tuio.uio_resid);
1434 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
1435         flush_dcache_page(pp);
1436         SetPageUptodate(pp);
1437 #else
1438         set_bit(PG_uptodate, &pp->flags);
1439 #endif
1440     }
1441
1442 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
1443     kunmap(pp);
1444     UnlockPage(pp);
1445 #else
1446     clear_bit(PG_locked, &pp->flags);
1447     wake_up(&pp->wait);
1448     free_page(address);
1449 #endif
1450
1451     if (!code && AFS_CHUNKOFFSET(offset) == 0) {
1452         struct dcache *tdc;
1453         struct vrequest treq;
1454
1455         AFS_GLOCK();
1456         code = afs_InitReq(&treq, credp);
1457         if (!code && !NBObtainWriteLock(&avc->lock, 534)) {
1458             tdc = afs_FindDCache(avc, offset);
1459             if (tdc) {
1460                 if (!(tdc->mflags & DFNextStarted))
1461                     afs_PrefetchChunk(avc, tdc, credp, &treq);
1462                 afs_PutDCache(tdc);
1463             }
1464             ReleaseWriteLock(&avc->lock);
1465         }
1466         AFS_GUNLOCK();
1467     }
1468
1469     crfree(credp);
1470     return -code;
1471 }
1472
1473 #if defined(AFS_LINUX24_ENV)
1474 int
1475 afs_linux_writepage(struct page *pp)
1476 {
1477     struct address_space *mapping = pp->mapping;
1478     struct inode *inode;
1479     unsigned long end_index;
1480     unsigned offset = PAGE_CACHE_SIZE;
1481     long status;
1482
1483 #ifdef PageLaunder
1484     if (PageLaunder(pp)) {
1485         return(fail_writepage(pp));
1486     }
1487 #endif
1488
1489     inode = (struct inode *)mapping->host;
1490     end_index = inode->i_size >> PAGE_CACHE_SHIFT;
1491
1492     /* easy case */
1493     if (pp->index < end_index)
1494         goto do_it;
1495     /* things got complicated... */
1496     offset = inode->i_size & (PAGE_CACHE_SIZE - 1);
1497     /* OK, are we completely out? */
1498     if (pp->index >= end_index + 1 || !offset)
1499         return -EIO;
1500   do_it:
1501     AFS_GLOCK();
1502     status = afs_linux_writepage_sync(inode, pp, 0, offset);
1503     AFS_GUNLOCK();
1504     SetPageUptodate(pp);
1505     UnlockPage(pp);
1506     if (status == offset)
1507         return 0;
1508     else
1509         return status;
1510 }
1511 #endif
1512
1513 /* afs_linux_permission
1514  * Check access rights - returns error if can't check or permission denied.
1515  */
1516 int
1517 afs_linux_permission(struct inode *ip, int mode)
1518 {
1519     int code;
1520     cred_t *credp = crref();
1521     int tmp = 0;
1522
1523     AFS_GLOCK();
1524     if (mode & MAY_EXEC)
1525         tmp |= VEXEC;
1526     if (mode & MAY_READ)
1527         tmp |= VREAD;
1528     if (mode & MAY_WRITE)
1529         tmp |= VWRITE;
1530     code = afs_access(ITOAFS(ip), tmp, credp);
1531
1532     AFS_GUNLOCK();
1533     crfree(credp);
1534     return -code;
1535 }
1536
1537
1538 #if defined(AFS_LINUX24_ENV)
1539 int
1540 afs_linux_writepage_sync(struct inode *ip, struct page *pp,
1541                          unsigned long offset, unsigned int count)
1542 {
1543     struct vcache *vcp = ITOAFS(ip);
1544     char *buffer;
1545     afs_offs_t base;
1546     int code = 0;
1547     cred_t *credp;
1548     uio_t tuio;
1549     struct iovec iovec;
1550     int f_flags = 0;
1551
1552     buffer = kmap(pp) + offset;
1553     base = (pp->index << PAGE_CACHE_SHIFT) + offset;
1554
1555     credp = crref();
1556     afs_Trace4(afs_iclSetp, CM_TRACE_UPDATEPAGE, ICL_TYPE_POINTER, vcp,
1557                ICL_TYPE_POINTER, pp, ICL_TYPE_INT32, page_count(pp),
1558                ICL_TYPE_INT32, 99999);
1559
1560     setup_uio(&tuio, &iovec, buffer, base, count, UIO_WRITE, AFS_UIOSYS);
1561
1562     code = afs_write(vcp, &tuio, f_flags, credp, 0);
1563
1564     vcache2inode(vcp);
1565
1566     if (!code
1567         && afs_stats_cmperf.cacheCurrDirtyChunks >
1568         afs_stats_cmperf.cacheMaxDirtyChunks) {
1569         struct vrequest treq;
1570
1571         ObtainWriteLock(&vcp->lock, 533);
1572         if (!afs_InitReq(&treq, credp))
1573             code = afs_DoPartialWrite(vcp, &treq);
1574         ReleaseWriteLock(&vcp->lock);
1575     }
1576     code = code ? -code : count - tuio.uio_resid;
1577
1578     afs_Trace4(afs_iclSetp, CM_TRACE_UPDATEPAGE, ICL_TYPE_POINTER, vcp,
1579                ICL_TYPE_POINTER, pp, ICL_TYPE_INT32, page_count(pp),
1580                ICL_TYPE_INT32, code);
1581
1582     crfree(credp);
1583     kunmap(pp);
1584
1585     return code;
1586 }
1587
1588 static int
1589 afs_linux_updatepage(struct file *file, struct page *page,
1590                      unsigned long offset, unsigned int count)
1591 {
1592     struct dentry *dentry = file->f_dentry;
1593
1594     return afs_linux_writepage_sync(dentry->d_inode, page, offset, count);
1595 }
1596 #else
1597 /* afs_linux_updatepage
1598  * What one would have thought was writepage - write dirty page to file.
1599  * Called from generic_file_write. buffer is still in user space. pagep
1600  * has been filled in with old data if we're updating less than a page.
1601  */
1602 int
1603 afs_linux_updatepage(struct file *fp, struct page *pp, unsigned long offset,
1604                      unsigned int count, int sync)
1605 {
1606     struct vcache *vcp = ITOAFS(FILE_INODE(fp));
1607     u8 *page_addr = (u8 *) afs_linux_page_address(pp);
1608     int code = 0;
1609     cred_t *credp;
1610     uio_t tuio;
1611     struct iovec iovec;
1612
1613     set_bit(PG_locked, &pp->flags);
1614
1615     credp = crref();
1616     AFS_GLOCK();
1617     afs_Trace4(afs_iclSetp, CM_TRACE_UPDATEPAGE, ICL_TYPE_POINTER, vcp,
1618                ICL_TYPE_POINTER, pp, ICL_TYPE_INT32, page_count(pp),
1619                ICL_TYPE_INT32, 99999);
1620     setup_uio(&tuio, &iovec, page_addr + offset,
1621               (afs_offs_t) (pageoff(pp) + offset), count, UIO_WRITE,
1622               AFS_UIOSYS);
1623
1624     code = afs_write(vcp, &tuio, fp->f_flags, credp, 0);
1625
1626     vcache2inode(vcp);
1627
1628     code = code ? -code : count - tuio.uio_resid;
1629     afs_Trace4(afs_iclSetp, CM_TRACE_UPDATEPAGE, ICL_TYPE_POINTER, vcp,
1630                ICL_TYPE_POINTER, pp, ICL_TYPE_INT32, page_count(pp),
1631                ICL_TYPE_INT32, code);
1632
1633     AFS_GUNLOCK();
1634     crfree(credp);
1635
1636     clear_bit(PG_locked, &pp->flags);
1637     return code;
1638 }
1639 #endif
1640
1641 #if defined(AFS_LINUX24_ENV)
1642 static int
1643 afs_linux_commit_write(struct file *file, struct page *page, unsigned offset,
1644                        unsigned to)
1645 {
1646     int code;
1647
1648     lock_kernel();
1649     AFS_GLOCK();
1650     code = afs_linux_updatepage(file, page, offset, to - offset);
1651     AFS_GUNLOCK();
1652     unlock_kernel();
1653     kunmap(page);
1654
1655     return code;
1656 }
1657
1658 static int
1659 afs_linux_prepare_write(struct file *file, struct page *page, unsigned from,
1660                         unsigned to)
1661 {
1662     kmap(page);
1663     return 0;
1664 }
1665
1666 extern int afs_notify_change(struct dentry *dp, struct iattr *iattrp);
1667 #endif
1668
1669 struct inode_operations afs_file_iops = {
1670 #if defined(AFS_LINUX26_ENV)
1671   .permission =         afs_linux_permission,
1672   .getattr =            afs_linux_getattr,
1673   .setattr =            afs_notify_change,
1674 #elif defined(AFS_LINUX24_ENV)
1675   .permission =         afs_linux_permission,
1676   .revalidate =         afs_linux_revalidate,
1677   .setattr =            afs_notify_change,
1678 #else
1679   .default_file_ops =   &afs_file_fops,
1680   .readpage =           afs_linux_readpage,
1681   .revalidate =         afs_linux_revalidate,
1682   .updatepage =         afs_linux_updatepage,
1683 #endif
1684 };
1685
1686 #if defined(AFS_LINUX24_ENV)
1687 struct address_space_operations afs_file_aops = {
1688   .readpage =           afs_linux_readpage,
1689   .writepage =          afs_linux_writepage,
1690   .commit_write =       afs_linux_commit_write,
1691   .prepare_write =      afs_linux_prepare_write,
1692 };
1693 #endif
1694
1695
1696 /* Separate ops vector for directories. Linux 2.2 tests type of inode
1697  * by what sort of operation is allowed.....
1698  */
1699
1700 struct inode_operations afs_dir_iops = {
1701 #if !defined(AFS_LINUX24_ENV)
1702   .default_file_ops =   &afs_dir_fops,
1703 #else
1704   .setattr =            afs_notify_change,
1705 #endif
1706   .create =             afs_linux_create,
1707   .lookup =             afs_linux_lookup,
1708   .link =               afs_linux_link,
1709   .unlink =             afs_linux_unlink,
1710   .symlink =            afs_linux_symlink,
1711   .mkdir =              afs_linux_mkdir,
1712   .rmdir =              afs_linux_rmdir,
1713   .rename =             afs_linux_rename,
1714 #if defined(AFS_LINUX26_ENV)
1715   .getattr =            afs_linux_getattr,
1716 #else
1717   .revalidate =         afs_linux_revalidate,
1718 #endif
1719   .permission =         afs_linux_permission,
1720 };
1721
1722 /* We really need a separate symlink set of ops, since do_follow_link()
1723  * determines if it _is_ a link by checking if the follow_link op is set.
1724  */
1725 #if defined(AFS_LINUX24_ENV)
1726 static int
1727 afs_symlink_filler(struct file *file, struct page *page)
1728 {
1729     struct inode *ip = (struct inode *)page->mapping->host;
1730     char *p = (char *)kmap(page);
1731     int code;
1732
1733     lock_kernel();
1734     AFS_GLOCK();
1735     code = afs_linux_ireadlink(ip, p, PAGE_SIZE, AFS_UIOSYS);
1736     AFS_GUNLOCK();
1737
1738     if (code < 0)
1739         goto fail;
1740     p[code] = '\0';             /* null terminate? */
1741     unlock_kernel();
1742
1743     SetPageUptodate(page);
1744     kunmap(page);
1745     UnlockPage(page);
1746     return 0;
1747
1748   fail:
1749     unlock_kernel();
1750
1751     SetPageError(page);
1752     kunmap(page);
1753     UnlockPage(page);
1754     return code;
1755 }
1756
1757 struct address_space_operations afs_symlink_aops = {
1758   .readpage =   afs_symlink_filler
1759 };
1760 #endif
1761
1762 struct inode_operations afs_symlink_iops = {
1763 #if defined(AFS_LINUX24_ENV)
1764   .readlink =           page_readlink,
1765   .follow_link =        page_follow_link,
1766   .setattr =            afs_notify_change,
1767 #else
1768   .readlink =           afs_linux_readlink,
1769   .follow_link =        afs_linux_follow_link,
1770   .permission =         afs_linux_permission,
1771   .revalidate =         afs_linux_revalidate,
1772 #endif
1773 };