linux-fmode-set-20050418
[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
24
25 int afs_osicred_initialized = 0;
26 struct AFS_UCRED afs_osi_cred;
27 afs_lock_t afs_xosi;            /* lock is for tvattr */
28 extern struct osi_dev cacheDev;
29 extern struct super_block *afs_cacheSBp;
30
31 void *
32 osi_UFSOpen(afs_int32 ainode)
33 {
34     register struct osi_file *afile = NULL;
35     extern int cacheDiskType;
36     afs_int32 code = 0;
37     struct inode *tip = NULL;
38     struct file *filp = NULL;
39     AFS_STATCNT(osi_UFSOpen);
40     if (cacheDiskType != AFS_FCACHE_TYPE_UFS) {
41         osi_Panic("UFSOpen called for non-UFS cache\n");
42     }
43     if (!afs_osicred_initialized) {
44         /* valid for alpha_osf, SunOS, Ultrix */
45         memset((char *)&afs_osi_cred, 0, sizeof(struct AFS_UCRED));
46         crhold(&afs_osi_cred);  /* don't let it evaporate, since it is static */
47         afs_osicred_initialized = 1;
48     }
49     afile = (struct osi_file *)osi_AllocLargeSpace(sizeof(struct osi_file));
50     AFS_GUNLOCK();
51     if (!afile) {
52         osi_Panic("osi_UFSOpen: Failed to allocate %d bytes for osi_file.\n",
53                   sizeof(struct osi_file));
54     }
55     memset(afile, 0, sizeof(struct osi_file));
56     filp = &afile->file;
57     filp->f_dentry = &afile->dentry;
58     tip = iget(afs_cacheSBp, (u_long) ainode);
59     if (!tip)
60         osi_Panic("Can't get inode %d\n", ainode);
61     FILE_INODE(filp) = tip;
62     tip->i_flags |= MS_NOATIME; /* Disable updating access times. */
63     filp->f_flags = O_RDWR;
64 #if defined(AFS_LINUX26_ENV)
65     filp->f_mapping = tip->i_mapping;
66 #endif
67 #if defined(AFS_LINUX24_ENV)
68     filp->f_mode = FMODE_READ|FMODE_WRITE;
69     filp->f_op = fops_get(tip->i_fop);
70 #else
71     filp->f_op = tip->i_op->default_file_ops;
72 #endif
73     if (filp->f_op && filp->f_op->open)
74         code = filp->f_op->open(tip, filp);
75     if (code)
76         osi_Panic("Can't open inode %d\n", ainode);
77     afile->size = tip->i_size;
78     AFS_GLOCK();
79     afile->offset = 0;
80     afile->proc = (int (*)())0;
81     afile->inum = ainode;       /* for hint validity checking */
82     return (void *)afile;
83 }
84
85 int
86 afs_osi_Stat(register struct osi_file *afile, register struct osi_stat *astat)
87 {
88     register afs_int32 code;
89     AFS_STATCNT(osi_Stat);
90     MObtainWriteLock(&afs_xosi, 320);
91     astat->size = FILE_INODE(&afile->file)->i_size;
92     astat->blksize = FILE_INODE(&afile->file)->i_blksize;
93 #if defined(AFS_LINUX26_ENV)
94     astat->mtime = FILE_INODE(&afile->file)->i_mtime.tv_sec;
95     astat->atime = FILE_INODE(&afile->file)->i_atime.tv_sec;
96 #else
97     astat->mtime = FILE_INODE(&afile->file)->i_mtime;
98     astat->atime = FILE_INODE(&afile->file)->i_atime;
99 #endif
100     code = 0;
101     MReleaseWriteLock(&afs_xosi);
102     return code;
103 }
104
105 int
106 osi_UFSClose(register struct osi_file *afile)
107 {
108     AFS_STATCNT(osi_Close);
109     if (afile) {
110         if (FILE_INODE(&afile->file)) {
111             struct file *filp = &afile->file;
112             if (filp->f_op && filp->f_op->release)
113                 filp->f_op->release(FILE_INODE(filp), filp);
114             iput(FILE_INODE(filp));
115         }
116     }
117
118     osi_FreeLargeSpace(afile);
119     return 0;
120 }
121
122 int
123 osi_UFSTruncate(register struct osi_file *afile, afs_int32 asize)
124 {
125     register afs_int32 code;
126     struct osi_stat tstat;
127     struct iattr newattrs;
128     struct inode *inode = FILE_INODE(&afile->file);
129     AFS_STATCNT(osi_Truncate);
130
131     /* This routine only shrinks files, and most systems
132      * have very slow truncates, even when the file is already
133      * small enough.  Check now and save some time.
134      */
135     code = afs_osi_Stat(afile, &tstat);
136     if (code || tstat.size <= asize)
137         return code;
138     MObtainWriteLock(&afs_xosi, 321);
139     AFS_GUNLOCK();
140 #ifdef STRUCT_INODE_HAS_I_ALLOC_SEM
141     down_write(&inode->i_alloc_sem);
142 #endif
143     down(&inode->i_sem);
144     newattrs.ia_size = asize;
145     newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
146 #if defined(AFS_LINUX24_ENV)
147     newattrs.ia_ctime = CURRENT_TIME;
148
149     /* avoid notify_change() since it wants to update dentry->d_parent */
150     lock_kernel();
151     code = inode_change_ok(inode, &newattrs);
152     if (!code)
153 #ifdef INODE_SETATTR_NOT_VOID
154         code = inode_setattr(inode, &newattrs);
155 #else
156         inode_setattr(inode, &newattrs);
157 #endif
158     unlock_kernel();
159     if (!code)
160         truncate_inode_pages(&inode->i_data, asize);
161 #else
162     inode->i_size = asize;
163     if (inode->i_sb->s_op && inode->i_sb->s_op->notify_change) {
164         code = inode->i_sb->s_op->notify_change(&afile->dentry, &newattrs);
165     }
166     if (!code) {
167         truncate_inode_pages(inode, asize);
168         if (inode->i_op && inode->i_op->truncate)
169             inode->i_op->truncate(inode);
170     }
171 #endif
172     code = -code;
173     up(&inode->i_sem);
174 #ifdef STRUCT_INODE_HAS_I_ALLOC_SEM
175     up_write(&inode->i_alloc_sem);
176 #endif
177     AFS_GLOCK();
178     MReleaseWriteLock(&afs_xosi);
179     return code;
180 }
181
182
183 /* Generic read interface */
184 int
185 afs_osi_Read(register struct osi_file *afile, int offset, void *aptr,
186              afs_int32 asize)
187 {
188     size_t resid;
189     register afs_int32 code;
190     AFS_STATCNT(osi_Read);
191
192     /**
193       * If the osi_file passed in is NULL, panic only if AFS is not shutting
194       * down. No point in crashing when we are already shutting down
195       */
196     if (!afile) {
197         if (!afs_shuttingdown)
198             osi_Panic("osi_Read called with null param");
199         else
200             return EIO;
201     }
202
203     if (offset != -1)
204         afile->offset = offset;
205     AFS_GUNLOCK();
206     code = osi_rdwr(UIO_READ, afile, (caddr_t) aptr, asize, &resid);
207     AFS_GLOCK();
208     if (code == 0) {
209         code = asize - resid;
210         afile->offset += code;
211     } else {
212         afs_Trace2(afs_iclSetp, CM_TRACE_READFAILED, ICL_TYPE_INT32, resid,
213                    ICL_TYPE_INT32, code);
214         code = -1;
215     }
216     return code;
217 }
218
219 /* Generic write interface */
220 int
221 afs_osi_Write(register struct osi_file *afile, afs_int32 offset, void *aptr,
222               afs_int32 asize)
223 {
224     size_t resid;
225     register afs_int32 code;
226     AFS_STATCNT(osi_Write);
227     if (!afile) {
228         if (!afs_shuttingdown)
229             osi_Panic("afs_osi_Write called with null param");
230         else
231             return EIO;
232     }
233     if (offset != -1)
234         afile->offset = offset;
235     AFS_GUNLOCK();
236     code = osi_rdwr(UIO_WRITE, afile, (caddr_t) aptr, asize, &resid);
237     AFS_GLOCK();
238     if (code == 0) {
239         code = asize - resid;
240         afile->offset += code;
241     } else {
242         if (code == ENOSPC)
243             afs_warnuser
244                 ("\n\n\n*** Cache partition is FULL - Decrease cachesize!!! ***\n\n");
245         code = -1;
246     }
247     if (afile->proc) {
248         (*afile->proc) (afile, code);
249     }
250     return code;
251 }
252
253
254 /*  This work should be handled by physstrat in ca/machdep.c.
255     This routine written from the RT NFS port strategy routine.
256     It has been generalized a bit, but should still be pretty clear. */
257 int
258 afs_osi_MapStrategy(int (*aproc) (struct buf * bp), register struct buf *bp)
259 {
260     afs_int32 returnCode;
261
262     AFS_STATCNT(osi_MapStrategy);
263     returnCode = (*aproc) (bp);
264
265     return returnCode;
266 }
267
268 void
269 shutdown_osifile(void)
270 {
271     extern int afs_cold_shutdown;
272
273     AFS_STATCNT(shutdown_osifile);
274     if (afs_cold_shutdown) {
275         afs_osicred_initialized = 0;
276     }
277 }