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