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