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