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