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