solaris-detect-kernel-dqrwlock-20010712
[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 <afsconfig.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         AFS_ITIMES(ip);
110         rw_exit(&ip->i_contents);
111         VN_RELE(ITOV(ip));
112         return (ENOENT);
113     }
114     
115     if (ip->i_nlink == 0 || (ip->i_mode&IFMT) != IFREG) {
116         AFS_ITIMES(ip);
117         rw_exit(&ip->i_contents);
118         VN_RELE(ITOV(ip));
119         return (ENOENT);
120     }
121     
122     /* On VFS40 systems, iput does major synchronous write action, but only
123        when the reference count on the vnode goes to 0.  Normally, Sun users
124        don't notice this because the DNLC keep references for them, but we
125        notice 'cause we don't.  So, we make a fake dnlc entry which gets
126        cleaned up by iget when it needs the space. */
127     if (dev != cacheDev.dev) {
128         /* 
129          * Don't call dnlc for the cm inodes since it's a big performance 
130          * penalty there!
131          */
132         dnlc_enter(ITOV(ip), "a", ITOV(ip), (struct AFS_UCRED *) 0);
133     }
134     
135     *ipp = ip;
136     rw_exit(&ip->i_contents);
137     return (code);
138 }
139
140 int CrSync = 1;
141
142 afs_syscall_icreate(dev, near_inode, param1, param2, param3, param4, rvp, credp)
143      rval_t *rvp;
144      struct AFS_UCRED *credp;
145      long near_inode, param1, param2, param3, param4;
146      dev_t dev;
147 {
148     int dummy, err=0;
149     struct inode *ip, *newip;
150     register int code;
151     dev_t newdev;
152     struct ufsvfs *ufsvfsp;
153
154     AFS_STATCNT(afs_syscall_icreate);
155     
156     if (!afs_suser(credp))
157         return (EPERM);
158     
159     /** Code to convert a 32 bit dev_t into a 64 bit dev_t
160       * This conversion is needed only for the 64 bit OS.
161       */
162     
163 #ifdef AFS_SUN57_64BIT_ENV
164     newdev = expldev( (dev32_t) dev);
165 #else
166     newdev = dev;
167 #endif
168
169     code = getinode(0, (dev_t)newdev, 2, &ip, credp,&dummy);
170     if (code) {
171         return (code);
172     }
173
174     ufsvfsp = ip->i_ufsvfs;
175     rw_enter(&ip->i_rwlock, RW_WRITER);
176 #ifdef HAVE_VFS_DQRWLOCK
177     rw_enter(&ufsvfsp->vfs_dqrwlock, RW_READER);
178 #endif
179     rw_enter(&ip->i_contents, RW_WRITER);
180     code = (*ufs_iallocp)(ip, near_inode, 0, &newip, credp);
181     AFS_ITIMES_NOLOCK(ip);
182     rw_exit(&ip->i_contents);
183 #ifdef HAVE_VFS_DQRWLOCK
184     rw_exit(&ufsvfsp->vfs_dqrwlock);
185 #endif
186     rw_exit(&ip->i_rwlock);
187     VN_RELE(ITOV(ip));
188
189     if (code) {
190         return (code);
191     }
192     rw_enter(&newip->i_contents, RW_WRITER);
193     newip->i_flag |= IACC|IUPD|ICHG;
194
195 #if     defined(AFS_SUN56_ENV)
196     newip->i_vicemagic = VICEMAGIC;
197 #else
198     newip->i_uid = 0;
199     newip->i_gid = -2;
200 #endif
201     newip->i_nlink = 1;
202     newip->i_mode = IFREG;
203     newip->i_vnode.v_type = VREG;
204     
205     newip->i_vicep1 = param1;
206     if (param2 == 0x1fffffff/*INODESPECIAL*/)   {
207         newip->i_vicep2 = ((0x1fffffff << 3) + (param4 & 0x3));
208         newip->i_vicep3 = param3;
209     } else {
210         newip->i_vicep2 = (((param2 >> 16) & 0x1f) << 27) +
211             (((param4 >> 16) & 0x1f) << 22) + 
212                 (param3 & 0x3fffff);        
213         newip->i_vicep3 = ((param4 << 16) + (param2 & 0xffff));
214     }
215 #ifdef AFS_SUN57_64BIT_ENV
216     rvp->r_vals = newip->i_number;
217 #else
218     rvp->r_val1 = newip->i_number;
219 #endif
220     
221     /* 
222      * We're being conservative and sync to the disk
223      */
224     if (CrSync)
225         (*ufs_iupdatp)(newip, 1);
226     AFS_ITIMES_NOLOCK(newip);
227     rw_exit(&newip->i_contents);
228     VN_RELE(ITOV(newip));
229     return (code);
230 }
231
232 afs_syscall_iopen(dev, inode, usrmod, rvp, credp)
233      rval_t *rvp;
234      struct AFS_UCRED *credp;
235      int  inode, usrmod;
236      dev_t dev;
237 {
238     struct file *fp;
239     struct inode *ip;
240     struct vnode *vp = (struct vnode *)0;
241     int dummy;
242     int fd;
243     register int code;
244     dev_t newdev;
245
246     AFS_STATCNT(afs_syscall_iopen);
247
248     if (!afs_suser(credp))
249         return (EPERM);
250
251     /** Code to convert a 32 bit dev_t into a 64 bit dev_t
252       * This conversion is needed only for the 64 bit OS.
253       */
254     
255 #ifdef AFS_SUN57_64BIT_ENV
256     newdev = expldev( (dev32_t) dev);
257 #else
258     newdev = dev;
259 #endif
260
261     code = igetinode(0, (dev_t)newdev, (ino_t)inode, &ip, credp,&dummy);
262     if (code) {
263         return (code);
264     }
265     code = falloc((struct vnode *)NULL, FWRITE|FREAD, &fp, &fd);
266     if (code) {
267         rw_enter(&ip->i_contents, RW_READER);
268         AFS_ITIMES(ip);
269         rw_exit(&ip->i_contents);
270         VN_RELE(ITOV(ip));
271         return (code);
272     }
273     
274     /* fp->f_count, f_audit_data are set by falloc */
275     fp->f_vnode = ITOV(ip);
276     
277     fp->f_flag = (usrmod+1) & (FMASK);
278     
279     /* fp->f_count, f_msgcount are set by falloc */
280     
281     /* fp->f_offset zeroed by falloc */
282     /* f_cred set by falloc */
283     /*
284      * falloc returns the fp write locked 
285      */
286     mutex_exit(&fp->f_tlock);
287     /*
288      * XXX We should set the fp to null since we don't need it in the icalls
289      */
290     setf(fd, fp);
291 #ifdef AFS_SUN57_64BIT_ENV
292     rvp->r_val2 = fd;
293 #else
294     rvp->r_val1 = fd;
295 #endif
296
297     return code;
298 }
299
300 int IncSync = 1;
301
302 afs_syscall_iincdec(dev, inode, inode_p1, amount, rvp, credp)
303      rval_t *rvp;
304      struct AFS_UCRED *credp;
305      int inode, inode_p1, amount;
306      dev_t dev;
307 {
308     int dummy;
309     struct inode *ip;
310     register afs_int32 code;
311     dev_t newdev;
312
313     if (!afs_suser(credp))
314         return (EPERM);
315
316         /** Code to convert a 32 bit dev_t into a 64 bit dev_t
317       * This conversion is needed only for the 64 bit OS.
318       */
319     
320 #ifdef AFS_SUN57_64BIT_ENV
321     newdev = expldev( (dev32_t) dev);
322 #else
323     newdev = dev;
324 #endif
325
326     code = igetinode(0, (dev_t)newdev, (ino_t)inode, &ip, credp,&dummy);
327     if (code) {
328         return (code);
329     }
330     if (!IS_VICEMAGIC(ip)) {
331         code = EPERM;
332         rw_enter(&ip->i_contents, RW_READER);
333         AFS_ITIMES(ip);
334         rw_exit(&ip->i_contents);
335         VN_RELE(ITOV(ip));
336     } else {
337         rw_enter(&ip->i_contents, RW_WRITER);
338         ip->i_nlink += amount;
339         if (ip->i_nlink == 0) {
340             /* remove the "a" name added by igetinode so that the space is reclaimed. */
341             dnlc_remove(ITOV(ip), "a");
342             CLEAR_VICEMAGIC(ip);
343         }
344         ip->i_flag |= ICHG;
345         /* We may want to force the inode to the disk in case of crashes, other references, etc. */
346         if (IncSync)
347             (*ufs_iupdatp)(ip, 1);
348         AFS_ITIMES_NOLOCK(ip);
349         rw_exit(&ip->i_contents);
350         VN_RELE(ITOV(ip));
351     }
352     return (code);
353 }
354