linux-restore-iget-cachemgr-20080326
[openafs.git] / src / afs / LINUX / osi_file.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 #include <afsconfig.h>
11 #include "afs/param.h"
12
13 RCSID
14     ("$Header$");
15
16 #ifdef AFS_LINUX24_ENV
17 #include "h/module.h" /* early to avoid printf->printk mapping */
18 #endif
19 #include "afs/sysincludes.h"    /* Standard vendor system headers */
20 #include "afsincludes.h"        /* Afs-based standard headers */
21 #include "afs/afs_stats.h"      /* afs statistics */
22 #include "h/smp_lock.h"
23 #if defined(AFS_LINUX26_ENV)
24 #include "h/namei.h"
25 #endif
26 #if !defined(HAVE_IGET)
27 #include "h/exportfs.h"
28 #endif
29
30 afs_lock_t afs_xosi;            /* lock is for tvattr */
31 extern struct osi_dev cacheDev;
32 #if defined(AFS_LINUX24_ENV)
33 extern struct vfsmount *afs_cacheMnt;
34 #endif
35 extern struct super_block *afs_cacheSBp;
36
37 #if defined(AFS_LINUX26_ENV) 
38 void *
39 osi_UFSOpen(afs_int32 ainode)
40 {
41     register struct osi_file *afile = NULL;
42     extern int cacheDiskType;
43     struct inode *tip = NULL;
44     struct dentry *dp = NULL;
45     struct file *filp = NULL;
46 #if !defined(HAVE_IGET)
47     struct fid fid;
48 #endif
49     AFS_STATCNT(osi_UFSOpen);
50     if (cacheDiskType != AFS_FCACHE_TYPE_UFS) {
51         osi_Panic("UFSOpen called for non-UFS cache\n");
52     }
53     if (!afs_osicred_initialized) {
54         /* valid for alpha_osf, SunOS, Ultrix */
55         memset((char *)&afs_osi_cred, 0, sizeof(struct AFS_UCRED));
56         crhold(&afs_osi_cred);  /* don't let it evaporate, since it is static */
57         afs_osicred_initialized = 1;
58     }
59     afile = (struct osi_file *)osi_AllocLargeSpace(sizeof(struct osi_file));
60     AFS_GUNLOCK();
61     if (!afile) {
62         osi_Panic("osi_UFSOpen: Failed to allocate %d bytes for osi_file.\n",
63                   sizeof(struct osi_file));
64     }
65     memset(afile, 0, sizeof(struct osi_file));
66 #if defined(HAVE_IGET)
67     tip = iget(afs_cacheSBp, (u_long) ainode);
68     if (!tip)
69         osi_Panic("Can't get inode %d\n", ainode);
70
71     dp = d_alloc_anon(tip);
72 #else
73     fid.i32.ino = ainode;
74     fid.i32.gen = 0;
75     dp = afs_cacheSBp->s_export_op->fh_to_dentry(afs_cacheSBp, &fid, sizeof(fid), FILEID_INO32_GEN);
76     if (!dp) 
77            osi_Panic("Can't get dentry for inode %d\n", ainode);          
78     tip = dp->d_inode;
79 #endif
80     tip->i_flags |= MS_NOATIME; /* Disable updating access times. */
81
82     filp = dentry_open(dp, mntget(afs_cacheMnt), O_RDWR);
83     if (IS_ERR(filp))
84         osi_Panic("Can't open inode %d\n", ainode);
85     afile->filp = filp;
86     afile->size = FILE_INODE(filp)->i_size;
87     AFS_GLOCK();
88     afile->offset = 0;
89     afile->proc = (int (*)())0;
90     afile->inum = ainode;       /* for hint validity checking */
91     return (void *)afile;
92 }
93 #else
94 void *
95 osi_UFSOpen(afs_int32 ainode)
96 {
97     register struct osi_file *afile = NULL;
98     extern int cacheDiskType;
99     afs_int32 code = 0;
100     struct inode *tip = NULL;
101     struct file *filp = NULL;
102     AFS_STATCNT(osi_UFSOpen);
103     if (cacheDiskType != AFS_FCACHE_TYPE_UFS) {
104         osi_Panic("UFSOpen called for non-UFS cache\n");
105     }
106     if (!afs_osicred_initialized) {
107         /* valid for alpha_osf, SunOS, Ultrix */
108         memset((char *)&afs_osi_cred, 0, sizeof(struct AFS_UCRED));
109         crhold(&afs_osi_cred);  /* don't let it evaporate, since it is static */
110         afs_osicred_initialized = 1;
111     }
112     afile = (struct osi_file *)osi_AllocLargeSpace(sizeof(struct osi_file));
113     AFS_GUNLOCK();
114     if (!afile) {
115         osi_Panic("osi_UFSOpen: Failed to allocate %d bytes for osi_file.\n",
116                   sizeof(struct osi_file));
117     }
118     memset(afile, 0, sizeof(struct osi_file));
119     filp = &afile->file;
120     filp->f_dentry = &afile->dentry;
121     tip = iget(afs_cacheSBp, (u_long) ainode);
122     if (!tip)
123         osi_Panic("Can't get inode %d\n", ainode);
124     FILE_INODE(filp) = tip;
125     tip->i_flags |= MS_NOATIME; /* Disable updating access times. */
126     filp->f_flags = O_RDWR;
127 #if defined(AFS_LINUX24_ENV)
128     filp->f_mode = FMODE_READ|FMODE_WRITE;
129     filp->f_op = fops_get(tip->i_fop);
130 #else
131     filp->f_op = tip->i_op->default_file_ops;
132 #endif
133     if (filp->f_op && filp->f_op->open)
134         code = filp->f_op->open(tip, filp);
135     if (code)
136         osi_Panic("Can't open inode %d\n", ainode);
137     afile->size = tip->i_size;
138     AFS_GLOCK();
139     afile->offset = 0;
140     afile->proc = (int (*)())0;
141     afile->inum = ainode;       /* for hint validity checking */
142     return (void *)afile;
143 }
144 #endif
145
146 int
147 afs_osi_Stat(register struct osi_file *afile, register struct osi_stat *astat)
148 {
149     register afs_int32 code;
150     AFS_STATCNT(osi_Stat);
151     MObtainWriteLock(&afs_xosi, 320);
152     astat->size = OSIFILE_INODE(afile)->i_size;
153 #if defined(AFS_LINUX26_ENV)
154     astat->mtime = OSIFILE_INODE(afile)->i_mtime.tv_sec;
155     astat->atime = OSIFILE_INODE(afile)->i_atime.tv_sec;
156 #else
157     astat->mtime = OSIFILE_INODE(afile)->i_mtime;
158     astat->atime = OSIFILE_INODE(afile)->i_atime;
159 #endif
160     code = 0;
161     MReleaseWriteLock(&afs_xosi);
162     return code;
163 }
164
165 #ifdef AFS_LINUX26_ENV
166 int
167 osi_UFSClose(register struct osi_file *afile)
168 {
169     AFS_STATCNT(osi_Close);
170     if (afile) {
171         if (OSIFILE_INODE(afile)) {
172             filp_close(afile->filp, NULL);
173         }
174     }
175
176     osi_FreeLargeSpace(afile);
177     return 0;
178 }
179 #else
180 int
181 osi_UFSClose(register struct osi_file *afile)
182 {
183     AFS_STATCNT(osi_Close);
184     if (afile) {
185         if (FILE_INODE(&afile->file)) {
186             struct file *filp = &afile->file;
187             if (filp->f_op && filp->f_op->release)
188                 filp->f_op->release(FILE_INODE(filp), filp);
189             iput(FILE_INODE(filp));
190         }
191     }
192
193     osi_FreeLargeSpace(afile);
194     return 0;
195 }
196 #endif
197
198 int
199 osi_UFSTruncate(register struct osi_file *afile, afs_int32 asize)
200 {
201     register afs_int32 code;
202     struct osi_stat tstat;
203     struct iattr newattrs;
204     struct inode *inode = OSIFILE_INODE(afile);
205     AFS_STATCNT(osi_Truncate);
206
207     /* This routine only shrinks files, and most systems
208      * have very slow truncates, even when the file is already
209      * small enough.  Check now and save some time.
210      */
211     code = afs_osi_Stat(afile, &tstat);
212     if (code || tstat.size <= asize)
213         return code;
214     MObtainWriteLock(&afs_xosi, 321);
215     AFS_GUNLOCK();
216 #ifdef STRUCT_INODE_HAS_I_ALLOC_SEM
217     down_write(&inode->i_alloc_sem);
218 #endif
219 #ifdef STRUCT_INODE_HAS_I_MUTEX
220     mutex_lock(&inode->i_mutex);
221 #else
222     down(&inode->i_sem);
223 #endif
224     newattrs.ia_size = asize;
225     newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
226 #if defined(AFS_LINUX24_ENV)
227     newattrs.ia_ctime = CURRENT_TIME;
228
229     /* avoid notify_change() since it wants to update dentry->d_parent */
230     lock_kernel();
231     code = inode_change_ok(inode, &newattrs);
232     if (!code)
233 #ifdef INODE_SETATTR_NOT_VOID
234         code = inode_setattr(inode, &newattrs);
235 #else
236         inode_setattr(inode, &newattrs);
237 #endif
238     unlock_kernel();
239     if (!code)
240         truncate_inode_pages(&inode->i_data, asize);
241 #else
242     inode->i_size = asize;
243     if (inode->i_sb->s_op && inode->i_sb->s_op->notify_change) {
244         code = inode->i_sb->s_op->notify_change(&afile->dentry, &newattrs);
245     }
246     if (!code) {
247         truncate_inode_pages(inode, asize);
248         if (inode->i_op && inode->i_op->truncate)
249             inode->i_op->truncate(inode);
250     }
251 #endif
252     code = -code;
253 #ifdef STRUCT_INODE_HAS_I_MUTEX
254     mutex_unlock(&inode->i_mutex);
255 #else
256     up(&inode->i_sem);
257 #endif
258 #ifdef STRUCT_INODE_HAS_I_ALLOC_SEM
259     up_write(&inode->i_alloc_sem);
260 #endif
261     AFS_GLOCK();
262     MReleaseWriteLock(&afs_xosi);
263     return code;
264 }
265
266
267 /* Generic read interface */
268 int
269 afs_osi_Read(register struct osi_file *afile, int offset, void *aptr,
270              afs_int32 asize)
271 {
272     struct uio auio;
273     struct iovec iov;
274     afs_int32 code;
275
276     AFS_STATCNT(osi_Read);
277
278     /*
279      * If the osi_file passed in is NULL, panic only if AFS is not shutting
280      * down. No point in crashing when we are already shutting down
281      */
282     if (!afile) {
283         if (!afs_shuttingdown)
284             osi_Panic("osi_Read called with null param");
285         else
286             return EIO;
287     }
288
289     if (offset != -1)
290         afile->offset = offset;
291     setup_uio(&auio, &iov, aptr, afile->offset, asize, UIO_READ, AFS_UIOSYS);
292     AFS_GUNLOCK();
293     code = osi_rdwr(afile, &auio, UIO_READ);
294     AFS_GLOCK();
295     if (code == 0) {
296         code = asize - auio.uio_resid;
297         afile->offset += code;
298     } else {
299         afs_Trace2(afs_iclSetp, CM_TRACE_READFAILED, ICL_TYPE_INT32, auio.uio_resid,
300                    ICL_TYPE_INT32, code);
301         code = -1;
302     }
303     return code;
304 }
305
306 /* Generic write interface */
307 int
308 afs_osi_Write(register struct osi_file *afile, afs_int32 offset, void *aptr,
309               afs_int32 asize)
310 {
311     struct uio auio;
312     struct iovec iov;
313     afs_int32 code;
314
315     AFS_STATCNT(osi_Write);
316
317     if (!afile) {
318         if (!afs_shuttingdown)
319             osi_Panic("afs_osi_Write called with null param");
320         else
321             return EIO;
322     }
323
324     if (offset != -1)
325         afile->offset = offset;
326     setup_uio(&auio, &iov, aptr, afile->offset, asize, UIO_WRITE, AFS_UIOSYS);
327     AFS_GUNLOCK();
328     code = osi_rdwr(afile, &auio, UIO_WRITE);
329     AFS_GLOCK();
330     if (code == 0) {
331         code = asize - auio.uio_resid;
332         afile->offset += code;
333     } else {
334         if (code == ENOSPC)
335             afs_warnuser
336                 ("\n\n\n*** Cache partition is FULL - Decrease cachesize!!! ***\n\n");
337         code = -1;
338     }
339
340     if (afile->proc)
341         (*afile->proc)(afile, code);
342
343     return code;
344 }
345
346
347 /*  This work should be handled by physstrat in ca/machdep.c.
348     This routine written from the RT NFS port strategy routine.
349     It has been generalized a bit, but should still be pretty clear. */
350 int
351 afs_osi_MapStrategy(int (*aproc) (struct buf * bp), register struct buf *bp)
352 {
353     afs_int32 returnCode;
354
355     AFS_STATCNT(osi_MapStrategy);
356     returnCode = (*aproc) (bp);
357
358     return returnCode;
359 }
360
361 void
362 shutdown_osifile(void)
363 {
364     AFS_STATCNT(shutdown_osifile);
365     if (afs_cold_shutdown) {
366         afs_osicred_initialized = 0;
367     }
368 }
369
370 /* Intialize cache device info and fragment size for disk cache partition. */
371 int
372 osi_InitCacheInfo(char *aname)
373 {
374     int code;
375     struct dentry *dp;
376     extern ino_t cacheInode;
377     extern struct osi_dev cacheDev;
378     extern afs_int32 afs_fsfragsize;
379     extern struct super_block *afs_cacheSBp;
380     extern struct vfsmount *afs_cacheMnt;
381     code = osi_lookupname_internal(aname, 1, &afs_cacheMnt, &dp);
382     if (code)
383         return ENOENT;
384
385     cacheInode = dp->d_inode->i_ino;
386     cacheDev.dev = dp->d_inode->i_sb->s_dev;
387     afs_fsfragsize = dp->d_inode->i_sb->s_blocksize - 1;
388     afs_cacheSBp = dp->d_inode->i_sb;
389
390     dput(dp);
391
392     return 0;
393 }
394
395
396 #define FOP_READ(F, B, C) (F)->f_op->read(F, B, (size_t)(C), &(F)->f_pos)
397 #define FOP_WRITE(F, B, C) (F)->f_op->write(F, B, (size_t)(C), &(F)->f_pos)
398
399 /* osi_rdwr
400  * seek, then read or write to an open inode. addrp points to data in
401  * kernel space.
402  */
403 int
404 osi_rdwr(struct osi_file *osifile, uio_t * uiop, int rw)
405 {
406 #ifdef AFS_LINUX26_ENV
407     struct file *filp = osifile->filp;
408 #else
409     struct file *filp = &osifile->file;
410 #endif
411     KERNEL_SPACE_DECL;
412     int code = 0;
413     struct iovec *iov;
414     afs_size_t count;
415     unsigned long savelim;
416
417     savelim = current->TASK_STRUCT_RLIM[RLIMIT_FSIZE].rlim_cur;
418     current->TASK_STRUCT_RLIM[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY;
419
420     if (uiop->uio_seg == AFS_UIOSYS)
421         TO_USER_SPACE();
422
423     /* seek to the desired position. Return -1 on error. */
424     if (filp->f_op->llseek) {
425         if (filp->f_op->llseek(filp, (loff_t) uiop->uio_offset, 0) != uiop->uio_offset)
426             return -1;
427     } else
428         filp->f_pos = uiop->uio_offset;
429
430     while (code == 0 && uiop->uio_resid > 0 && uiop->uio_iovcnt > 0) {
431         iov = uiop->uio_iov;
432         count = iov->iov_len;
433         if (count == 0) {
434             uiop->uio_iov++;
435             uiop->uio_iovcnt--;
436             continue;
437         }
438
439         if (rw == UIO_READ)
440             code = FOP_READ(filp, iov->iov_base, count);
441         else
442             code = FOP_WRITE(filp, iov->iov_base, count);
443
444         if (code < 0) {
445             code = -code;
446             break;
447         } else if (code == 0) {
448             /*
449              * This is bad -- we can't read any more data from the
450              * file, but we have no good way of signaling a partial
451              * read either.
452              */
453             code = EIO;
454             break;
455         }
456
457         iov->iov_base += code;
458         iov->iov_len -= code;
459         uiop->uio_resid -= code;
460         uiop->uio_offset += code;
461         code = 0;
462     }
463
464     if (uiop->uio_seg == AFS_UIOSYS)
465         TO_KERNEL_SPACE();
466
467     current->TASK_STRUCT_RLIM[RLIMIT_FSIZE].rlim_cur = savelim;
468
469     return code;
470 }
471
472 /* setup_uio 
473  * Setup a uio struct.
474  */
475 void
476 setup_uio(uio_t * uiop, struct iovec *iovecp, const char *buf, afs_offs_t pos,
477           int count, uio_flag_t flag, uio_seg_t seg)
478 {
479     iovecp->iov_base = (char *)buf;
480     iovecp->iov_len = count;
481     uiop->uio_iov = iovecp;
482     uiop->uio_iovcnt = 1;
483     uiop->uio_offset = pos;
484     uiop->uio_seg = seg;
485     uiop->uio_resid = count;
486     uiop->uio_flag = flag;
487 }
488
489
490 /* uiomove
491  * UIO_READ : dp -> uio
492  * UIO_WRITE : uio -> dp
493  */
494 int
495 uiomove(char *dp, int length, uio_flag_t rw, uio_t * uiop)
496 {
497     int count;
498     struct iovec *iov;
499     int code;
500
501     while (length > 0 && uiop->uio_resid > 0 && uiop->uio_iovcnt > 0) {
502         iov = uiop->uio_iov;
503         count = iov->iov_len;
504
505         if (!count) {
506             uiop->uio_iov++;
507             uiop->uio_iovcnt--;
508             continue;
509         }
510
511         if (count > length)
512             count = length;
513
514         switch (uiop->uio_seg) {
515         case AFS_UIOSYS:
516             switch (rw) {
517             case UIO_READ:
518                 memcpy(iov->iov_base, dp, count);
519                 break;
520             case UIO_WRITE:
521                 memcpy(dp, iov->iov_base, count);
522                 break;
523             default:
524                 printf("uiomove: Bad rw = %d\n", rw);
525                 return -EINVAL;
526             }
527             break;
528         case AFS_UIOUSER:
529             switch (rw) {
530             case UIO_READ:
531                 AFS_COPYOUT(dp, iov->iov_base, count, code);
532                 break;
533             case UIO_WRITE:
534                 AFS_COPYIN(iov->iov_base, dp, count, code);
535                 break;
536             default:
537                 printf("uiomove: Bad rw = %d\n", rw);
538                 return -EINVAL;
539             }
540             break;
541         default:
542             printf("uiomove: Bad seg = %d\n", uiop->uio_seg);
543             return -EINVAL;
544         }
545
546         dp += count;
547         length -= count;
548         iov->iov_base += count;
549         iov->iov_len -= count;
550         uiop->uio_offset += count;
551         uiop->uio_resid -= count;
552     }
553     return 0;
554 }
555