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