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