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