]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/fs/coda/coda_vfsops.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / sys / fs / coda / coda_vfsops.c
1 /*-
2  *             Coda: an Experimental Distributed File System
3  *                              Release 3.1
4  *
5  *           Copyright (c) 1987-1998 Carnegie Mellon University
6  *                          All Rights Reserved
7  *
8  * Permission  to  use, copy, modify and distribute this software and its
9  * documentation is hereby granted,  provided  that  both  the  copyright
10  * notice  and  this  permission  notice  appear  in  all  copies  of the
11  * software, derivative works or  modified  versions,  and  any  portions
12  * thereof, and that both notices appear in supporting documentation, and
13  * that credit is given to Carnegie Mellon University  in  all  documents
14  * and publicity pertaining to direct or indirect use of this code or its
15  * derivatives.
16  *
17  * CODA IS AN EXPERIMENTAL SOFTWARE SYSTEM AND IS  KNOWN  TO  HAVE  BUGS,
18  * SOME  OF  WHICH MAY HAVE SERIOUS CONSEQUENCES.  CARNEGIE MELLON ALLOWS
19  * FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION.   CARNEGIE  MELLON
20  * DISCLAIMS  ANY  LIABILITY  OF  ANY  KIND  FOR  ANY  DAMAGES WHATSOEVER
21  * RESULTING DIRECTLY OR INDIRECTLY FROM THE USE OF THIS SOFTWARE  OR  OF
22  * ANY DERIVATIVE WORK.
23  *
24  * Carnegie  Mellon  encourages  users  of  this  software  to return any
25  * improvements or extensions that  they  make,  and  to  grant  Carnegie
26  * Mellon the rights to redistribute these changes without encumbrance.
27  *
28  *      @(#) src/sys/cfs/coda_vfsops.c,v 1.1.1.1 1998/08/29 21:14:52 rvb Exp $
29  */
30
31 /*-
32  * Mach Operating System
33  * Copyright (c) 1989 Carnegie-Mellon University
34  * All rights reserved.  The CMU software License Agreement specifies
35  * the terms and conditions for use and redistribution.
36  */
37
38 /*
39  * This code was written for the Coda filesystem at Carnegie Mellon
40  * University.  Contributers include David Steere, James Kistler, and
41  * M. Satyanarayanan.
42  */
43
44 #include <sys/cdefs.h>
45 __FBSDID("$FreeBSD$");
46
47 #include <sys/param.h>
48 #include <sys/systm.h>
49 #include <sys/conf.h>
50 #include <sys/kernel.h>
51 #include <sys/lock.h>
52 #include <sys/malloc.h>
53 #include <sys/mount.h>
54 #include <sys/namei.h>
55 #include <sys/proc.h>
56
57 #include <fs/coda/coda.h>
58 #include <fs/coda/cnode.h>
59 #include <fs/coda/coda_vfsops.h>
60 #include <fs/coda/coda_venus.h>
61 #include <fs/coda/coda_subr.h>
62 #include <fs/coda/coda_opstats.h>
63
64 MALLOC_DEFINE(M_CODA, "coda", "Various Coda Structures");
65
66 int codadebug = 0;
67 int coda_vfsop_print_entry = 0;
68 #define ENTRY do {                                                      \
69         if (coda_vfsop_print_entry)                                     \
70                 myprintf(("Entered %s\n", __func__));                   \
71 } while (0)
72
73 struct vnode *coda_ctlvp;
74
75 /*
76  * Structure to keep statistics of internally generated/satisfied calls.
77  */
78 static struct coda_op_stats coda_vfsopstats[CODA_VFSOPS_SIZE];
79
80 #define MARK_ENTRY(op)          (coda_vfsopstats[op].entries++)
81 #define MARK_INT_SAT(op)        (coda_vfsopstats[op].sat_intrn++)
82 #define MARK_INT_FAIL(op)       (coda_vfsopstats[op].unsat_intrn++)
83 #define MARK_INT_GEN(op)        (coda_vfsopstats[op].gen_intrn++)
84
85 int
86 coda_vfsopstats_init(void)
87 {
88         int i;
89
90         for (i=0; i<CODA_VFSOPS_SIZE;i++) {
91                 coda_vfsopstats[i].opcode = i;
92                 coda_vfsopstats[i].entries = 0;
93                 coda_vfsopstats[i].sat_intrn = 0;
94                 coda_vfsopstats[i].unsat_intrn = 0;
95                 coda_vfsopstats[i].gen_intrn = 0;
96         }
97         return (0);
98 }
99
100 static const char *coda_opts[] = { "from", NULL };
101 /*
102  * cfs mount vfsop
103  *
104  * Set up mount info record and attach it to vfs struct.
105  */
106 /*ARGSUSED*/
107 int
108 coda_mount(struct mount *vfsp, struct thread *td)
109 {
110         struct vnode *dvp;
111         struct cnode *cp;
112         struct cdev *dev;
113         struct coda_mntinfo *mi;
114         struct vnode *rootvp;
115         CodaFid rootfid = INVAL_FID;
116         CodaFid ctlfid = CTL_FID;
117         int error;
118         struct nameidata ndp;
119         ENTRY;
120         char *from;
121
122         if (vfs_filteropt(vfsp->mnt_optnew, coda_opts))
123                 return (EINVAL);
124         from = vfs_getopts(vfsp->mnt_optnew, "from", &error);
125         if (error)
126                 return (error);
127         coda_vfsopstats_init();
128         coda_vnodeopstats_init();
129         MARK_ENTRY(CODA_MOUNT_STATS);
130         if (CODA_MOUNTED(vfsp)) {
131                 MARK_INT_FAIL(CODA_MOUNT_STATS);
132                 return (EBUSY);
133         }
134
135         /*
136          * Validate mount device.  Similar to getmdev().
137          */
138         NDINIT(&ndp, LOOKUP, FOLLOW, UIO_SYSSPACE, from, td);
139         error = namei(&ndp);
140         dvp = ndp.ni_vp;
141         if (error) {
142                 MARK_INT_FAIL(CODA_MOUNT_STATS);
143                 return (error);
144         }
145         if (dvp->v_type != VCHR) {
146                 MARK_INT_FAIL(CODA_MOUNT_STATS);
147                 vrele(dvp);
148                 NDFREE(&ndp, NDF_ONLY_PNBUF);
149                 return (ENXIO);
150         }
151         dev = dvp->v_rdev;
152         vrele(dvp);
153         NDFREE(&ndp, NDF_ONLY_PNBUF);
154
155         /*
156          * Initialize the mount record and link it to the vfs struct.
157          */
158         mi = dev2coda_mntinfo(dev);
159         if (!mi) {
160                 MARK_INT_FAIL(CODA_MOUNT_STATS);
161                 printf("Coda mount: %s is not a cfs device\n", from);
162                 return (ENXIO);
163         }
164         if (!VC_OPEN(&mi->mi_vcomm)) {
165                 MARK_INT_FAIL(CODA_MOUNT_STATS);
166                 return (ENODEV);
167         }
168
169         /*
170          * No initialization (here) of mi_vcomm!
171          */
172         vfsp->mnt_data = mi;
173         vfs_getnewfsid (vfsp);
174         mi->mi_vfsp = vfsp;
175         mi->mi_started = 0;                     /* XXX See coda_root() */
176
177         /*
178          * Make a root vnode to placate the Vnode interface, but don't
179          * actually make the CODA_ROOT call to venus until the first call to
180          * coda_root in case a server is down while venus is starting.
181          */
182         cp = make_coda_node(&rootfid, vfsp, VDIR);
183         rootvp = CTOV(cp);
184         rootvp->v_vflag |= VV_ROOT;
185         cp = make_coda_node(&ctlfid, vfsp, VREG);
186         coda_ctlvp = CTOV(cp);
187
188         /*
189          * Add vfs and rootvp to chain of vfs hanging off mntinfo.
190          */
191         mi->mi_vfsp = vfsp;
192         mi->mi_rootvp = rootvp;
193         vfs_mountedfrom(vfsp, from);
194
195         /*
196          * Error is currently guaranteed to be zero, but in case some code
197          * changes...
198          */
199         CODADEBUG(1, myprintf(("coda_mount returned %d\n", error)););
200         if (error)
201                 MARK_INT_FAIL(CODA_MOUNT_STATS);
202         else
203                 MARK_INT_SAT(CODA_MOUNT_STATS);
204         return (error);
205 }
206
207 int
208 coda_unmount(struct mount *vfsp, int mntflags, struct thread *td)
209 {
210         struct coda_mntinfo *mi = vftomi(vfsp);
211         int active, error = 0;
212
213         ENTRY;
214         MARK_ENTRY(CODA_UMOUNT_STATS);
215         if (!CODA_MOUNTED(vfsp)) {
216                 MARK_INT_FAIL(CODA_UMOUNT_STATS);
217                 return (EINVAL);
218         }
219         if (mi->mi_vfsp == vfsp) {
220                 /*
221                  * We found the victim.
222                  */
223                 if (!IS_UNMOUNTING(VTOC(mi->mi_rootvp)))
224                         return (EBUSY);         /* Venus is still running */
225 #ifdef DEBUG
226                 printf("coda_unmount: ROOT: vp %p, cp %p\n", mi->mi_rootvp,
227                     VTOC(mi->mi_rootvp));
228 #endif
229                 vrele(mi->mi_rootvp);
230                 mi->mi_rootvp = NULL;
231                 vrele(coda_ctlvp);
232                 coda_ctlvp = NULL;
233                 active = coda_kill(vfsp, NOT_DOWNCALL);
234                 error = vflush(mi->mi_vfsp, 0, FORCECLOSE, td);
235 #ifdef CODA_VERBOSE
236                 printf("coda_unmount: active = %d, vflush active %d\n",
237                     active, error);
238 #endif
239                 error = 0;
240                 /*
241                  * I'm going to take this out to allow lookups to go through.
242                  * I'm not sure it's important anyway. -- DCS 2/2/94
243                  */
244                 /* vfsp->VFS_DATA = NULL; */
245
246                 /*
247                  * No more vfsp's to hold onto.
248                  */
249                 mi->mi_vfsp = NULL;
250
251                 if (error)
252                         MARK_INT_FAIL(CODA_UMOUNT_STATS);
253                 else
254                         MARK_INT_SAT(CODA_UMOUNT_STATS);
255                 return (error);
256         }
257         return (EINVAL);
258 }
259
260 /*
261  * Find root of cfs.
262  */
263 int
264 coda_root(struct mount *vfsp, int flags, struct vnode **vpp,
265      struct thread *td)
266 {
267         struct coda_mntinfo *mi = vftomi(vfsp);
268         struct vnode **result;
269         int error;
270         struct proc *p = td->td_proc;
271         CodaFid VFid;
272         static const CodaFid invalfid = INVAL_FID;
273
274         ENTRY;
275         MARK_ENTRY(CODA_ROOT_STATS);
276         result = NULL;
277         if (vfsp == mi->mi_vfsp) {
278                 /*
279                  * Cache the root across calls.  We only need to pass the
280                  * request on to Venus if the root vnode is the dummy we
281                  * installed in coda_mount() with all c_fid members zeroed.
282                  *
283                  * XXX In addition, we assume that the first call to
284                  * coda_root() is from vfs_mount() (before the call to
285                  * checkdirs()) and return the dummy root node to avoid a
286                  * deadlock.  This bug is fixed in the Coda CVS repository
287                  * but not in any released versions as of 6 Mar 2003.
288                  */
289                 if (memcmp(&VTOC(mi->mi_rootvp)->c_fid, &invalfid,
290                     sizeof(CodaFid)) != 0 || mi->mi_started == 0) {
291                         /*
292                          * Found valid root.
293                          */
294                         *vpp = mi->mi_rootvp;
295                         mi->mi_started = 1;
296
297                         /*
298                          * On Mach, this is vref.  On FreeBSD, vref +
299                          * vn_lock.
300                          */
301                         vref(*vpp);
302                         vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY, td);
303                         MARK_INT_SAT(CODA_ROOT_STATS);
304                         return (0);
305                 }
306         }
307
308         error = venus_root(vftomi(vfsp), td->td_ucred, p, &VFid);
309         if (!error) {
310                 /*
311                  * Save the new rootfid in the cnode, and rehash the cnode
312                  * into the cnode hash with the new fid key.
313                  */
314                 coda_unsave(VTOC(mi->mi_rootvp));
315                 VTOC(mi->mi_rootvp)->c_fid = VFid;
316                 coda_save(VTOC(mi->mi_rootvp));
317                 *vpp = mi->mi_rootvp;
318                 vref(*vpp);
319                 vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY, td);
320                 MARK_INT_SAT(CODA_ROOT_STATS);
321         } else if (error == ENODEV || error == EINTR) {
322                 /*
323                  * Gross hack here!
324                  *
325                  * If Venus fails to respond to the CODA_ROOT call, coda_call
326                  * returns ENODEV. Return the uninitialized root vnode to
327                  * allow vfs operations such as unmount to continue.  Without
328                  * this hack, there is no way to do an unmount if Venus dies
329                  * before a successful CODA_ROOT call is done.  All vnode
330                  * operations will fail.
331                  */
332                 *vpp = mi->mi_rootvp;
333                 vref(*vpp);
334                 vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY, td);
335                 MARK_INT_FAIL(CODA_ROOT_STATS);
336                 error = 0;
337         } else {
338                 CODADEBUG(CODA_ROOT, myprintf(("error %d in CODA_ROOT\n",
339                     error)););
340                 MARK_INT_FAIL(CODA_ROOT_STATS);
341         }
342         return (error);
343 }
344
345 /*
346  * Get filesystem statistics.
347  */
348 int
349 coda_statfs(struct mount *vfsp, struct statfs *sbp, struct thread *td)
350 {
351
352         ENTRY;
353         MARK_ENTRY(CODA_STATFS_STATS);
354         if (!CODA_MOUNTED(vfsp)) {
355                 MARK_INT_FAIL(CODA_STATFS_STATS);
356                 return (EINVAL);
357         }
358
359         /*
360          * XXX - what to do about f_flags, others? --bnoble
361          *
362          * We just make up free space counts that are sufficiently large.
363          */
364         sbp->f_flags = 0;
365         sbp->f_bsize = 8192; /* XXX */
366         sbp->f_iosize = 8192; /* XXX */
367 #define CODA_SFS_SIZ    0x8AB75D
368         sbp->f_blocks = CODA_SFS_SIZ;
369         sbp->f_bfree = CODA_SFS_SIZ;
370         sbp->f_bavail = CODA_SFS_SIZ;
371         sbp->f_files = CODA_SFS_SIZ;
372         sbp->f_ffree = CODA_SFS_SIZ;
373         MARK_INT_SAT(CODA_STATFS_STATS);
374         return (0);
375 }
376
377 /*
378  * Flush any pending I/O.
379  */
380 int
381 coda_sync(struct mount *vfsp, int waitfor, struct thread *td)
382 {
383
384         ENTRY;
385         MARK_ENTRY(CODA_SYNC_STATS);
386         MARK_INT_SAT(CODA_SYNC_STATS);
387         return (0);
388 }
389
390 /*
391  * fhtovp is now what vget used to be in 4.3-derived systems.  For some silly
392  * reason, vget is now keyed by a 32 bit ino_t, rather than a type-specific
393  * fid.
394  *
395  * XXX: coda_fhtovp is currently not hooked up, so no NFS export for Coda.
396  * We leave it here in the hopes that someone will find it someday and hook
397  * it up.  Among other things, it will need some reworking to match the
398  * vfs_fhtovp_t prototype.
399  */
400 int
401 coda_fhtovp(struct mount *vfsp, struct fid *fhp, struct mbuf *nam,
402     struct vnode **vpp, int *exflagsp, struct ucred **creadanonp)
403 {
404         struct cfid *cfid = (struct cfid *)fhp;
405         struct cnode *cp = NULL;
406         int error;
407         struct thread *td = curthread; /* XXX -mach */
408         struct proc *p = td->td_proc;
409         CodaFid VFid;
410         int vtype;
411
412         ENTRY;
413         MARK_ENTRY(CODA_VGET_STATS);
414
415         /*
416          * Check for vget of control object.
417          */
418         if (IS_CTL_FID(&cfid->cfid_fid)) {
419                 *vpp = coda_ctlvp;
420                 vref(coda_ctlvp);
421                 MARK_INT_SAT(CODA_VGET_STATS);
422                 return (0);
423         }
424         error = venus_fhtovp(vftomi(vfsp), &cfid->cfid_fid, td->td_ucred, p,
425             &VFid, &vtype);
426         if (error) {
427                 CODADEBUG(CODA_VGET, myprintf(("vget error %d\n",error)););
428                 *vpp = NULL;
429         } else {
430                 CODADEBUG(CODA_VGET, myprintf(("vget: %s type %d result "
431                     "%d\n", coda_f2s(&VFid), vtype, error)););
432                 cp = make_coda_node(&VFid, vfsp, vtype);
433                 *vpp = CTOV(cp);
434         }
435         return (error);
436 }
437
438 struct vfsops coda_vfsops = {
439         .vfs_mount =            coda_mount,
440         .vfs_root =             coda_root,
441         .vfs_statfs =           coda_statfs,
442         .vfs_sync =             coda_sync,
443         .vfs_unmount =          coda_unmount,
444 };
445 VFS_SET(coda_vfsops, coda, VFCF_NETWORK);