0319b33b13df6c3127c554bfb58a65b93ed47ef5
[openafs.git] / src / afs / IRIX / 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  * IRIX inode operations
12  *
13  * Implements:
14  * afsdptoip
15  * afsiptodp
16  * afsidestroy
17  * getinode
18  * igetinode
19  * xfs_getinode
20  * xfs_igetinode
21  * icreate
22  * afs_syscall_icreate
23  * xfs_icreatename64
24  * afs_syscall_icreatename64
25  * iopenargs64
26  * afs_syscall_iopen
27  * iopen
28  * iopen64
29  * efs_iincdec
30  * xfs_iincdec64
31  * iincdec64
32  * afs_syscall_idec64
33  * afs_syscall_iinc64
34  * iincdec
35  * iinc
36  * idec
37  * afs_syscall_iincdec
38  * afs_syscall_ilistinode64
39  *
40  */
41
42 #include <afsconfig.h>
43 #include "afs/param.h"
44
45
46 #include "afs/sysincludes.h"    /* Standard vendor system headers */
47 #include "afsincludes.h"        /* Afs-based standard headers */
48 #include "afs/osi_inode.h"
49 #include "afs/afs_stats.h"      /* statistics stuff */
50
51 #define BAD_IGET        -1000
52
53 /*
54  * SGI dependent system calls
55  */
56 #ifndef INODESPECIAL
57 /*
58  * `INODESPECIAL' type inodes are ones that describe volumes.
59  */
60 #define INODESPECIAL    0xffffffff      /* ... from ../vol/viceinode.h  */
61 #endif
62 /*
63  * copy disk inode to incore inode and vice-versa
64  */
65 void
66 afsdptoip(struct efs_dinode *dp, struct inode *ip)
67 {
68     struct afsparms *ap;
69
70     ip->i_afs = kmem_alloc(sizeof(struct afsparms), KM_SLEEP);
71     osi_Assert(ip->i_version == EFS_IVER_AFSSPEC
72                || ip->i_version == EFS_IVER_AFSINO);
73     ap = (struct afsparms *)ip->i_afs;
74     /* vicep1 is VOLid */
75     ap->vicep1 =
76         dmag(dp, 0) << 24 | dmag(dp, 1) << 16 | dmag(dp, 2) << 8 | dmag(dp,
77                                                                         3) <<
78         0;
79
80     if (ip->i_version == EFS_IVER_AFSSPEC) {
81         ap->vicep3 = dmag(dp, 8);       /* Type */
82         ap->vicep4 =
83             dmag(dp, 4) << 24 | dmag(dp, 5) << 16 | dmag(dp,
84                                                          6) << 8 | dmag(dp,
85                                                                         7) <<
86             0;
87
88     } else {
89         /* vnode number */
90         ap->vicep2 = dmag(dp, 4) << 16 | dmag(dp, 5) << 8 | dmag(dp, 6) << 0;
91         /* disk uniqifier */
92         ap->vicep3 = dmag(dp, 7) << 16 | dmag(dp, 8) << 8 | dmag(dp, 9) << 0;
93         /* data version */
94         ap->vicep4 = dmag(dp, 10) << 16 | dmag(dp, 11) << 8 | (dp)->di_spare;
95     }
96 }
97
98 void
99 afsiptodp(struct inode *ip, struct efs_dinode *dp)
100 {
101     struct afsparms *ap;
102
103     if (ip->i_afs == NULL)
104         return;
105
106     osi_Assert(ip->i_version == EFS_IVER_AFSSPEC
107                || ip->i_version == EFS_IVER_AFSINO);
108     ap = (struct afsparms *)ip->i_afs;
109     /* vicep1 is VOLid */
110     dmag(dp, 0) = ap->vicep1 >> 24;
111     dmag(dp, 1) = ap->vicep1 >> 16;
112     dmag(dp, 2) = ap->vicep1 >> 8;
113     dmag(dp, 3) = ap->vicep1 >> 0;
114
115     if (ip->i_version == EFS_IVER_AFSSPEC) {
116         /* Type */
117         dmag(dp, 8) = ap->vicep3;
118         /* ParentId */
119         dmag(dp, 4) = ap->vicep4 >> 24;
120         dmag(dp, 5) = ap->vicep4 >> 16;
121         dmag(dp, 6) = ap->vicep4 >> 8;
122         dmag(dp, 7) = ap->vicep4 >> 0;
123     } else {
124         /* vnode number */
125         dmag(dp, 4) = ap->vicep2 >> 16;
126         dmag(dp, 5) = ap->vicep2 >> 8;
127         dmag(dp, 6) = ap->vicep2 >> 0;
128         /* disk uniqifier */
129         dmag(dp, 7) = ap->vicep3 >> 16;
130         dmag(dp, 8) = ap->vicep3 >> 8;
131         dmag(dp, 9) = ap->vicep3 >> 0;
132         /* data version */
133         dmag(dp, 10) = ap->vicep4 >> 16;
134         dmag(dp, 11) = ap->vicep4 >> 8;
135         dp->di_spare = ap->vicep4 >> 0;
136     }
137 }
138
139 void
140 afsidestroy(struct inode *ip)
141 {
142     if (ip->i_afs) {
143         kmem_free(ip->i_afs, sizeof(struct afsparms));
144         ip->i_afs = NULL;
145     }
146 }
147
148 extern int efs_fstype;
149 #ifdef AFS_SGI_XFS_IOPS_ENV
150 extern int xfs_fstype;
151 #endif
152
153 int
154 getinode(struct vfs *vfsp, dev_t dev, ino_t inode, struct inode **ipp)
155 {
156     struct inode *ip;
157     int error;
158
159     if (!vfsp) {
160 #ifdef AFS_SGI65_ENV
161         vfsp = vfs_devsearch(dev, efs_fstype);
162 #else
163         vfsp = vfs_devsearch(dev);
164 #endif
165         if (!vfsp) {
166             return ENXIO;
167         }
168     }
169 #ifndef AFS_SGI65_ENV
170     if (vfsp->vfs_fstype != efs_fstype)
171         return ENOSYS;
172 #endif
173
174     if (error =
175         iget((((struct mount *)((vfsp)->vfs_bh.bh_first)->bd_pdata)),
176              (unsigned int)(inode & 0xffffffff), &ip)) {
177         return error;
178     }
179     *ipp = ip;
180     return 0;
181 }
182
183 int
184 igetinode(struct vfs *vfsp, dev_t dev, ino_t inode, struct inode **ipp)
185 {
186     struct inode *ip;
187     int error;
188
189     AFS_STATCNT(igetinode);
190     if (error = getinode(vfsp, dev, inode, &ip))
191         return error;
192     *ipp = ip;
193     return 0;
194 }
195
196 int XFS_IGET_EPOS;
197 ino_t XFS_IGET_INO;
198 dev_t XFS_IGET_DEV;
199 #define SET_XFS_ERROR(POS, DEV, INO) \
200         XFS_IGET_EPOS = (POS), XFS_IGET_DEV = (DEV), XFS_IGET_INO = (INO)
201
202 int
203 xfs_getinode(struct vfs *vfsp, dev_t dev, ino_t inode, struct xfs_inode **ipp)
204 {
205     struct xfs_inode *ip;
206     int error;
207
208     if (!vfsp) {
209 #ifdef AFS_SGI65_ENV
210         vfsp = vfs_devsearch(dev, xfs_fstype);
211 #else
212         vfsp = vfs_devsearch(dev);
213 #endif
214         if (!vfsp) {
215             SET_XFS_ERROR(1, dev, inode);
216             return ENXIO;
217         }
218     }
219 #ifndef AFS_SGI65_ENV
220     if (vfsp->vfs_fstype != xfs_fstype) {
221         SET_XFS_ERROR(2, vfsp->vfs_dev, inode);
222         return ENOSYS;
223     }
224 #endif
225
226     if (error = xfs_iget((((struct mount *)
227                            ((vfsp)->vfs_bh.bh_first)->bd_pdata)), (void *)0,
228                          (xfs_ino_t) inode, XFS_ILOCK_SHARED, &ip,
229                          (daddr_t) 0)) {
230         SET_XFS_ERROR(3, vfsp->vfs_dev, inode);
231         return error;
232     }
233
234     *ipp = ip;
235     return 0;
236 }
237
238 /* xfs_igetinode now returns an unlocked inode. This is fine, since we
239  * have a refcount on the holding vnode.
240  */
241 int
242 xfs_igetinode(struct vfs *vfsp, dev_t dev, ino_t inode,
243               struct xfs_inode **ipp)
244 {
245     struct xfs_inode *ip;
246     vnode_t *vp;
247     vattr_t vattr;
248     int error;
249
250     AFS_STATCNT(igetinode);
251
252     *ipp = NULL;
253     if (error = xfs_getinode(vfsp, dev, inode, &ip)) {
254         return error;
255     }
256
257     xfs_iunlock(ip, XFS_ILOCK_SHARED);
258     vp = XFS_ITOV(ip);
259     vattr.va_mask = AT_STAT;
260     AFS_VOP_GETATTR(vp, &vattr, 0, OSI_GET_CURRENT_CRED(), error);
261     if (error) {
262         SET_XFS_ERROR(4, vp->v_vfsp->vfs_dev, inode);
263         VN_RELE(vp);
264         return error;
265     }
266     if (vattr.va_nlink == 0 || vattr.va_type != VREG) {
267         SET_XFS_ERROR(5, vp->v_vfsp->vfs_dev, inode);
268         VN_RELE(vp);
269         return ENOENT;
270     }
271
272     *ipp = ip;
273     return 0;
274 }
275
276 /**************************************************************************
277  * inode creation routines.
278  *
279  ***************************************************************************/
280 struct icreateargs {
281     sysarg_t dev;
282     sysarg_t near_inode;
283     sysarg_t param1;
284     sysarg_t param2;
285     sysarg_t param3;
286     sysarg_t param4;
287 };
288
289 /* EFS only fs suite uses this entry point - icreate in afssyscalls.c. */
290 int
291 icreate(struct icreateargs *uap, rval_t * rvp)
292 {
293     return ENOSYS;
294 }
295
296 int
297 afs_syscall_icreate(dev, near_inode, param1, param2, param3, param4, rvp)
298      afs_uint32 dev, near_inode, param1, param2, param3, param4;
299      rval_t *rvp;
300 {
301     return ENOSYS;
302 }
303
304 #ifdef AFS_SGI_XFS_IOPS_ENV
305 /* inode creation routines for icreatename64 entry point. Use for EFS/XFS
306  * fileserver suite.  For XFS, create a name in the namespace as well as the
307  * inode. For EFS, just call the original routine.
308  */
309
310 #include <afs/xfsattrs.h>
311 #include <sys/attributes.h>
312
313 extern char *int_to_base64(char *, int);
314
315 /* Lock against races creating/removing directory - vos zap RO, vos create RW*/
316 kmutex_t afs_vol_create_lock;
317 int afs_vol_create_lock_inited = 0;
318 #define AFS_LOCK_VOL_CREATE() { \
319         if (!afs_vol_create_lock_inited) { \
320             mutex_init(&afs_vol_create_lock, MUTEX_DEFAULT, \
321                        "afs_vol_create_lock"); \
322             afs_vol_create_lock_inited = 1; \
323         } \
324         mutex_enter(&afs_vol_create_lock); \
325                                  }
326 #define AFS_UNLOCK_VOL_CREATE() mutex_exit(&afs_vol_create_lock)
327
328
329 /* xfs_icreatename64
330  * Create an AFS inode in the XFS name space. If required create the proper
331  * containing directory. See sys/xfsattrs.h for the details on the naming
332  * conventions and the usage of file and directory attributes.
333  *
334  * The inode parameters are stored in an XFS attribute called "AFS". In
335  * addition gid is set to XFS_VICEMAGIC and uid is set to the low 31 bits
336  * of the RW volume id. This is so inode verification in iinc and idec
337  * don't need to get the attribute. Note that only the low 31 bits are set.
338  * This is because chmod only accepts up to MAX_UID and chmod is used
339  * to correct these values in xfs_ListViceInodes.
340  */
341 int
342 xfs_icreatename64(struct vfs *vfsp, int datap, int datalen,
343                   afs_inode_params_t params, ino_t * inop)
344 {
345 #define AFS_PNAME_SIZE 16
346     char path[64];
347     char name[64];
348     b64_string_t stmp1, stmp2;
349     afs_xfs_attr_t attrs;
350     struct vattr vattr;
351     int name_version = AFS_XFS_NAME_VERS;
352     int code = 0, unused;
353     struct vnode *vp;
354     struct vnode *dvp;
355     int rw_vno;                 /* volume ID of parent volume */
356     int i;
357     int createdDir = 0;
358     size_t junk;
359     char *s;
360
361
362     /* Get vnode for directory which will contain new inode. */
363     if (datalen >= AFS_PNAME_SIZE)
364         return E2BIG;
365
366     AFS_COPYINSTR((char *)datap, path, AFS_PNAME_SIZE - 1, &junk, unused);
367     if (*path != '/') {
368         return EINVAL;
369     }
370
371     rw_vno = (params[1] == INODESPECIAL) ? params[3] : params[0];
372
373     /* directory name */
374     strcat(path, "/");
375     strcat(path, AFS_INODE_DIR_NAME);
376     strcat(path, int_to_base64(stmp1, rw_vno));
377
378     if (params[1] == INODESPECIAL)
379         AFS_LOCK_VOL_CREATE();
380
381     code = gop_lookupname(path, AFS_UIOSYS, FOLLOW, &dvp);
382     if (code == ENOENT) {
383         /* Maybe it's an old directory name format. */
384         AFS_COPYINSTR((char *)datap, name, AFS_PNAME_SIZE - 1, &junk, unused);
385         strcat(name, "/.");
386         strcat(name, int_to_base64(stmp1, rw_vno));
387         code = gop_lookupname(name, AFS_UIOSYS, FOLLOW, &dvp);
388         if (!code) {
389             /* Use old name format. */
390             strcpy(path, name);
391             name_version = AFS_XFS_NAME_VERS1;
392         }
393     }
394
395     if (code == ENOENT) {
396         afs_xfs_dattr_t dattr;
397         /* make directory. */
398
399         code =
400             AFS_VN_OPEN(path, UIO_SYSSPACE, FCREAT | FEXCL, 0700, &dvp,
401                         CRMKDIR);
402         if (code) {
403             if (code == EEXIST) {
404                 /* someone beat us to it? */
405                 code = gop_lookupname(path, AFS_UIOSYS, NO_FOLLOW, &dvp);
406             }
407             if (code) {
408                 AFS_UNLOCK_VOL_CREATE();
409                 return code;
410             }
411         } else
412             createdDir = 1;
413         memset(&dattr, 0, sizeof(dattr));
414         dattr.atd_version = AFS_XFS_ATD_VERS;
415         dattr.atd_volume = rw_vno;
416         AFS_VOP_ATTR_SET(dvp, AFS_XFS_DATTR, (char *)&dattr,
417                          SIZEOF_XFS_DATTR_T, ATTR_ROOT | ATTR_CREATE,
418                          OSI_GET_CURRENT_CRED(), code);
419         if (code) {
420             VN_RELE(dvp);
421             if (createdDir)
422                 (void)vn_remove(path, UIO_SYSSPACE, RMDIRECTORY);
423             AFS_UNLOCK_VOL_CREATE();
424             return code;
425         }
426     }
427
428     vattr.va_mask = AT_FSID | AT_NODEID;        /* gets a guick return using FSID */
429     AFS_VOP_GETATTR(dvp, &vattr, 0, OSI_GET_CURRENT_CRED(), code);
430     if (code) {
431         VN_RELE(dvp);
432         return code;
433     }
434
435     memset(&attrs, 0, sizeof(attrs));
436     attrs.at_pino = vattr.va_nodeid;
437     VN_RELE(dvp);
438
439     /* Create the desired file. Use up to ten tries to create a unique name. */
440     (void)strcpy(name, path);
441     (void)strcat(name, "/.");
442     (void)strcat(name, int_to_base64(stmp2, params[2]));
443     s = &name[strlen(name)];
444
445     attrs.at_tag = 0;           /* Initial guess at a unique tag. */
446     for (i = 0; i < 10; i++) {
447         *s = '\0';
448         strcat(s, ".");
449         strcat(s, int_to_base64(stmp1, attrs.at_tag));
450         code =
451             AFS_VN_OPEN(name, UIO_SYSSPACE, FCREAT | FEXCL, 0600, &vp,
452                         CRCREAT);
453         if (!code || code != EEXIST)
454             break;
455
456         attrs.at_tag++;
457     }
458     /* Unlock the creation process since the directory now has a file in it. */
459     if (params[1] == INODESPECIAL)
460         AFS_UNLOCK_VOL_CREATE();
461
462     if (!code) {
463         /* Set attributes. */
464         memcpy((char *)attrs.at_param, (char *)params,
465                sizeof(afs_inode_params_t));
466         attrs.at_attr_version = AFS_XFS_ATTR_VERS;
467         attrs.at_name_version = name_version;
468         AFS_VOP_ATTR_SET(vp, AFS_XFS_ATTR, (char *)&attrs, SIZEOF_XFS_ATTR_T,
469                          ATTR_ROOT | ATTR_CREATE, OSI_GET_CURRENT_CRED(),
470                          code);
471         if (!code) {
472             vattr.va_mode = 1;
473             vattr.va_uid = AFS_XFS_VNO_CLIP(params[0]);
474             vattr.va_gid = XFS_VICEMAGIC;
475             vattr.va_mask = AT_MODE | AT_UID | AT_GID;
476             AFS_VOP_SETATTR(vp, &vattr, 0, OSI_GET_CURRENT_CRED(), code);
477         }
478         if (!code) {
479             vattr.va_mask = AT_NODEID;
480             AFS_VOP_GETATTR(vp, &vattr, 0, OSI_GET_CURRENT_CRED(), code);
481         }
482         if (!code)
483             *inop = vattr.va_nodeid;
484         VN_RELE(vp);
485     }
486
487     if (code) {
488         /* remove partially created file. */
489         (void)vn_remove(name, UIO_SYSSPACE, RMFILE);
490
491         /* and directory if volume special file. */
492         if (createdDir) {
493             AFS_LOCK_VOL_CREATE();
494             (void)vn_remove(path, UIO_SYSSPACE, RMDIRECTORY);
495             AFS_UNLOCK_VOL_CREATE();
496         }
497     }
498     return code;
499 }
500
501 /* afs_syscall_icreatename64
502  * This is the icreatename64 entry point used by the combined EFS/XFS
503  * fileserver suite. The datap and datalen do not need to be set for EFS.
504  */
505 int
506 afs_syscall_icreatename64(int dev, int datap, int datalen, int paramp,
507                           int inop)
508 {
509     struct vfs *vfsp;
510     afs_inode_params_t param;
511     int code;
512     rval_t rval;
513     ino_t ino;
514
515
516     if (!afs_suser(NULL))
517         return EPERM;
518
519 #ifdef AFS_SGI65_ENV
520     vfsp = vfs_devsearch(dev, VFS_FSTYPE_ANY);
521 #else
522     vfsp = vfs_devsearch(dev);
523 #endif
524     if (vfsp == NULL) {
525         return ENXIO;
526     }
527
528     AFS_COPYIN((char *)paramp, (char *)param, sizeof(afs_inode_params_t),
529                code);
530     if (vfsp->vfs_fstype == xfs_fstype) {
531         code = xfs_icreatename64(vfsp, datap, datalen, param, &ino);
532         if (code)
533             return code;
534         else {
535             AFS_COPYOUT((char *)&ino, (char *)inop, sizeof(ino_t), code);
536             return code;
537         }
538     } else if (vfsp->vfs_fstype == efs_fstype) {
539         code =
540             afs_syscall_icreate(dev, 0, param[0], param[1], param[2],
541                                 param[3], &rval);
542         if (code)
543             return code;
544         else {
545             ino = (ino_t) rval.r_val1;
546             AFS_COPYOUT((char *)&ino, (char *)inop, sizeof(ino_t), code);
547             return code;
548         }
549     }
550     return ENXIO;
551 }
552 #endif /* AFS_SGI_XFS_IOPS_ENV */
553
554 /*
555  * iopen system calls -- open an inode for reading/writing
556  * Restricted to super user.
557  * Any IFREG files.
558  * The original EFS only system calls are still present in the kernel for
559  * in case a kernel upgrade is done for a fix, but the EFS fileserver is
560  * still in use.
561  */
562 struct iopenargs {
563     sysarg_t dev;
564     sysarg_t inode;
565     sysarg_t usrmod;
566 };
567
568 #ifdef AFS_SGI_XFS_IOPS_ENV
569 struct iopenargs64 {
570     sysarg_t dev;
571     sysarg_t inode_hi;
572     sysarg_t inode_lo;
573     sysarg_t usrmod;
574 };
575
576 #ifdef AFS_SGI65_ENV
577 int
578 afs_syscall_iopen(int dev, ino_t inode, int usrmod, rval_t * rvp)
579 {
580     struct file *fp;
581     int fd;
582     int error;
583     struct vfs *vfsp;
584     struct vnode *vp;
585
586     AFS_STATCNT(afs_syscall_iopen);
587     if (!afs_suser(NULL))
588         return EPERM;
589     vfsp = vfs_devsearch(dev, xfs_fstype);
590     if (!vfsp)
591         vfsp = vfs_devsearch(dev, efs_fstype);
592     if (!vfsp)
593         return ENXIO;
594
595     if (vfsp->vfs_fstype == xfs_fstype) {
596         struct xfs_inode *xip;
597         if (error = xfs_igetinode(vfsp, (dev_t) dev, inode, &xip))
598             return error;
599         vp = XFS_ITOV(xip);
600         if (error = vfile_alloc((usrmod + 1) & (FMASK), &fp, &fd)) {
601             VN_RELE(vp);
602             return error;
603         }
604     } else {
605         osi_Panic("afs_syscall_iopen: bad fstype = %d\n", vfsp->vfs_fstype);
606     }
607     vfile_ready(fp, vp);
608     rvp->r_val1 = fd;
609     return 0;
610 }
611 #else
612 /* afs_syscall_iopen
613  * EFS/XFS version vectors to correct code based vfs_fstype. Expects a
614  * 64 bit inode number.
615  */
616 int
617 afs_syscall_iopen(int dev, ino_t inode, int usrmod, rval_t * rvp)
618 {
619     struct file *fp;
620     int fd;
621     int error;
622     struct vfs *vfsp;
623
624     AFS_STATCNT(afs_syscall_iopen);
625     if (!afs_suser(NULL))
626         return EPERM;
627     vfsp = vfs_devsearch(dev);
628     if (!vfsp) {
629         return ENXIO;
630     }
631
632     if (vfsp->vfs_fstype == xfs_fstype) {
633         struct xfs_inode *xip;
634         struct vnode *vp;
635         if (error = xfs_igetinode(vfsp, (dev_t) dev, inode, &xip))
636             return error;
637         vp = XFS_ITOV(xip);
638         if (error = falloc(vp, (usrmod + 1) & (FMASK), &fp, &fd)) {
639             VN_RELE(vp);
640             return error;
641         }
642     } else if (vfsp->vfs_fstype == efs_fstype) {
643         struct inode *ip;
644         if (error = igetinode(vfsp, (dev_t) dev, inode, &ip))
645             return error;
646         if (error = falloc(EFS_ITOV(ip), (usrmod + 1) & (FMASK), &fp, &fd)) {
647             iput(ip);
648             return error;
649         }
650         iunlock(ip);
651     } else {
652         osi_Panic("afs_syscall_iopen: bad fstype = %d\n", vfsp->vfs_fstype);
653     }
654     fready(fp);
655     rvp->r_val1 = fd;
656     return 0;
657 }
658 #endif /* AFS_SGI65_ENV */
659
660 int
661 iopen(struct iopenargs *uap, rval_t * rvp)
662 {
663     AFS_STATCNT(iopen);
664     return (afs_syscall_iopen
665             (uap->dev, (ino_t) uap->inode, uap->usrmod, rvp));
666 }
667
668 int
669 iopen64(struct iopenargs64 *uap, rval_t * rvp)
670 {
671     AFS_STATCNT(iopen);
672     return (afs_syscall_iopen
673             (uap->dev, (ino_t) ((uap->inode_hi << 32) | uap->inode_lo),
674              uap->usrmod, rvp));
675 }
676
677 #else /* AFS_SGI_XFS_IOPS_ENV */
678 /* iopen/afs_syscall_iopen
679  *
680  * Original EFS only 32 bit iopen call.
681  */
682 int
683 iopen(struct iopenargs *uap, rval_t * rvp)
684 {
685     AFS_STATCNT(iopen);
686     return (afs_syscall_iopen(uap->dev, uap->inode, uap->usrmod, rvp));
687 }
688
689 int
690 afs_syscall_iopen(dev, inode, usrmod, rvp)
691      int dev, inode, usrmod;
692      rval_t *rvp;
693 {
694     struct file *fp;
695     struct inode *ip;
696     int fd;
697     int error;
698
699     AFS_STATCNT(afs_syscall_iopen);
700     if (!afs_suser(NULL))
701         return EPERM;
702     if (error = igetinode(0, (dev_t) dev, inode, &ip))
703         return error;
704     if (error = falloc(EFS_ITOV(ip), (usrmod + 1) & (FMASK), &fp, &fd)) {
705         iput(ip);
706         return error;
707     }
708     iunlock(ip);
709     rvp->r_val1 = fd;
710 #ifdef  AFS_SGI53_ENV
711     fready(fp);
712 #endif
713     return 0;
714 }
715 #endif /* AFS_SGI_XFS_IOPS_ENV */
716
717 /*
718  * Support for iinc() and idec() system calls--increment or decrement
719  * count on inode.
720  * Restricted to super user.
721  * Only VICEMAGIC type inodes.
722  */
723 #ifdef AFS_SGI_XFS_IOPS_ENV
724
725 /* xfs_iincdec
726  *
727  * XFS/EFS iinc/idec code for EFS. Uses 64 bit inode numbers. 
728  */
729 static int
730 xfs_iincdec64(struct vfs *vfsp, ino_t inode, int inode_p1, int amount)
731 {
732     vnode_t *vp;
733     xfs_inode_t *ip;
734     int code = 0;
735     afs_xfs_attr_t attrs;
736     int length = SIZEOF_XFS_ATTR_T;
737     afs_xfs_dattr_t dattr;
738     struct vattr vattr;
739     int nlink;
740     int vol;
741
742     code =
743         xfs_iget((((struct mount *)((vfsp)->vfs_bh.bh_first)->bd_pdata)),
744                  (void *)0, (xfs_ino_t) inode, XFS_ILOCK_SHARED, &ip,
745                  (daddr_t) 0);
746     if (code)
747         return code;
748
749     vp = XFS_ITOV(ip);
750     xfs_iunlock(ip, XFS_ILOCK_SHARED);
751
752     vattr.va_mask = AT_GID | AT_UID | AT_MODE;
753     AFS_VOP_GETATTR(vp, &vattr, 0, OSI_GET_CURRENT_CRED(), code);
754     if (code)
755         code = EPERM;
756
757     if (!code && (vattr.va_gid != XFS_VICEMAGIC))
758         code = EPERM;
759
760     if (!code && (AFS_XFS_VNO_CLIP(inode_p1) != vattr.va_uid))
761         code = ENXIO;
762
763     if (code) {
764         VN_RELE(vp);
765         return code;
766     }
767
768     nlink = vattr.va_mode & AFS_XFS_MODE_LINK_MASK;
769     nlink += amount;
770     if (nlink > 07) {
771         code = EOVERFLOW;
772     }
773     if (nlink > 0) {
774         vattr.va_mode &= ~AFS_XFS_MODE_LINK_MASK;
775         vattr.va_mode |= nlink;
776         vattr.va_mask = AT_MODE;
777         AFS_VOP_SETATTR(vp, &vattr, 0, OSI_GET_CURRENT_CRED(), code);
778         VN_RELE(vp);
779         return code;
780     } else {
781         char path[64];
782         b64_string_t stmp1, stmp2;
783         vnode_t *dvp;
784         xfs_inode_t *ip;
785
786         length = SIZEOF_XFS_ATTR_T;
787         AFS_VOP_ATTR_GET(vp, AFS_XFS_ATTR, (char *)&attrs, &length, ATTR_ROOT,
788                          OSI_GET_CURRENT_CRED(), code);
789         VN_RELE(vp);
790         if (!code) {
791             if (length != SIZEOF_XFS_ATTR_T
792                 || attrs.at_attr_version != AFS_XFS_ATTR_VERS)
793                 return EINVAL;
794         }
795         /* Get the vnode for the directory this file is in. */
796         if (!attrs.at_pino)
797             return ENOENT;
798
799         code = xfs_getinode(vp->v_vfsp, NULL, attrs.at_pino, &ip);
800         if (code)
801             return code;
802
803         dvp = XFS_ITOV(ip);
804         xfs_iunlock(ip, XFS_ILOCK_SHARED);
805
806         /* Verify directory attributes. */
807         length = SIZEOF_XFS_DATTR_T;
808         AFS_VOP_ATTR_GET(dvp, AFS_XFS_DATTR, (char *)&dattr, &length,
809                          ATTR_ROOT, OSI_GET_CURRENT_CRED(), code);
810         if (!code) {
811             if (length != SIZEOF_XFS_DATTR_T
812                 || dattr.atd_version != AFS_XFS_ATD_VERS)
813                 code = ENXIO;
814         }
815         if (code) {
816             VN_RELE(dvp);
817             return code;
818         }
819
820         strcpy(path, ".");
821         strcat(path, int_to_base64(stmp1, attrs.at_param[2]));
822         strcat(path, ".");
823         strcat(path, int_to_base64(stmp1, attrs.at_tag));
824
825         AFS_VOP_REMOVE(dvp, path, OSI_GET_CURRENT_CRED(), code);
826
827         if (!code) {
828             int code2;
829             vattr.va_mask = AT_NLINK;
830             AFS_VOP_GETATTR(dvp, &vattr, 0, OSI_GET_CURRENT_CRED(), code2);
831             if (!code2) {
832                 if (vattr.va_nlink == 2) {
833                     vnode_t *ddvp;      /* parent of volume directory. */
834                     /* Try to remove the directory if this is a volume
835                      * special file. It's ok to fail.
836                      */
837                     AFS_VOP_LOOKUP(dvp, "..", &ddvp, (struct pathname *)NULL,
838                                    0, OSI_GET_CURRENT_RDIR(),
839                                    OSI_GET_CURRENT_CRED(), code2);
840                     if (!code2) {
841                         VN_RELE(dvp);
842                         dvp = (vnode_t *) 0;
843                         strcpy(path, ".");
844                         if (attrs.at_name_version == AFS_XFS_NAME_VERS2)
845                             strcpy(path, AFS_INODE_DIR_NAME);
846                         else
847                             strcpy(path, ".");
848                         int_to_base64(stmp1,
849                                       (attrs.at_param[1] ==
850                                        INODESPECIAL) ? attrs.
851                                       at_param[3] : attrs.at_param[0]);
852                         strcat(path, stmp1);
853                         AFS_LOCK_VOL_CREATE();
854                         AFS_VOP_RMDIR(ddvp, path, OSI_GET_CURRENT_CDIR(),
855                                       OSI_GET_CURRENT_CRED(), code2);
856                         AFS_UNLOCK_VOL_CREATE();
857                         VN_RELE(ddvp);
858                     }
859                 }
860             }
861         }
862         if (dvp)
863             VN_RELE(dvp);
864     }
865     return code;
866 }
867
868 int
869 iincdec64(int dev, int inode_hi, int inode_lo, int inode_p1, int amount)
870 {
871     struct vfs *vfsp;
872
873     if (!afs_suser(NULL))
874         return EPERM;
875 #ifdef AFS_SGI65_ENV
876     vfsp = vfs_devsearch(dev, VFS_FSTYPE_ANY);
877 #else
878     vfsp = vfs_devsearch(dev);
879 #endif
880     if (!vfsp) {
881         return ENXIO;
882     }
883
884     if (vfsp->vfs_fstype == xfs_fstype) {
885         ino_t inode;
886         inode = inode_hi;
887         inode <<= 32;
888         inode |= inode_lo;
889         return xfs_iincdec64(vfsp, inode, inode_p1, amount);
890     }
891     return ENXIO;
892 }
893
894 int
895 afs_syscall_idec64(int dev, int inode_hi, int inode_lo, int inode_p1)
896 {
897     return iincdec64(dev, inode_hi, inode_lo, inode_p1, -1);
898 }
899
900 int
901 afs_syscall_iinc64(int dev, int inode_hi, int inode_lo, int inode_p1)
902 {
903     return iincdec64(dev, inode_hi, inode_lo, inode_p1, 1);
904 }
905
906
907
908
909 struct iincargs {
910     sysarg_t dev;
911     sysarg_t inode;
912     sysarg_t inode_p1;
913 };
914
915 #ifdef AFS_SGI65_ENV
916 int
917 iinc(struct iincargs *uap, rval_t * rvp)
918 {
919     AFS_STATCNT(iinc);
920     return ENOTSUP;
921 }
922
923 int
924 idec(struct iincargs *uap, rval_t * rvp)
925 {
926     AFS_STATCNT(idec);
927     return ENOTSUP;
928 }
929 #else
930 /* iincdec
931  *
932  * XFS/EFS iinc/idec entry points for EFS only fileservers.
933  *
934  */
935 int
936 iincdec(dev, inode, inode_p1, amount)
937      int dev, inode, inode_p1, amount;
938 {
939     struct vfs *vfsp;
940
941     if (!afs_suser(NULL))
942         return EPERM;
943     vfsp = vfs_devsearch(dev);
944     if (!vfsp) {
945         return ENXIO;
946     }
947     if (vfsp->vfs_fstype != efs_fstype)
948         return ENOSYS;
949
950     return efs_iincdec(vfsp, inode, inode_p1, amount);
951 }
952
953 int
954 iinc(struct iincargs *uap, rval_t * rvp)
955 {
956     AFS_STATCNT(iinc);
957     return (iincdec(uap->dev, uap->inode, uap->inode_p1, 1));
958 }
959
960 int
961 idec(struct iincargs *uap, rval_t * rvp)
962 {
963     AFS_STATCNT(idec);
964     return (iincdec(uap->dev, uap->inode, uap->inode_p1, -1));
965 }
966 #endif /* AFS_SGI65_ENV */
967
968 #else /* AFS_SGI_XFS_IOPS_ENV */
969 /* afs_syscall_iincdec iinc idec
970  *
971  * These are the original EFS only entry points.
972  */
973 int
974 afs_syscall_iincdec(dev, inode, inode_p1, amount)
975      int dev, inode, inode_p1, amount;
976 {
977     struct inode *ip;
978     int error = 0;
979
980     if (!afs_suser(NULL))
981         return EPERM;
982     if (error = igetinode(0, (dev_t) dev, inode, &ip))
983         return error;
984
985     if (!IS_VICEMAGIC(ip))
986         error = EPERM;
987     else if (((struct afsparms *)ip->i_afs)->vicep1 != inode_p1)
988         error = ENXIO;
989     else {
990         ip->i_nlink += amount;
991         osi_Assert(ip->i_nlink >= 0);
992         if (ip->i_nlink == 0) {
993             CLEAR_VICEMAGIC(ip);
994             afsidestroy(ip);
995         }
996         ip->i_flags |= ICHG;
997     }
998     /* XXX sync write?? */
999     iput(ip);
1000     return error;
1001 }
1002
1003 struct iincargs {
1004     sysarg_t dev;
1005     sysarg_t inode;
1006     sysarg_t inode_p1;
1007 };
1008
1009 int
1010 iinc(struct iincargs *uap, rval_t * rvp)
1011 {
1012     AFS_STATCNT(iinc);
1013     return (afs_syscall_iincdec(uap->dev, uap->inode, uap->inode_p1, 1));
1014 }
1015
1016 int
1017 idec(struct iincargs *uap, rval_t * rvp)
1018 {
1019     AFS_STATCNT(idec);
1020     return (afs_syscall_iincdec(uap->dev, uap->inode, uap->inode_p1, -1));
1021 }
1022 #endif /* AFS_SGI_XFS_IOPS_ENV */
1023
1024 #ifdef AFS_SGI_XFS_IOPS_ENV
1025 /* afs_syscall_ilistinode64
1026  * Gathers up all required info for ListViceInodes in one system call.
1027  */
1028 int
1029 afs_syscall_ilistinode64(int dev, int inode_hi, int inode_lo, int datap,
1030                          int datalenp)
1031 {
1032     int code = 0;
1033     ino_t inode;
1034     xfs_inode_t *ip;
1035     vfs_t *vfsp;
1036     vnode_t *vp;
1037     struct vattr vattr;
1038     afs_xfs_attr_t attrs;
1039     int length;
1040     i_list_inode_t data;
1041     int idatalen;
1042
1043     if (!afs_suser(NULL))
1044         return EPERM;
1045 #ifdef AFS_SGI65_ENV
1046     vfsp = vfs_devsearch(dev, xfs_fstype);
1047 #else
1048     vfsp = vfs_devsearch(dev);
1049 #endif
1050     if (!vfsp) {
1051         return ENXIO;
1052     }
1053 #ifndef AFS_SGI65_ENV
1054     if (vfsp->vfs_fstype != xfs_fstype)
1055         return ENOSYS;
1056 #endif
1057
1058     AFS_COPYIN((char *)datalenp, &idatalen, sizeof(int), code);
1059     if (idatalen < sizeof(i_list_inode_t)) {
1060         idatalen = sizeof(i_list_inode_t);
1061         AFS_COPYOUT((char *)datalenp, (char *)&idatalen, sizeof(int), code);
1062         return E2BIG;
1063     }
1064     idatalen = sizeof(i_list_inode_t);
1065     AFS_COPYOUT((char *)datalenp, (char *)&idatalen, sizeof(int), code);
1066
1067     AFS_COPYIN((char *)datap, (char *)&data, sizeof(i_list_inode_t), code);
1068     if (data.ili_version != AFS_XFS_ILI_VERSION) {
1069         data.ili_version = AFS_XFS_ILI_VERSION;
1070         AFS_COPYOUT((char *)&data, (char *)datap, sizeof(i_list_inode_t),
1071                     code);
1072         return EINVAL;
1073     }
1074
1075
1076     inode = inode_hi;
1077     inode <<= 32;
1078     inode |= inode_lo;
1079     code =
1080         xfs_iget((((struct mount *)((vfsp)->vfs_bh.bh_first)->bd_pdata)),
1081                  (void *)0, (xfs_ino_t) inode, XFS_ILOCK_SHARED, &ip,
1082                  (daddr_t) 0);
1083     if (code)
1084         return code;
1085
1086     vp = XFS_ITOV(ip);
1087     xfs_iunlock(ip, XFS_ILOCK_SHARED);
1088
1089     length = SIZEOF_XFS_ATTR_T;
1090
1091     AFS_VOP_ATTR_GET(vp, AFS_XFS_ATTR, (char *)&attrs, &length, ATTR_ROOT,
1092                      OSI_GET_CURRENT_CRED(), code);
1093     if (code) {
1094         code = EPERM;
1095     }
1096
1097     if (!code) {
1098         if (attrs.at_attr_version != AFS_XFS_ATTR_VERS)
1099             code = EINVAL;
1100     }
1101
1102     if (!code) {
1103         vattr.va_mask = AT_STAT;
1104         AFS_VOP_GETATTR(vp, &vattr, 0, OSI_GET_CURRENT_CRED(), code);
1105     }
1106
1107     if (!code) {
1108         memset(&data, 0, sizeof(data));
1109         data.ili_info.inodeNumber = inode;
1110         data.ili_info.byteCount = vattr.va_size;
1111         data.ili_info.linkCount = (vattr.va_mode & AFS_XFS_MODE_LINK_MASK);
1112         memcpy((char *)data.ili_info.param, (char *)attrs.at_param,
1113                sizeof(data.ili_info.param));
1114         data.ili_attr_version = attrs.at_attr_version;
1115         data.ili_name_version = attrs.at_name_version;
1116         data.ili_tag = attrs.at_tag;
1117         data.ili_pino = attrs.at_pino;
1118         data.ili_vno = vattr.va_uid;
1119         data.ili_magic = vattr.va_gid;
1120         AFS_COPYOUT((char *)&data, (char *)datap, sizeof(data), code);
1121     }
1122     VN_RELE(vp);
1123     return code;
1124 }
1125 #endif /* AFS_SGI_XFS_IOPS_ENV */