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