afs: clarify cold and warm shutdown logic
[openafs.git] / src / afs / FBSD / osi_vfsops.c
1 #include <afsconfig.h>
2 #include <afs/param.h>
3
4
5 #include <afs/sysincludes.h>    /* Standard vendor system headers */
6 #include <afsincludes.h>        /* Afs-based standard headers */
7 #include <afs/afs_stats.h>      /* statistics */
8 #include <sys/malloc.h>
9 #include <sys/namei.h>
10 #include <sys/conf.h>
11 #include <sys/module.h>
12 #include <sys/sysproto.h>
13 #include <sys/syscall.h>
14 #include <sys/sysent.h>
15
16 struct vcache *afs_globalVp = NULL;
17 struct mount *afs_globalVFS = NULL;
18 int afs_pbuf_freecnt = -1;
19
20 extern int Afs_xsetgroups();
21 extern int afs_xioctl();
22
23 static struct syscall_helper_data afs_syscalls[] = {
24     {
25         .syscall_no = AFS_SYSCALL,
26         .new_sysent = {
27             .sy_narg = 5,
28             .sy_call = (sy_call_t *)afs3_syscall,
29             .sy_auevent = AUE_NULL,
30         },
31     },
32     SYSCALL_INIT_LAST
33 };
34
35 static int
36 afs_init(struct vfsconf *vfc)
37 {
38     int code;
39 #if defined(FBSD_SYSCALL_REGISTER_TAKES_FLAGS)
40     code = syscall_helper_register(afs_syscalls, 0);
41 #else
42     code = syscall_helper_register(afs_syscalls);
43 #endif
44     if (code) {
45         printf("AFS_SYSCALL in use, error %i. aborting\n", code);
46         return code;
47     }
48     osi_Init();
49     afs_pbuf_freecnt = nswbuf / 2 + 1;
50     return 0;
51 }
52
53 static int
54 afs_uninit(struct vfsconf *vfc)
55 {
56     if (afs_globalVFS)
57         return EBUSY;
58
59     return syscall_helper_unregister(afs_syscalls);
60 }
61
62 static int
63 afs_statfs(struct mount *mp, struct statfs *abp)
64 {
65     AFS_GLOCK();
66     AFS_STATCNT(afs_statfs);
67
68     abp->f_bsize = mp->vfs_bsize;
69     abp->f_iosize = mp->vfs_bsize;
70
71     abp->f_blocks = abp->f_bfree = abp->f_bavail = abp->f_files =
72         abp->f_ffree = AFS_VFS_FAKEFREE;
73
74     abp->f_fsid.val[0] = mp->mnt_stat.f_fsid.val[0];
75     abp->f_fsid.val[1] = mp->mnt_stat.f_fsid.val[1];
76     if (abp != &mp->mnt_stat) {
77         abp->f_type = mp->mnt_vfc->vfc_typenum;
78         memcpy((caddr_t) & abp->f_mntonname[0],
79                (caddr_t) mp->mnt_stat.f_mntonname, MNAMELEN);
80         memcpy((caddr_t) & abp->f_mntfromname[0],
81                (caddr_t) mp->mnt_stat.f_mntfromname, MNAMELEN);
82     }
83
84     AFS_GUNLOCK();
85     return 0;
86 }
87
88 static int
89 afs_omount(struct mount *mp, char *path, caddr_t data)
90 {
91     /* ndp contains the mounted-from device.  Just ignore it.
92      * we also don't care about our thread struct. */
93     size_t size;
94
95     if (mp->mnt_flag & MNT_UPDATE)
96         return EINVAL;
97
98     AFS_GLOCK();
99     AFS_STATCNT(afs_mount);
100
101     if (afs_globalVFS) {        /* Don't allow remounts. */
102         AFS_GUNLOCK();
103         return EBUSY;
104     }
105
106     afs_globalVFS = mp;
107     mp->vfs_bsize = 8192;
108     vfs_getnewfsid(mp);
109     /*
110      * This is kind of ugly, as the interlock has grown to encompass
111      * more fields over time and there's not a good way to group the
112      * code without duplication.
113      */
114     MNT_ILOCK(mp);
115     mp->mnt_flag &= ~MNT_LOCAL;
116 #if __FreeBSD_version < 1000021
117     mp->mnt_kern_flag |= MNTK_MPSAFE; /* solid steel */
118 #endif
119     /*
120      * XXX mnt_stat "is considered stable as long as a ref is held".
121      * We should check that we hold the only ref.
122      */
123     mp->mnt_stat.f_iosize = 8192;
124
125     if (path != NULL)
126         copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
127     else
128         bcopy("/afs", mp->mnt_stat.f_mntonname, size = 4);
129     memset(mp->mnt_stat.f_mntonname + size, 0, MNAMELEN - size);
130     memset(mp->mnt_stat.f_mntfromname, 0, MNAMELEN);
131     strcpy(mp->mnt_stat.f_mntfromname, "AFS");
132     /* null terminated string "AFS" will fit, just leave it be. */
133     strcpy(mp->mnt_stat.f_fstypename, "afs");
134     MNT_IUNLOCK(mp);
135     AFS_GUNLOCK();
136     afs_statfs(mp, &mp->mnt_stat);
137
138     return 0;
139 }
140
141 static int
142 afs_mount(struct mount *mp)
143 {
144     return afs_omount(mp, NULL, NULL);
145 }
146
147 static int
148 #if __FreeBSD_version >= 1000004
149 afs_cmount(struct mntarg *ma, void *data, uint64_t flags)
150 #else
151 afs_cmount(struct mntarg *ma, void *data, int flags)
152 #endif
153 {
154     return kernel_mount(ma, flags);
155 }
156
157 static int
158 afs_unmount(struct mount *mp, int flags)
159 {
160     int error = 0;
161
162     AFS_GLOCK();
163     if (afs_globalVp &&
164         ((flags & MNT_FORCE) || !VREFCOUNT_GT(afs_globalVp, 1))) {
165         /* Put back afs_root's ref */
166         struct vcache *gvp = afs_globalVp;
167         afs_globalVp = NULL;
168         afs_PutVCache(gvp);
169     }
170     if (afs_globalVp)
171         error = EBUSY;
172     AFS_GUNLOCK();
173
174     if (!error) {
175         /*
176          * Release any remaining vnodes on this mount point. The second
177          * argument is how many refs we hold on the root vnode. Since we
178          * released our reference to the root vnode up above, give 0.
179          */
180         error = vflush(mp, 0, (flags & MNT_FORCE) ? FORCECLOSE : 0, curthread);
181     }
182     if (error)
183         goto out;
184     AFS_GLOCK();
185     AFS_STATCNT(afs_unmount);
186     afs_globalVFS = 0;
187     afs_shutdown(AFS_WARM);
188     AFS_GUNLOCK();
189
190 out:
191     return error;
192 }
193
194 static int
195 afs_root(struct mount *mp, int flags, struct vnode **vpp)
196 {
197     int error;
198     struct vrequest treq;
199     struct vcache *tvp = 0;
200     struct vcache *gvp;
201     struct thread *td = curthread;
202     struct ucred *cr = osi_curcred();
203
204     AFS_GLOCK();
205     AFS_STATCNT(afs_root);
206     crhold(cr);
207 tryagain:
208     if (afs_globalVp && (afs_globalVp->f.states & CStatd)) {
209         tvp = afs_globalVp;
210         error = 0;
211     } else {
212         if (!(error = afs_InitReq(&treq, cr)) && !(error = afs_CheckInit())) {
213             tvp = afs_GetVCache(&afs_rootFid, &treq);
214             /* we really want this to stay around */
215             if (tvp) {
216                 gvp = afs_globalVp;
217                 afs_globalVp = tvp;
218                 if (gvp) {
219                     afs_PutVCache(gvp);
220                     if (tvp != afs_globalVp) {
221                         /* someone raced us and won */
222                         afs_PutVCache(tvp);
223                         goto tryagain;
224                     }
225                 }
226             } else
227                 error = EIO;
228         }
229     }
230     if (tvp) {
231         struct vnode *vp = AFSTOV(tvp);
232
233         ASSERT_VI_UNLOCKED(vp, "afs_root");
234         AFS_GUNLOCK();
235         error = vget(vp, LK_EXCLUSIVE | LK_RETRY, td);
236         AFS_GLOCK();
237         /* we dropped the glock, so re-check everything it had serialized */
238         if (!afs_globalVp || !(afs_globalVp->f.states & CStatd) ||
239                 tvp != afs_globalVp) {
240             vput(vp);
241             afs_PutVCache(tvp);
242             goto tryagain;
243         }
244         if (error != 0)
245             goto tryagain;
246         /*
247          * I'm uncomfortable about this.  Shouldn't this happen at a
248          * higher level, and shouldn't we busy the top-level directory
249          * to prevent recycling?
250          */
251         vp->v_vflag |= VV_ROOT;
252
253         afs_globalVFS = mp;
254         *vpp = vp;
255     }
256
257     afs_Trace2(afs_iclSetp, CM_TRACE_VFSROOT, ICL_TYPE_POINTER, tvp ? AFSTOV(tvp) : NULL,
258                ICL_TYPE_INT32, error);
259     AFS_GUNLOCK();
260     crfree(cr);
261     return error;
262 }
263
264 static int
265 afs_sync(struct mount *mp, int waitfor)
266 {
267     return 0;
268 }
269
270 struct vfsops afs_vfsops = {
271         .vfs_init =             afs_init,
272         .vfs_mount =            afs_mount,
273         .vfs_cmount =           afs_cmount,
274         .vfs_root =             afs_root,
275         .vfs_statfs =           afs_statfs,
276         .vfs_sync =             afs_sync,
277         .vfs_uninit =           afs_uninit,
278         .vfs_unmount =          afs_unmount,
279         .vfs_sysctl =           vfs_stdsysctl,
280 };