source: rtems-libbsd/freebsd/sys/fs/nfsclient/nfs_clsubs.c @ 882425f

6-freebsd-12
Last change on this file since 882425f was 882425f, checked in by Chris Johns <chrisj@…>, on 07/29/21 at 05:49:52

kern/sys: Add NFSv4 client

Update #4475

  • Property mode set to 100644
File size: 10.1 KB
Line 
1#include <machine/rtems-bsd-kernel-space.h>
2
3/*-
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 * Copyright (c) 1989, 1993
7 *      The Regents of the University of California.  All rights reserved.
8 *
9 * This code is derived from software contributed to Berkeley by
10 * Rick Macklem at The University of Guelph.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 *    notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 *    notice, this list of conditions and the following disclaimer in the
19 *    documentation and/or other materials provided with the distribution.
20 * 3. Neither the name of the University nor the names of its contributors
21 *    may be used to endorse or promote products derived from this software
22 *    without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 *      from nfs_subs.c  8.8 (Berkeley) 5/22/95
37 */
38
39#include <sys/cdefs.h>
40__FBSDID("$FreeBSD$");
41
42/*
43 * These functions support the macros and help fiddle mbuf chains for
44 * the nfs op functions. They do things like create the rpc header and
45 * copy data between mbuf chains and uio lists.
46 */
47
48#include <sys/param.h>
49#include <sys/systm.h>
50#include <sys/kernel.h>
51#include <sys/bio.h>
52#include <sys/buf.h>
53#include <sys/proc.h>
54#include <sys/mount.h>
55#include <sys/vnode.h>
56#include <sys/namei.h>
57#include <sys/mbuf.h>
58#include <sys/socket.h>
59#include <sys/stat.h>
60#include <sys/malloc.h>
61#include <sys/sysent.h>
62#ifndef __rtems__
63#include <sys/syscall.h>
64#endif /* __rtems__ */
65#include <sys/sysproto.h>
66#include <sys/taskqueue.h>
67
68#include <vm/vm.h>
69#include <vm/vm_object.h>
70#include <vm/vm_extern.h>
71#include <vm/uma.h>
72
73#include <fs/nfs/nfsport.h>
74#include <fs/nfsclient/nfsnode.h>
75#include <fs/nfsclient/nfsmount.h>
76#include <fs/nfsclient/nfs.h>
77#include <fs/nfsclient/nfs_kdtrace.h>
78
79#include <netinet/in.h>
80
81/*
82 * Note that stdarg.h and the ANSI style va_start macro is used for both
83 * ANSI and traditional C compilers.
84 */
85#include <machine/stdarg.h>
86
87extern struct mtx ncl_iod_mutex;
88extern enum nfsiod_state ncl_iodwant[NFS_MAXASYNCDAEMON];
89extern struct nfsmount *ncl_iodmount[NFS_MAXASYNCDAEMON];
90extern int ncl_numasync;
91extern unsigned int ncl_iodmax;
92extern struct nfsstatsv1 nfsstatsv1;
93
94struct task     ncl_nfsiodnew_task;
95
96int
97ncl_uninit(struct vfsconf *vfsp)
98{
99        /*
100         * XXX: Unloading of nfscl module is unsupported.
101         */
102#if 0
103        int i;
104
105        /*
106         * Tell all nfsiod processes to exit. Clear ncl_iodmax, and wakeup
107         * any sleeping nfsiods so they check ncl_iodmax and exit.
108         */
109        NFSLOCKIOD();
110        ncl_iodmax = 0;
111        for (i = 0; i < ncl_numasync; i++)
112                if (ncl_iodwant[i] == NFSIOD_AVAILABLE)
113                        wakeup(&ncl_iodwant[i]);
114        /* The last nfsiod to exit will wake us up when ncl_numasync hits 0 */
115        while (ncl_numasync)
116                msleep(&ncl_numasync, &ncl_iod_mutex, PWAIT, "ioddie", 0);
117        NFSUNLOCKIOD();
118        ncl_nhuninit();
119        return (0);
120#else
121        return (EOPNOTSUPP);
122#endif
123}
124
125void
126ncl_dircookie_lock(struct nfsnode *np)
127{
128        NFSLOCKNODE(np);
129        while (np->n_flag & NDIRCOOKIELK)
130                (void) msleep(&np->n_flag, &np->n_mtx, PZERO, "nfsdirlk", 0);
131        np->n_flag |= NDIRCOOKIELK;
132        NFSUNLOCKNODE(np);
133}
134
135void
136ncl_dircookie_unlock(struct nfsnode *np)
137{
138        NFSLOCKNODE(np);
139        np->n_flag &= ~NDIRCOOKIELK;
140        wakeup(&np->n_flag);
141        NFSUNLOCKNODE(np);
142}
143
144bool
145ncl_excl_start(struct vnode *vp)
146{
147        struct nfsnode *np;
148        int vn_lk;
149
150        ASSERT_VOP_LOCKED(vp, "ncl_excl_start");
151        vn_lk = NFSVOPISLOCKED(vp);
152        if (vn_lk == LK_EXCLUSIVE)
153                return (false);
154        KASSERT(vn_lk == LK_SHARED,
155            ("ncl_excl_start: wrong vnode lock %d", vn_lk));
156        /* Ensure exclusive access, this might block */
157        np = VTONFS(vp);
158        lockmgr(&np->n_excl, LK_EXCLUSIVE, NULL);
159        return (true);
160}
161
162void
163ncl_excl_finish(struct vnode *vp, bool old_lock)
164{
165        struct nfsnode *np;
166
167        if (!old_lock)
168                return;
169        np = VTONFS(vp);
170        lockmgr(&np->n_excl, LK_RELEASE, NULL);
171}
172
173#ifdef NFS_ACDEBUG
174#include <sys/sysctl.h>
175SYSCTL_DECL(_vfs_nfs);
176static int nfs_acdebug;
177SYSCTL_INT(_vfs_nfs, OID_AUTO, acdebug, CTLFLAG_RW, &nfs_acdebug, 0, "");
178#endif
179
180/*
181 * Check the time stamp
182 * If the cache is valid, copy contents to *vap and return 0
183 * otherwise return an error
184 */
185int
186ncl_getattrcache(struct vnode *vp, struct vattr *vaper)
187{
188        struct nfsnode *np;
189        struct vattr *vap;
190        struct nfsmount *nmp;
191        int timeo, mustflush;
192        u_quad_t nsize;
193        bool setnsize;
194       
195        np = VTONFS(vp);
196        vap = &np->n_vattr.na_vattr;
197        nmp = VFSTONFS(vp->v_mount);
198        mustflush = nfscl_mustflush(vp);        /* must be before mtx_lock() */
199        NFSLOCKNODE(np);
200        /* XXX n_mtime doesn't seem to be updated on a miss-and-reload */
201        timeo = (time_second - np->n_mtime.tv_sec) / 10;
202
203#ifdef NFS_ACDEBUG
204        if (nfs_acdebug>1)
205                printf("ncl_getattrcache: initial timeo = %d\n", timeo);
206#endif
207
208        if (vap->va_type == VDIR) {
209                if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acdirmin)
210                        timeo = nmp->nm_acdirmin;
211                else if (timeo > nmp->nm_acdirmax)
212                        timeo = nmp->nm_acdirmax;
213        } else {
214                if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acregmin)
215                        timeo = nmp->nm_acregmin;
216                else if (timeo > nmp->nm_acregmax)
217                        timeo = nmp->nm_acregmax;
218        }
219
220#ifdef NFS_ACDEBUG
221        if (nfs_acdebug > 2)
222                printf("acregmin %d; acregmax %d; acdirmin %d; acdirmax %d\n",
223                    nmp->nm_acregmin, nmp->nm_acregmax,
224                    nmp->nm_acdirmin, nmp->nm_acdirmax);
225
226        if (nfs_acdebug)
227                printf("ncl_getattrcache: age = %d; final timeo = %d\n",
228                    (time_second - np->n_attrstamp), timeo);
229#endif
230
231        if ((time_second - np->n_attrstamp) >= timeo &&
232            (mustflush != 0 || np->n_attrstamp == 0)) {
233                nfsstatsv1.attrcache_misses++;
234                NFSUNLOCKNODE(np);
235                KDTRACE_NFS_ATTRCACHE_GET_MISS(vp);
236                return( ENOENT);
237        }
238        nfsstatsv1.attrcache_hits++;
239        setnsize = false;
240        if (vap->va_size != np->n_size) {
241                if (vap->va_type == VREG) {
242                        if (np->n_flag & NMODIFIED) {
243                                if (vap->va_size < np->n_size)
244                                        vap->va_size = np->n_size;
245                                else
246                                        np->n_size = vap->va_size;
247                        } else {
248                                np->n_size = vap->va_size;
249                        }
250                        setnsize = ncl_pager_setsize(vp, &nsize);
251                } else {
252                        np->n_size = vap->va_size;
253                }
254        }
255        bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr));
256        if (np->n_flag & NCHG) {
257                if (np->n_flag & NACC)
258                        vaper->va_atime = np->n_atim;
259                if (np->n_flag & NUPD)
260                        vaper->va_mtime = np->n_mtim;
261        }
262        NFSUNLOCKNODE(np);
263#ifndef __rtems__
264        if (setnsize)
265                vnode_pager_setsize(vp, nsize);
266#endif /* __rtems__ */
267        KDTRACE_NFS_ATTRCACHE_GET_HIT(vp, vap);
268        return (0);
269}
270
271static nfsuint64 nfs_nullcookie = { { 0, 0 } };
272/*
273 * This function finds the directory cookie that corresponds to the
274 * logical byte offset given.
275 */
276nfsuint64 *
277ncl_getcookie(struct nfsnode *np, off_t off, int add)
278{
279        struct nfsdmap *dp, *dp2;
280        int pos;
281        nfsuint64 *retval = NULL;
282       
283        pos = (uoff_t)off / NFS_DIRBLKSIZ;
284        if (pos == 0 || off < 0) {
285                KASSERT(!add, ("nfs getcookie add at <= 0"));
286                return (&nfs_nullcookie);
287        }
288        pos--;
289        dp = LIST_FIRST(&np->n_cookies);
290        if (!dp) {
291                if (add) {
292                        dp = malloc(sizeof (struct nfsdmap),
293                                M_NFSDIROFF, M_WAITOK);
294                        dp->ndm_eocookie = 0;
295                        LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list);
296                } else
297                        goto out;
298        }
299        while (pos >= NFSNUMCOOKIES) {
300                pos -= NFSNUMCOOKIES;
301                if (LIST_NEXT(dp, ndm_list)) {
302                        if (!add && dp->ndm_eocookie < NFSNUMCOOKIES &&
303                            pos >= dp->ndm_eocookie)
304                                goto out;
305                        dp = LIST_NEXT(dp, ndm_list);
306                } else if (add) {
307                        dp2 = malloc(sizeof (struct nfsdmap),
308                                M_NFSDIROFF, M_WAITOK);
309                        dp2->ndm_eocookie = 0;
310                        LIST_INSERT_AFTER(dp, dp2, ndm_list);
311                        dp = dp2;
312                } else
313                        goto out;
314        }
315        if (pos >= dp->ndm_eocookie) {
316                if (add)
317                        dp->ndm_eocookie = pos + 1;
318                else
319                        goto out;
320        }
321        retval = &dp->ndm_cookies[pos];
322out:
323        return (retval);
324}
325
326/*
327 * Invalidate cached directory information, except for the actual directory
328 * blocks (which are invalidated separately).
329 * Done mainly to avoid the use of stale offset cookies.
330 */
331void
332ncl_invaldir(struct vnode *vp)
333{
334        struct nfsnode *np = VTONFS(vp);
335
336        KASSERT(vp->v_type == VDIR, ("nfs: invaldir not dir"));
337        ncl_dircookie_lock(np);
338        np->n_direofoffset = 0;
339        np->n_cookieverf.nfsuquad[0] = 0;
340        np->n_cookieverf.nfsuquad[1] = 0;
341        if (LIST_FIRST(&np->n_cookies))
342                LIST_FIRST(&np->n_cookies)->ndm_eocookie = 0;
343        ncl_dircookie_unlock(np);
344}
345
346/*
347 * The write verifier has changed (probably due to a server reboot), so all
348 * B_NEEDCOMMIT blocks will have to be written again. Since they are on the
349 * dirty block list as B_DELWRI, all this takes is clearing the B_NEEDCOMMIT
350 * and B_CLUSTEROK flags.  Once done the new write verifier can be set for the
351 * mount point.
352 *
353 * B_CLUSTEROK must be cleared along with B_NEEDCOMMIT because stage 1 data
354 * writes are not clusterable.
355 */
356void
357ncl_clearcommit(struct mount *mp)
358{
359        struct vnode *vp, *nvp;
360        struct buf *bp, *nbp;
361        struct bufobj *bo;
362
363        MNT_VNODE_FOREACH_ALL(vp, mp, nvp) {
364                bo = &vp->v_bufobj;
365                vholdl(vp);
366                VI_UNLOCK(vp);
367                BO_LOCK(bo);
368                TAILQ_FOREACH_SAFE(bp, &bo->bo_dirty.bv_hd, b_bobufs, nbp) {
369                        if (!BUF_ISLOCKED(bp) &&
370                            (bp->b_flags & (B_DELWRI | B_NEEDCOMMIT))
371                                == (B_DELWRI | B_NEEDCOMMIT))
372                                bp->b_flags &= ~(B_NEEDCOMMIT | B_CLUSTEROK);
373                }
374                BO_UNLOCK(bo);
375                vdrop(vp);
376        }
377}
378
379/*
380 * Called once to initialize data structures...
381 */
382int
383ncl_init(struct vfsconf *vfsp)
384{
385        int i;
386
387        /* Ensure async daemons disabled */
388        for (i = 0; i < NFS_MAXASYNCDAEMON; i++) {
389                ncl_iodwant[i] = NFSIOD_NOT_AVAILABLE;
390                ncl_iodmount[i] = NULL;
391        }
392        TASK_INIT(&ncl_nfsiodnew_task, 0, ncl_nfsiodnew_tq, NULL);
393        ncl_nhinit();                   /* Init the nfsnode table */
394
395        return (0);
396}
Note: See TracBrowser for help on using the repository browser.