solaris-ufs-call-updates-20010414
[openafs.git] / src / afs / SOLARIS / osi_inode.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 /*
11  * SOLARIS inode operations
12  *
13  * Implements:
14  *
15  */
16 #include "../afs/param.h"       /* Should be always first */
17 #include "../afs/sysincludes.h" /* Standard vendor system headers */
18 #include "../afs/afsincludes.h" /* Afs-based standard headers */
19 #include "../afs/osi_inode.h"
20 #include "../afs/afs_stats.h" /* statistics stuff */
21
22 extern int (*ufs_iallocp)(), (*ufs_iupdatp)(), (*ufs_igetp)(),
23            (*ufs_itimes_nolockp)();
24
25 #define AFS_ITIMES(ip) { \
26         mutex_enter(&(ip)->i_tlock); \
27         (*ufs_itimes_nolockp)(ip); \
28         mutex_exit(&(ip)->i_tlock); \
29 }
30
31 getinode(vfsp, dev, inode, ipp, credp,perror)
32      struct vfs *vfsp;
33      struct AFS_UCRED *credp;
34      struct inode **ipp;
35      dev_t dev;
36      ino_t inode;
37      int *perror;
38 {
39     struct inode *ip;
40     register afs_int32 code;
41     struct vnode *vp;
42     struct fs *fs;
43     struct inode *pip;
44     struct ufsvfs *ufsvfsp;
45     
46     AFS_STATCNT(getinode);
47     
48     *perror = 0;
49     
50     if (!vfsp 
51 #if !defined(AFS_SUN58_ENV)
52         && !(vfsp = vfs_devsearch(dev))
53 #else
54         && !(vfsp = vfs_dev2vfsp(dev))
55 #endif
56         ) {
57         return (ENODEV);
58     }
59     ufsvfsp = (struct ufsvfs *)vfsp->vfs_data;
60
61     rw_enter(&ufsvfsp->vfs_dqrwlock, RW_READER);
62     code = (*ufs_igetp)(vfsp, inode, &ip, credp);
63     rw_exit(&ufsvfsp->vfs_dqrwlock);
64
65     if (code) {
66         *perror = BAD_IGET;
67         return code;
68     }
69     *ipp = ip;
70     return code;
71 }
72
73 /* get an existing inode.  Common code for iopen, iread/write, iinc/dec. */
74 igetinode(vfsp, dev, inode, ipp, credp,perror)
75      struct AFS_UCRED *credp;
76      struct inode **ipp;
77      struct vfs *vfsp;
78      dev_t dev;
79      ino_t inode;
80      int *perror;
81 {
82     struct inode *pip, *ip;
83     extern struct osi_dev cacheDev;
84     register int code = 0;
85     
86     *perror = 0;
87     
88     AFS_STATCNT(igetinode);
89     
90     code = getinode(vfsp, dev, inode, &ip, credp,perror);
91     if (code) 
92         return code;
93     
94     rw_enter(&ip->i_contents, RW_READER);
95     
96     if (ip->i_mode == 0) {
97         /* Not an allocated inode */
98         AFS_ITIMES(ip);
99         rw_exit(&ip->i_contents);
100         VN_RELE(ITOV(ip));
101         return (ENOENT);
102     }
103     
104     if (ip->i_nlink == 0 || (ip->i_mode&IFMT) != IFREG) {
105         AFS_ITIMES(ip);
106         rw_exit(&ip->i_contents);
107         VN_RELE(ITOV(ip));
108         return (ENOENT);
109     }
110     
111     /* On VFS40 systems, iput does major synchronous write action, but only
112        when the reference count on the vnode goes to 0.  Normally, Sun users
113        don't notice this because the DNLC keep references for them, but we
114        notice 'cause we don't.  So, we make a fake dnlc entry which gets
115        cleaned up by iget when it needs the space. */
116     if (dev != cacheDev.dev) {
117         /* 
118          * Don't call dnlc for the cm inodes since it's a big performance 
119          * penalty there!
120          */
121         dnlc_enter(ITOV(ip), "a", ITOV(ip), (struct AFS_UCRED *) 0);
122     }
123     
124     *ipp = ip;
125     rw_exit(&ip->i_contents);
126     return (code);
127 }
128
129 int CrSync = 1;
130
131 afs_syscall_icreate(dev, near_inode, param1, param2, param3, param4, rvp, credp)
132      rval_t *rvp;
133      struct AFS_UCRED *credp;
134      long near_inode, param1, param2, param3, param4;
135      dev_t dev;
136 {
137     int dummy, err=0;
138     struct inode *ip, *newip;
139     register int code;
140     dev_t newdev;
141     struct ufsvfs *ufsvfsp;
142
143     AFS_STATCNT(afs_syscall_icreate);
144     
145     if (!afs_suser(credp))
146         return (EPERM);
147     
148     /** Code to convert a 32 bit dev_t into a 64 bit dev_t
149       * This conversion is needed only for the 64 bit OS.
150       */
151     
152 #ifdef AFS_SUN57_64BIT_ENV
153     newdev = expldev( (dev32_t) dev);
154 #else
155     newdev = dev;
156 #endif
157
158     code = getinode(0, (dev_t)newdev, 2, &ip, credp,&dummy);
159     if (code) {
160         return (code);
161     }
162
163     ufsvfsp = ip->i_ufsvfs;
164     rw_enter(&ip->i_rwlock, RW_WRITER);
165     rw_enter(&ufsvfsp->vfs_dqrwlock, RW_READER);
166     rw_enter(&ip->i_contents, RW_WRITER);
167     code = (*ufs_iallocp)(ip, near_inode, 0, &newip, credp);
168     rw_exit(&ufsvfsp->vfs_dqrwlock);
169     rw_exit(&ip->i_rwlock);
170
171     AFS_ITIMES(ip);
172     rw_exit(&ip->i_contents);
173     VN_RELE(ITOV(ip));
174
175     if (code) {
176         return (code);
177     }
178     rw_enter(&newip->i_contents, RW_WRITER);
179     mutex_enter(&newip->i_tlock);
180     newip->i_flag |= IACC|IUPD|ICHG;
181     mutex_exit(&newip->i_tlock);
182     
183     
184 #if     defined(AFS_SUN56_ENV)
185     newip->i_vicemagic = VICEMAGIC;
186 #else
187     newip->i_uid = 0;
188     newip->i_gid = -2;
189 #endif
190     newip->i_nlink = 1;
191     newip->i_mode = IFREG;
192     newip->i_vnode.v_type = VREG;
193     
194     newip->i_vicep1 = param1;
195     if (param2 == 0x1fffffff/*INODESPECIAL*/)   {
196         newip->i_vicep2 = ((0x1fffffff << 3) + (param4 & 0x3));
197         newip->i_vicep3 = param3;
198     } else {
199         newip->i_vicep2 = (((param2 >> 16) & 0x1f) << 27) +
200             (((param4 >> 16) & 0x1f) << 22) + 
201                 (param3 & 0x3fffff);        
202         newip->i_vicep3 = ((param4 << 16) + (param2 & 0xffff));
203     }
204 #ifdef AFS_SUN57_64BIT_ENV
205     rvp->r_vals = newip->i_number;
206 #else
207     rvp->r_val1 = newip->i_number;
208 #endif
209     
210     /* 
211      * We're being conservative and sync to the disk
212      */
213     if (CrSync)
214         (*ufs_iupdatp)(newip, 1);
215     AFS_ITIMES(newip);
216     rw_exit(&newip->i_contents);
217     VN_RELE(ITOV(newip));
218     return (code);
219 }
220
221 afs_syscall_iopen(dev, inode, usrmod, rvp, credp)
222      rval_t *rvp;
223      struct AFS_UCRED *credp;
224      int  inode, usrmod;
225      dev_t dev;
226 {
227     struct file *fp;
228     struct inode *ip;
229     struct vnode *vp = (struct vnode *)0;
230     int dummy;
231     int fd;
232     register int code;
233     dev_t newdev;
234
235     AFS_STATCNT(afs_syscall_iopen);
236
237     if (!afs_suser(credp))
238         return (EPERM);
239
240     /** Code to convert a 32 bit dev_t into a 64 bit dev_t
241       * This conversion is needed only for the 64 bit OS.
242       */
243     
244 #ifdef AFS_SUN57_64BIT_ENV
245     newdev = expldev( (dev32_t) dev);
246 #else
247     newdev = dev;
248 #endif
249
250     code = igetinode(0, (dev_t)newdev, (ino_t)inode, &ip, credp,&dummy);
251     if (code) {
252         return (code);
253     }
254     code = falloc((struct vnode *)NULL, FWRITE|FREAD, &fp, &fd);
255     if (code) {
256         rw_enter(&ip->i_contents, RW_READER);
257         AFS_ITIMES(ip);
258         rw_exit(&ip->i_contents);
259         VN_RELE(ITOV(ip));
260         return (code);
261     }
262     
263     /* fp->f_count, f_audit_data are set by falloc */
264     fp->f_vnode = ITOV(ip);
265     
266     fp->f_flag = (usrmod+1) & (FMASK);
267     
268     /* fp->f_count, f_msgcount are set by falloc */
269     
270     /* fp->f_offset zeroed by falloc */
271     /* f_cred set by falloc */
272     /*
273      * falloc returns the fp write locked 
274      */
275     mutex_exit(&fp->f_tlock);
276     /*
277      * XXX We should set the fp to null since we don't need it in the icalls
278      */
279     setf(fd, fp);
280 #ifdef AFS_SUN57_64BIT_ENV
281     rvp->r_val2 = fd;
282 #else
283     rvp->r_val1 = fd;
284 #endif
285
286     return code;
287 }
288
289 int IncSync = 1;
290
291 afs_syscall_iincdec(dev, inode, inode_p1, amount, rvp, credp)
292      rval_t *rvp;
293      struct AFS_UCRED *credp;
294      int inode, inode_p1, amount;
295      dev_t dev;
296 {
297     int dummy;
298     struct inode *ip;
299     register afs_int32 code;
300     dev_t newdev;
301
302     if (!afs_suser(credp))
303         return (EPERM);
304
305         /** Code to convert a 32 bit dev_t into a 64 bit dev_t
306       * This conversion is needed only for the 64 bit OS.
307       */
308     
309 #ifdef AFS_SUN57_64BIT_ENV
310     newdev = expldev( (dev32_t) dev);
311 #else
312     newdev = dev;
313 #endif
314
315     code = igetinode(0, (dev_t)newdev, (ino_t)inode, &ip, credp,&dummy);
316     if (code) {
317         return (code);
318     }
319     if (!IS_VICEMAGIC(ip)) {
320         code = EPERM;
321         rw_enter(&ip->i_contents, RW_READER);
322         AFS_ITIMES(ip);
323         rw_exit(&ip->i_contents);
324         VN_RELE(ITOV(ip));
325     } else {
326         rw_enter(&ip->i_contents, RW_WRITER);
327         ip->i_nlink += amount;
328         if (ip->i_nlink == 0) {
329             /* remove the "a" name added by igetinode so that the space is reclaimed. */
330             dnlc_remove(ITOV(ip), "a");
331             CLEAR_VICEMAGIC(ip);
332         }
333         mutex_enter(&ip->i_tlock);
334         ip->i_flag |= ICHG;
335         mutex_exit(&ip->i_tlock);
336         /* We may want to force the inode to the disk in case of crashes, other references, etc. */
337         if (IncSync)
338             (*ufs_iupdatp)(ip, 1);
339         AFS_ITIMES(ip);
340         rw_exit(&ip->i_contents);
341         VN_RELE(ITOV(ip));
342     }
343     return (code);
344 }
345