linux-sysname-list-sys-links-resolve-dentry-20031109
[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 #define AFS_EQ_ATSYS(name) (((name)[0]=='@')&&((name)[1]=='s')&&((name)[2]=='y')&&((name)[3]=='s')&&(!(name)[4]))
1076
1077 /* afs_linux_lookup */
1078 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,10)
1079 struct dentry *
1080 afs_linux_lookup(struct inode *dip, struct dentry *dp)
1081 #else
1082 int
1083 afs_linux_lookup(struct inode *dip, struct dentry *dp)
1084 #endif
1085 {
1086     int code = 0;
1087     cred_t *credp = crref();
1088     struct vcache *vcp = NULL;
1089     const char *comp = dp->d_name.name;
1090     char *name = NULL;
1091     struct sysname_info sysState;
1092     struct qstr qstr;
1093     struct vrequest treq;
1094
1095     sysState.allocked = 0;
1096
1097     AFS_GLOCK();
1098
1099     /* In order that we not get ESTALE on @sys links that resolve
1100        into the 2nd or later item in an @sys list, resolve it ourselves
1101        and force a lookup of the actual match here. The real directory
1102        thus gets the dentry. */
1103     if (AFS_EQ_ATSYS(comp) && !afs_InitReq(&treq, credp)) {
1104         Check_AtSys(ITOAFS(dip), comp, &sysState, &treq);
1105         name = sysState.name;
1106
1107         code = afs_lookup(ITOAFS(dip), name, &vcp, credp);
1108         while (code == ENOENT && Next_AtSys(ITOAFS(dip), &treq, &sysState)) {
1109             code = afs_lookup(ITOAFS(dip), name, &vcp, credp);
1110         }
1111     } else
1112         code = afs_lookup(ITOAFS(dip), comp, &vcp, credp);
1113     
1114     if (vcp) {
1115         struct inode *ip = AFSTOI(vcp);
1116         /* Reset ops if symlink or directory. */
1117 #if defined(AFS_LINUX24_ENV)
1118         if (S_ISREG(ip->i_mode)) {
1119             ip->i_op = &afs_file_iops;
1120             ip->i_fop = &afs_file_fops;
1121             ip->i_data.a_ops = &afs_file_aops;
1122         } else if (S_ISDIR(ip->i_mode)) {
1123             ip->i_op = &afs_dir_iops;
1124             ip->i_fop = &afs_dir_fops;
1125         } else if (S_ISLNK(ip->i_mode)) {
1126             ip->i_op = &afs_symlink_iops;
1127             ip->i_data.a_ops = &afs_symlink_aops;
1128             ip->i_mapping = &ip->i_data;
1129         } else
1130             printk
1131                 ("afs_linux_lookup: ip->i_mode 0x%x  dp->d_name.name %s  code %d\n",
1132                  ip->i_mode, dp->d_name.name, code);
1133 #else
1134         if (S_ISDIR(ip->i_mode))
1135             ip->i_op = &afs_dir_iops;
1136         else if (S_ISLNK(ip->i_mode))
1137             ip->i_op = &afs_symlink_iops;
1138 #endif
1139     }
1140     dp->d_time = jiffies;
1141     dp->d_op = afs_dops;
1142     d_add(dp, AFSTOI(vcp));
1143
1144 #if 0
1145     /* Set up a dentry alias. Should we be doing this for @sys?
1146        You only get one for a directory, which would be fine,
1147        @sys would only map to one at a time, but it's unclear
1148        that this is consistent behavior. */
1149     if (AFS_EQ_ATSYS(comp) && sysState.allocked) {
1150         int result;
1151         struct dentry *dentry;
1152
1153         qstr.name = name;
1154         qstr.len  = strlen(name);
1155         qstr.hash = full_name_hash(name, qstr.len);
1156         result = d_lookup(dp->d_parent, &qstr);
1157         if (!result) {
1158             dentry = d_alloc(dp->d_parent, &qstr);
1159             if (dentry)
1160                 d_instantiate(dentry, AFSTOI(vcp));
1161         }
1162     }
1163 #endif
1164
1165     AFS_GUNLOCK();
1166     crfree(credp);
1167
1168     /* It's ok for the file to not be found. That's noted by the caller by
1169      * seeing that the dp->d_inode field is NULL.
1170      */
1171 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,10)
1172     if (code == ENOENT)
1173         return ERR_PTR(0);
1174     else
1175         return ERR_PTR(-code);
1176 #else
1177     if (code == ENOENT)
1178         code = 0;
1179     return -code;
1180 #endif
1181 }
1182
1183 int
1184 afs_linux_link(struct dentry *olddp, struct inode *dip, struct dentry *newdp)
1185 {
1186     int code;
1187     cred_t *credp = crref();
1188     const char *name = newdp->d_name.name;
1189     struct inode *oldip = olddp->d_inode;
1190
1191     /* If afs_link returned the vnode, we could instantiate the
1192      * dentry. Since it's not, we drop this one and do a new lookup.
1193      */
1194     d_drop(newdp);
1195
1196     AFS_GLOCK();
1197     code = afs_link(ITOAFS(oldip), ITOAFS(dip), name, credp);
1198
1199     AFS_GUNLOCK();
1200     crfree(credp);
1201     return -code;
1202 }
1203
1204 int
1205 afs_linux_unlink(struct inode *dip, struct dentry *dp)
1206 {
1207     int code;
1208     cred_t *credp = crref();
1209     const char *name = dp->d_name.name;
1210
1211     AFS_GLOCK();
1212     code = afs_remove(ITOAFS(dip), name, credp);
1213     AFS_GUNLOCK();
1214     if (!code)
1215         d_drop(dp);
1216     crfree(credp);
1217     return -code;
1218 }
1219
1220
1221 int
1222 afs_linux_symlink(struct inode *dip, struct dentry *dp, const char *target)
1223 {
1224     int code;
1225     cred_t *credp = crref();
1226     struct vattr vattr;
1227     const char *name = dp->d_name.name;
1228
1229     /* If afs_symlink returned the vnode, we could instantiate the
1230      * dentry. Since it's not, we drop this one and do a new lookup.
1231      */
1232     d_drop(dp);
1233
1234     AFS_GLOCK();
1235     VATTR_NULL(&vattr);
1236     code = afs_symlink(ITOAFS(dip), name, &vattr, target, credp);
1237     AFS_GUNLOCK();
1238     crfree(credp);
1239     return -code;
1240 }
1241
1242 int
1243 afs_linux_mkdir(struct inode *dip, struct dentry *dp, int mode)
1244 {
1245     int code;
1246     cred_t *credp = crref();
1247     struct vcache *tvcp = NULL;
1248     struct vattr vattr;
1249     const char *name = dp->d_name.name;
1250
1251     AFS_GLOCK();
1252     VATTR_NULL(&vattr);
1253     vattr.va_mask = ATTR_MODE;
1254     vattr.va_mode = mode;
1255     code = afs_mkdir(ITOAFS(dip), name, &vattr, &tvcp, credp);
1256
1257     if (tvcp) {
1258         tvcp->v.v_op = &afs_dir_iops;
1259 #if defined(AFS_LINUX24_ENV)
1260         tvcp->v.v_fop = &afs_dir_fops;
1261 #endif
1262         dp->d_op = afs_dops;
1263         dp->d_time = jiffies;
1264         d_instantiate(dp, AFSTOI(tvcp));
1265     }
1266
1267     AFS_GUNLOCK();
1268     crfree(credp);
1269     return -code;
1270 }
1271
1272 int
1273 afs_linux_rmdir(struct inode *dip, struct dentry *dp)
1274 {
1275     int code;
1276     cred_t *credp = crref();
1277     const char *name = dp->d_name.name;
1278
1279     AFS_GLOCK();
1280     code = afs_rmdir(ITOAFS(dip), name, credp);
1281
1282     /* Linux likes to see ENOTEMPTY returned from an rmdir() syscall
1283      * that failed because a directory is not empty. So, we map
1284      * EEXIST to ENOTEMPTY on linux.
1285      */
1286     if (code == EEXIST) {
1287         code = ENOTEMPTY;
1288     }
1289
1290     if (!code) {
1291         d_drop(dp);
1292     }
1293
1294     AFS_GUNLOCK();
1295     crfree(credp);
1296     return -code;
1297 }
1298
1299
1300
1301 int
1302 afs_linux_rename(struct inode *oldip, struct dentry *olddp,
1303                  struct inode *newip, struct dentry *newdp)
1304 {
1305     int code;
1306     cred_t *credp = crref();
1307     const char *oldname = olddp->d_name.name;
1308     const char *newname = newdp->d_name.name;
1309
1310     /* Remove old and new entries from name hash. New one will change below.
1311      * While it's optimal to catch failures and re-insert newdp into hash,
1312      * it's also error prone and in that case we're already dealing with error
1313      * cases. Let another lookup put things right, if need be.
1314      */
1315     if (!list_empty(&olddp->d_hash)) {
1316         d_drop(olddp);
1317     }
1318     if (!list_empty(&newdp->d_hash)) {
1319         d_drop(newdp);
1320     }
1321     AFS_GLOCK();
1322     code = afs_rename(ITOAFS(oldip), oldname, ITOAFS(newip), newname, credp);
1323     AFS_GUNLOCK();
1324
1325     if (!code) {
1326         /* update time so it doesn't expire immediately */
1327         newdp->d_time = jiffies;
1328         d_move(olddp, newdp);
1329     }
1330
1331     crfree(credp);
1332     return -code;
1333 }
1334
1335
1336 /* afs_linux_ireadlink 
1337  * Internal readlink which can return link contents to user or kernel space.
1338  * Note that the buffer is NOT supposed to be null-terminated.
1339  */
1340 static int
1341 afs_linux_ireadlink(struct inode *ip, char *target, int maxlen, uio_seg_t seg)
1342 {
1343     int code;
1344     cred_t *credp = crref();
1345     uio_t tuio;
1346     struct iovec iov;
1347
1348     setup_uio(&tuio, &iov, target, (afs_offs_t) 0, maxlen, UIO_READ, seg);
1349     code = afs_readlink(ITOAFS(ip), &tuio, credp);
1350     crfree(credp);
1351
1352     if (!code)
1353         return maxlen - tuio.uio_resid;
1354     else
1355         return -code;
1356 }
1357
1358 #if !defined(AFS_LINUX24_ENV)
1359 /* afs_linux_readlink 
1360  * Fill target (which is in user space) with contents of symlink.
1361  */
1362 int
1363 afs_linux_readlink(struct dentry *dp, char *target, int maxlen)
1364 {
1365     int code;
1366     struct inode *ip = dp->d_inode;
1367
1368     AFS_GLOCK();
1369     code = afs_linux_ireadlink(ip, target, maxlen, AFS_UIOUSER);
1370     AFS_GUNLOCK();
1371     return code;
1372 }
1373
1374
1375 /* afs_linux_follow_link
1376  * a file system dependent link following routine.
1377  */
1378 struct dentry *
1379 afs_linux_follow_link(struct dentry *dp, struct dentry *basep,
1380                       unsigned int follow)
1381 {
1382     int code = 0;
1383     char *name;
1384     struct dentry *res;
1385
1386
1387     AFS_GLOCK();
1388     name = osi_Alloc(PATH_MAX + 1);
1389     if (!name) {
1390         AFS_GUNLOCK();
1391         dput(basep);
1392         return ERR_PTR(-EIO);
1393     }
1394
1395     code = afs_linux_ireadlink(dp->d_inode, name, PATH_MAX, AFS_UIOSYS);
1396     AFS_GUNLOCK();
1397
1398     if (code < 0) {
1399         dput(basep);
1400         res = ERR_PTR(code);
1401     } else {
1402         name[code] = '\0';
1403         res = lookup_dentry(name, basep, follow);
1404     }
1405
1406     AFS_GLOCK();
1407     osi_Free(name, PATH_MAX + 1);
1408     AFS_GUNLOCK();
1409     return res;
1410 }
1411 #endif
1412
1413 /* afs_linux_readpage
1414  * all reads come through here. A strategy-like read call.
1415  */
1416 int
1417 afs_linux_readpage(struct file *fp, struct page *pp)
1418 {
1419     int code;
1420     cred_t *credp = crref();
1421 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
1422     char *address;
1423     afs_offs_t offset = pp->index << PAGE_CACHE_SHIFT;
1424 #else
1425     ulong address = afs_linux_page_address(pp);
1426     afs_offs_t offset = pageoff(pp);
1427 #endif
1428     uio_t tuio;
1429     struct iovec iovec;
1430     struct inode *ip = FILE_INODE(fp);
1431     int cnt = atomic_read(&pp->count);
1432     struct vcache *avc = ITOAFS(ip);
1433
1434     AFS_GLOCK();
1435     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 */
1436 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
1437     address = kmap(pp);
1438     ClearPageError(pp);
1439
1440     lock_kernel();
1441 #else
1442     atomic_add(1, &pp->count);
1443     set_bit(PG_locked, &pp->flags);     /* other bits? See mm.h */
1444     clear_bit(PG_error, &pp->flags);
1445 #endif
1446
1447     setup_uio(&tuio, &iovec, (char *)address, offset, PAGESIZE, UIO_READ,
1448               AFS_UIOSYS);
1449     code = afs_rdwr(avc, &tuio, UIO_READ, 0, credp);
1450 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
1451     unlock_kernel();
1452 #endif
1453
1454     if (!code) {
1455         if (tuio.uio_resid)     /* zero remainder of page */
1456             memset((void *)(address + (PAGESIZE - tuio.uio_resid)), 0,
1457                    tuio.uio_resid);
1458 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
1459         flush_dcache_page(pp);
1460         SetPageUptodate(pp);
1461 #else
1462         set_bit(PG_uptodate, &pp->flags);
1463 #endif
1464     }
1465 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
1466     kunmap(pp);
1467     UnlockPage(pp);
1468 #else
1469     clear_bit(PG_locked, &pp->flags);
1470     wake_up(&pp->wait);
1471     free_page(address);
1472 #endif
1473
1474     if (!code && AFS_CHUNKOFFSET(offset) == 0) {
1475         struct dcache *tdc;
1476         struct vrequest treq;
1477
1478         code = afs_InitReq(&treq, credp);
1479         if (!code && !NBObtainWriteLock(&avc->lock, 534)) {
1480             tdc = afs_FindDCache(avc, offset);
1481             if (tdc) {
1482                 if (!(tdc->mflags & DFNextStarted))
1483                     afs_PrefetchChunk(avc, tdc, credp, &treq);
1484                 afs_PutDCache(tdc);
1485             }
1486             ReleaseWriteLock(&avc->lock);
1487         }
1488     }
1489
1490     crfree(credp);
1491     afs_Trace4(afs_iclSetp, CM_TRACE_READPAGE, ICL_TYPE_POINTER, ip,
1492                ICL_TYPE_POINTER, pp, ICL_TYPE_INT32, cnt, ICL_TYPE_INT32,
1493                code);
1494     AFS_GUNLOCK();
1495     return -code;
1496 }
1497
1498 #if defined(AFS_LINUX24_ENV)
1499 int
1500 afs_linux_writepage(struct page *pp)
1501 {
1502     struct address_space *mapping = pp->mapping;
1503     struct inode *inode;
1504     unsigned long end_index;
1505     unsigned offset = PAGE_CACHE_SIZE;
1506     long status;
1507
1508     inode = (struct inode *)mapping->host;
1509     end_index = inode->i_size >> PAGE_CACHE_SHIFT;
1510
1511     /* easy case */
1512     if (pp->index < end_index)
1513         goto do_it;
1514     /* things got complicated... */
1515     offset = inode->i_size & (PAGE_CACHE_SIZE - 1);
1516     /* OK, are we completely out? */
1517     if (pp->index >= end_index + 1 || !offset)
1518         return -EIO;
1519   do_it:
1520     AFS_GLOCK();
1521     status = afs_linux_writepage_sync(inode, pp, 0, offset);
1522     AFS_GUNLOCK();
1523     SetPageUptodate(pp);
1524     UnlockPage(pp);
1525     if (status == offset)
1526         return 0;
1527     else
1528         return status;
1529 }
1530 #endif
1531
1532 #ifdef NOTUSED
1533 /* afs_linux_bmap - supports generic_readpage, but we roll our own. */
1534 int
1535 afs_linux_bmap(struct inode *ip, int)
1536 {
1537     return -EINVAL;
1538 }
1539
1540 /* afs_linux_truncate
1541  * Handles discarding disk blocks if this were a device. ext2 indicates we
1542  * may need to zero partial last pages of memory mapped files.
1543  */
1544 void
1545 afs_linux_truncate(struct inode *ip)
1546 {
1547 }
1548 #endif
1549
1550 /* afs_linux_permission
1551  * Check access rights - returns error if can't check or permission denied.
1552  */
1553 int
1554 afs_linux_permission(struct inode *ip, int mode)
1555 {
1556     int code;
1557     cred_t *credp = crref();
1558     int tmp = 0;
1559
1560     AFS_GLOCK();
1561     if (mode & MAY_EXEC)
1562         tmp |= VEXEC;
1563     if (mode & MAY_READ)
1564         tmp |= VREAD;
1565     if (mode & MAY_WRITE)
1566         tmp |= VWRITE;
1567     code = afs_access(ITOAFS(ip), tmp, credp);
1568
1569     AFS_GUNLOCK();
1570     crfree(credp);
1571     return -code;
1572 }
1573
1574
1575 #ifdef NOTUSED
1576 /* msdos sector mapping hack for memory mapping. */
1577 int
1578 afs_linux_smap(struct inode *ip, int)
1579 {
1580     return -EINVAL;
1581 }
1582 #endif
1583
1584 #if defined(AFS_LINUX24_ENV)
1585 int
1586 afs_linux_writepage_sync(struct inode *ip, struct page *pp,
1587                          unsigned long offset, unsigned int count)
1588 {
1589     struct vcache *vcp = ITOAFS(ip);
1590     char *buffer;
1591     afs_offs_t base;
1592     int code = 0;
1593     cred_t *credp;
1594     uio_t tuio;
1595     struct iovec iovec;
1596     int f_flags = 0;
1597
1598     buffer = kmap(pp) + offset;
1599     base = (pp->index << PAGE_CACHE_SHIFT) + offset;
1600
1601     credp = crref();
1602     afs_Trace4(afs_iclSetp, CM_TRACE_UPDATEPAGE, ICL_TYPE_POINTER, vcp,
1603                ICL_TYPE_POINTER, pp, ICL_TYPE_INT32, atomic_read(&pp->count),
1604                ICL_TYPE_INT32, 99999);
1605
1606     setup_uio(&tuio, &iovec, buffer, base, count, UIO_WRITE, AFS_UIOSYS);
1607
1608     code = afs_write(vcp, &tuio, f_flags, credp, 0);
1609
1610     vcache2inode(vcp);
1611
1612     if (!code
1613         && afs_stats_cmperf.cacheCurrDirtyChunks >
1614         afs_stats_cmperf.cacheMaxDirtyChunks) {
1615         struct vrequest treq;
1616
1617         ObtainWriteLock(&vcp->lock, 533);
1618         if (!afs_InitReq(&treq, credp))
1619             code = afs_DoPartialWrite(vcp, &treq);
1620         ReleaseWriteLock(&vcp->lock);
1621     }
1622     code = code ? -code : count - tuio.uio_resid;
1623
1624     afs_Trace4(afs_iclSetp, CM_TRACE_UPDATEPAGE, ICL_TYPE_POINTER, vcp,
1625                ICL_TYPE_POINTER, pp, ICL_TYPE_INT32, atomic_read(&pp->count),
1626                ICL_TYPE_INT32, code);
1627
1628     crfree(credp);
1629     kunmap(pp);
1630
1631     return code;
1632 }
1633
1634 static int
1635 afs_linux_updatepage(struct file *file, struct page *page,
1636                      unsigned long offset, unsigned int count)
1637 {
1638     struct dentry *dentry = file->f_dentry;
1639
1640     return afs_linux_writepage_sync(dentry->d_inode, page, offset, count);
1641 }
1642 #else
1643 /* afs_linux_updatepage
1644  * What one would have thought was writepage - write dirty page to file.
1645  * Called from generic_file_write. buffer is still in user space. pagep
1646  * has been filled in with old data if we're updating less than a page.
1647  */
1648 int
1649 afs_linux_updatepage(struct file *fp, struct page *pp, unsigned long offset,
1650                      unsigned int count, int sync)
1651 {
1652     struct vcache *vcp = ITOAFS(FILE_INODE(fp));
1653     u8 *page_addr = (u8 *) afs_linux_page_address(pp);
1654     int code = 0;
1655     cred_t *credp;
1656     uio_t tuio;
1657     struct iovec iovec;
1658
1659     set_bit(PG_locked, &pp->flags);
1660
1661     credp = crref();
1662     AFS_GLOCK();
1663     afs_Trace4(afs_iclSetp, CM_TRACE_UPDATEPAGE, ICL_TYPE_POINTER, vcp,
1664                ICL_TYPE_POINTER, pp, ICL_TYPE_INT32, atomic_read(&pp->count),
1665                ICL_TYPE_INT32, 99999);
1666     setup_uio(&tuio, &iovec, page_addr + offset,
1667               (afs_offs_t) (pageoff(pp) + offset), count, UIO_WRITE,
1668               AFS_UIOSYS);
1669
1670     code = afs_write(vcp, &tuio, fp->f_flags, credp, 0);
1671
1672     vcache2inode(vcp);
1673
1674     code = code ? -code : count - tuio.uio_resid;
1675     afs_Trace4(afs_iclSetp, CM_TRACE_UPDATEPAGE, ICL_TYPE_POINTER, vcp,
1676                ICL_TYPE_POINTER, pp, ICL_TYPE_INT32, atomic_read(&pp->count),
1677                ICL_TYPE_INT32, code);
1678
1679     AFS_GUNLOCK();
1680     crfree(credp);
1681
1682     clear_bit(PG_locked, &pp->flags);
1683     return code;
1684 }
1685 #endif
1686
1687 #if defined(AFS_LINUX24_ENV)
1688 static int
1689 afs_linux_commit_write(struct file *file, struct page *page, unsigned offset,
1690                        unsigned to)
1691 {
1692     int code;
1693
1694     AFS_GLOCK();
1695     lock_kernel();
1696     code = afs_linux_updatepage(file, page, offset, to - offset);
1697     unlock_kernel();
1698     AFS_GUNLOCK();
1699     kunmap(page);
1700
1701     return code;
1702 }
1703
1704 static int
1705 afs_linux_prepare_write(struct file *file, struct page *page, unsigned from,
1706                         unsigned to)
1707 {
1708     kmap(page);
1709     return 0;
1710 }
1711
1712 extern int afs_notify_change(struct dentry *dp, struct iattr *iattrp);
1713 #endif
1714
1715 #if defined(AFS_LINUX24_ENV)
1716 struct inode_operations afs_file_iops = {
1717   revalidate:afs_linux_revalidate,
1718   setattr:afs_notify_change,
1719   permission:afs_linux_permission,
1720 };
1721 struct address_space_operations afs_file_aops = {
1722   readpage:afs_linux_readpage,
1723   writepage:afs_linux_writepage,
1724   commit_write:afs_linux_commit_write,
1725   prepare_write:afs_linux_prepare_write,
1726 };
1727
1728 struct inode_operations *afs_ops = &afs_file_iops;
1729 #else
1730 struct inode_operations afs_iops = {
1731     &afs_file_fops,             /* file operations */
1732     NULL,                       /* afs_linux_create */
1733     NULL,                       /* afs_linux_lookup */
1734     NULL,                       /* afs_linux_link */
1735     NULL,                       /* afs_linux_unlink */
1736     NULL,                       /* afs_linux_symlink */
1737     NULL,                       /* afs_linux_mkdir */
1738     NULL,                       /* afs_linux_rmdir */
1739     NULL,                       /* afs_linux_mknod */
1740     NULL,                       /* afs_linux_rename */
1741     NULL,                       /* afs_linux_readlink */
1742     NULL,                       /* afs_linux_follow_link */
1743     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     afs_linux_updatepage,
1750     afs_linux_revalidate,
1751 };
1752
1753 struct inode_operations *afs_ops = &afs_iops;
1754 #endif
1755
1756 /* Separate ops vector for directories. Linux 2.2 tests type of inode
1757  * by what sort of operation is allowed.....
1758  */
1759 #if defined(AFS_LINUX24_ENV)
1760 struct inode_operations afs_dir_iops = {
1761   create:afs_linux_create,
1762   lookup:afs_linux_lookup,
1763   link:afs_linux_link,
1764   unlink:afs_linux_unlink,
1765   symlink:afs_linux_symlink,
1766   mkdir:afs_linux_mkdir,
1767   rmdir:afs_linux_rmdir,
1768   rename:afs_linux_rename,
1769   revalidate:afs_linux_revalidate,
1770   setattr:afs_notify_change,
1771   permission:afs_linux_permission,
1772 };
1773 #else
1774 struct inode_operations afs_dir_iops = {
1775     &afs_dir_fops,              /* file operations for directories */
1776     afs_linux_create,
1777     afs_linux_lookup,
1778     afs_linux_link,
1779     afs_linux_unlink,
1780     afs_linux_symlink,
1781     afs_linux_mkdir,
1782     afs_linux_rmdir,
1783     NULL,                       /* afs_linux_mknod */
1784     afs_linux_rename,
1785     NULL,                       /* afs_linux_readlink */
1786     NULL,                       /* afs_linux_follow_link */
1787     NULL,                       /* afs_linux_readpage */
1788     NULL,                       /* afs_linux_writepage */
1789     NULL,                       /* afs_linux_bmap */
1790     NULL,                       /* afs_linux_truncate */
1791     afs_linux_permission,
1792     NULL,                       /* afs_linux_smap */
1793     NULL,                       /* afs_linux_updatepage */
1794     afs_linux_revalidate,
1795 };
1796 #endif
1797
1798 /* We really need a separate symlink set of ops, since do_follow_link()
1799  * determines if it _is_ a link by checking if the follow_link op is set.
1800  */
1801 #if defined(AFS_LINUX24_ENV)
1802 static int
1803 afs_symlink_filler(struct file *file, struct page *page)
1804 {
1805     struct inode *ip = (struct inode *)page->mapping->host;
1806     char *p = (char *)kmap(page);
1807     int code;
1808
1809     AFS_GLOCK();
1810     lock_kernel();
1811     code = afs_linux_ireadlink(ip, p, PAGE_SIZE, AFS_UIOSYS);
1812
1813     if (code < 0)
1814         goto fail;
1815     p[code] = '\0';             /* null terminate? */
1816     unlock_kernel();
1817     AFS_GUNLOCK();
1818
1819     SetPageUptodate(page);
1820     kunmap(page);
1821     UnlockPage(page);
1822     return 0;
1823
1824   fail:
1825     unlock_kernel();
1826     AFS_GUNLOCK();
1827
1828     SetPageError(page);
1829     kunmap(page);
1830     UnlockPage(page);
1831     return code;
1832 }
1833
1834 struct address_space_operations afs_symlink_aops = {
1835   readpage:afs_symlink_filler
1836 };
1837
1838 struct inode_operations afs_symlink_iops = {
1839   readlink:page_readlink,
1840   follow_link:page_follow_link,
1841   setattr:afs_notify_change,
1842 };
1843 #else
1844 struct inode_operations afs_symlink_iops = {
1845     NULL,                       /* file operations */
1846     NULL,                       /* create */
1847     NULL,                       /* lookup */
1848     NULL,                       /* link */
1849     NULL,                       /* unlink */
1850     NULL,                       /* symlink */
1851     NULL,                       /* mkdir */
1852     NULL,                       /* rmdir */
1853     NULL,                       /* afs_linux_mknod */
1854     NULL,                       /* rename */
1855     afs_linux_readlink,
1856     afs_linux_follow_link,
1857     NULL,                       /* readpage */
1858     NULL,                       /* afs_linux_writepage */
1859     NULL,                       /* afs_linux_bmap */
1860     NULL,                       /* afs_linux_truncate */
1861     afs_linux_permission,       /* tho the code appears to indicate not used? */
1862     NULL,                       /* afs_linux_smap */
1863     NULL,                       /* updatepage */
1864     afs_linux_revalidate,       /* tho the code appears to indicate not used? */
1865 };
1866 #endif