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