Print this page
NEX-15740 NFS deadlock in rfs4_compound with hundreds of threads waiting for lock owned by rfs4_op_rename (lint fix)
NEX-15740 NFS deadlock in rfs4_compound with hundreds of threads waiting for lock owned by rfs4_op_rename
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-16917 Need to reduce the impact of NFS per-share kstats on failover
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
NEX-16835 Kernel panic during BDD tests at rfs4_compound func
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
NEX-15924 Getting panic: BAD TRAP: type=d (#gp General protection) rp=ffffff0021464690 addr=12
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
NEX-16812 Timing window where dtrace probe could try to access share info after unshared
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
NEX-16452 NFS server in a zone state database needs to be per zone
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
NEX-15279 support NFS server in zone
NEX-15520 online NFS shares cause zoneadm halt to hang in nfs_export_zone_fini
Portions contributed by: Dan Kruchinin dan.kruchinin@nexenta.com
Portions contributed by: Stepan Zastupov stepan.zastupov@gmail.com
Reviewed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
NEX-9275 Got "bad mutex" panic when run IO to nfs share from clients
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
NEX-7366 Getting panic in "module "nfssrv" due to a NULL pointer dereference" when updating NFS shares on a pool
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Steve Peng <steve.peng@nexenta.com>
NEX-6778 NFS kstats leak and cause system to hang
Revert "NEX-4261 Per-client NFS server IOPS, bandwidth, and latency kstats"
This reverts commit 586c3ab1927647487f01c337ddc011c642575a52.
Revert "NEX-5354 Aggregated IOPS, bandwidth, and latency kstats for NFS server"
This reverts commit c91d7614da8618ef48018102b077f60ecbbac8c2.
Revert "NEX-5667 nfssrv_stats_flags does not work for aggregated kstats"
This reverts commit 3dcf42618be7dd5f408c327f429c81e07ca08e74.
Revert "NEX-5750 Time values for aggregated NFS server kstats should be normalized"
This reverts commit 1f4d4f901153b0191027969fa4a8064f9d3b9ee1.
Revert "NEX-5942 Panic in rfs4_minorvers_mismatch() with NFSv4.1 client"
This reverts commit 40766417094a162f5e4cc8786c0fa0a7e5871cd9.
Revert "NEX-5752 NFS server: namespace collision in kstats"
This reverts commit ae81e668db86050da8e483264acb0cce0444a132.
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-6109 NFS client panics in nfssrv when running nfsv4-test basic_ops STC tests
Reviewed by: Gordon Ross <gwr@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
Reviewed by: Jean McCormack <jean.mccormack@nexenta.com>
Reviewed by: Steve Peng <steve.peng@nexenta.com>
NEX-4261 Per-client NFS server IOPS, bandwidth, and latency kstats
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-5134 Deadlock between rfs4_do_lock() and rfs4_op_read()
Reviewed by: Dan Fields <dan.fields@nexenta.com>
Reviewed by: Alek Pinchuk <alek.pinchuk@nexenta.com>
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
NEX-3311 NFSv4: setlock() can spin forever
Reviewed by: Josef 'Jeff' Sipek <josef.sipek@nexenta.com>
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
NEX-3097 IOPS, bandwidth, and latency kstats for NFS server
Reviewed by: Josef 'Jeff' Sipek <josef.sipek@nexenta.com>
NEX-1128 NFS server: Generic uid and gid remapping for AUTH_SYS
Reviewed by: Jan Kryl <jan.kryl@nexenta.com>
OS-72 NULL pointer dereference in rfs4_op_setclientid()
Reviewed by: Dan McDonald <danmcd@nexenta.com>
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/uts/common/fs/nfs/nfs4_srv.c
+++ new/usr/src/uts/common/fs/nfs/nfs4_srv.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
|
↓ open down ↓ |
12 lines elided |
↑ open up ↑ |
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 - * Copyright 2016 Nexenta Systems, Inc. All rights reserved.
24 23 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
25 - * Copyright (c) 2012, 2016 by Delphix. All rights reserved.
26 24 */
27 25
28 26 /*
29 27 * Copyright (c) 1983,1984,1985,1986,1987,1988,1989 AT&T.
30 28 * All Rights Reserved
31 29 */
32 30
31 +/*
32 + * Copyright 2019 Nexenta Systems, Inc.
33 + * Copyright (c) 2012, 2016 by Delphix. All rights reserved.
34 + */
35 +
33 36 #include <sys/param.h>
34 37 #include <sys/types.h>
35 38 #include <sys/systm.h>
36 39 #include <sys/cred.h>
37 40 #include <sys/buf.h>
38 41 #include <sys/vfs.h>
39 42 #include <sys/vfs_opreg.h>
40 43 #include <sys/vnode.h>
41 44 #include <sys/uio.h>
42 45 #include <sys/errno.h>
43 46 #include <sys/sysmacros.h>
44 47 #include <sys/statvfs.h>
45 48 #include <sys/kmem.h>
46 49 #include <sys/dirent.h>
47 50 #include <sys/cmn_err.h>
48 51 #include <sys/debug.h>
49 52 #include <sys/systeminfo.h>
|
↓ open down ↓ |
7 lines elided |
↑ open up ↑ |
50 53 #include <sys/flock.h>
51 54 #include <sys/pathname.h>
52 55 #include <sys/nbmlock.h>
53 56 #include <sys/share.h>
54 57 #include <sys/atomic.h>
55 58 #include <sys/policy.h>
56 59 #include <sys/fem.h>
57 60 #include <sys/sdt.h>
58 61 #include <sys/ddi.h>
59 62 #include <sys/zone.h>
63 +#include <sys/kstat.h>
60 64
61 65 #include <fs/fs_reparse.h>
62 66
63 67 #include <rpc/types.h>
64 68 #include <rpc/auth.h>
65 69 #include <rpc/rpcsec_gss.h>
66 70 #include <rpc/svc.h>
67 71
68 72 #include <nfs/nfs.h>
73 +#include <nfs/nfssys.h>
69 74 #include <nfs/export.h>
70 75 #include <nfs/nfs_cmd.h>
71 76 #include <nfs/lm.h>
72 77 #include <nfs/nfs4.h>
78 +#include <nfs/nfs4_drc.h>
73 79
74 80 #include <sys/strsubr.h>
75 81 #include <sys/strsun.h>
76 82
77 83 #include <inet/common.h>
78 84 #include <inet/ip.h>
79 85 #include <inet/ip6.h>
80 86
81 87 #include <sys/tsol/label.h>
82 88 #include <sys/tsol/tndb.h>
83 89
84 90 #define RFS4_MAXLOCK_TRIES 4 /* Try to get the lock this many times */
85 91 static int rfs4_maxlock_tries = RFS4_MAXLOCK_TRIES;
86 92 #define RFS4_LOCK_DELAY 10 /* Milliseconds */
87 93 static clock_t rfs4_lock_delay = RFS4_LOCK_DELAY;
88 94 extern struct svc_ops rdma_svc_ops;
89 95 extern int nfs_loaned_buffers;
90 96 /* End of Tunables */
91 97
92 98 static int rdma_setup_read_data4(READ4args *, READ4res *);
93 99
94 100 /*
95 101 * Used to bump the stateid4.seqid value and show changes in the stateid
96 102 */
97 103 #define next_stateid(sp) (++(sp)->bits.chgseq)
98 104
99 105 /*
100 106 * RFS4_MINLEN_ENTRY4: XDR-encoded size of smallest possible dirent.
101 107 * This is used to return NFS4ERR_TOOSMALL when clients specify
102 108 * maxcount that isn't large enough to hold the smallest possible
103 109 * XDR encoded dirent.
104 110 *
105 111 * sizeof cookie (8 bytes) +
106 112 * sizeof name_len (4 bytes) +
107 113 * sizeof smallest (padded) name (4 bytes) +
108 114 * sizeof bitmap4_len (12 bytes) + NOTE: we always encode len=2 bm4
109 115 * sizeof attrlist4_len (4 bytes) +
110 116 * sizeof next boolean (4 bytes)
111 117 *
112 118 * RFS4_MINLEN_RDDIR4: XDR-encoded size of READDIR op reply containing
113 119 * the smallest possible entry4 (assumes no attrs requested).
114 120 * sizeof nfsstat4 (4 bytes) +
115 121 * sizeof verifier4 (8 bytes) +
116 122 * sizeof entry4list bool (4 bytes) +
117 123 * sizeof entry4 (36 bytes) +
118 124 * sizeof eof bool (4 bytes)
119 125 *
120 126 * RFS4_MINLEN_RDDIR_BUF: minimum length of buffer server will provide to
121 127 * VOP_READDIR. Its value is the size of the maximum possible dirent
122 128 * for solaris. The DIRENT64_RECLEN macro returns the size of dirent
123 129 * required for a given name length. MAXNAMELEN is the maximum
124 130 * filename length allowed in Solaris. The first two DIRENT64_RECLEN()
125 131 * macros are to allow for . and .. entries -- just a minor tweak to try
126 132 * and guarantee that buffer we give to VOP_READDIR will be large enough
127 133 * to hold ., .., and the largest possible solaris dirent64.
128 134 */
129 135 #define RFS4_MINLEN_ENTRY4 36
130 136 #define RFS4_MINLEN_RDDIR4 (4 + NFS4_VERIFIER_SIZE + 4 + RFS4_MINLEN_ENTRY4 + 4)
131 137 #define RFS4_MINLEN_RDDIR_BUF \
132 138 (DIRENT64_RECLEN(1) + DIRENT64_RECLEN(2) + DIRENT64_RECLEN(MAXNAMELEN))
133 139
134 140 /*
135 141 * It would be better to pad to 4 bytes since that's what XDR would do,
136 142 * but the dirents UFS gives us are already padded to 8, so just take
137 143 * what we're given. Dircount is only a hint anyway. Currently the
138 144 * solaris kernel is ASCII only, so there's no point in calling the
139 145 * UTF8 functions.
|
↓ open down ↓ |
57 lines elided |
↑ open up ↑ |
140 146 *
141 147 * dirent64: named padded to provide 8 byte struct alignment
142 148 * d_ino(8) + d_off(8) + d_reclen(2) + d_name(namelen + null(1) + pad)
143 149 *
144 150 * cookie: uint64_t + utf8namelen: uint_t + utf8name padded to 8 bytes
145 151 *
146 152 */
147 153 #define DIRENT64_TO_DIRCOUNT(dp) \
148 154 (3 * BYTES_PER_XDR_UNIT + DIRENT64_NAMELEN((dp)->d_reclen))
149 155
150 -time_t rfs4_start_time; /* Initialized in rfs4_srvrinit */
156 +zone_key_t rfs4_zone_key;
151 157
152 -static sysid_t lockt_sysid; /* dummy sysid for all LOCKT calls */
158 +static sysid_t lockt_sysid; /* dummy sysid for all LOCKT calls */
153 159
154 160 u_longlong_t nfs4_srv_caller_id;
155 161 uint_t nfs4_srv_vkey = 0;
156 162
157 -verifier4 Write4verf;
158 -verifier4 Readdir4verf;
159 -
160 163 void rfs4_init_compound_state(struct compound_state *);
161 164
162 165 static void nullfree(caddr_t);
163 166 static void rfs4_op_inval(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
164 - struct compound_state *);
167 + struct compound_state *);
165 168 static void rfs4_op_access(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
166 - struct compound_state *);
169 + struct compound_state *);
167 170 static void rfs4_op_close(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
168 - struct compound_state *);
171 + struct compound_state *);
169 172 static void rfs4_op_commit(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
170 - struct compound_state *);
173 + struct compound_state *);
171 174 static void rfs4_op_create(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
172 - struct compound_state *);
175 + struct compound_state *);
173 176 static void rfs4_op_create_free(nfs_resop4 *resop);
174 177 static void rfs4_op_delegreturn(nfs_argop4 *, nfs_resop4 *,
175 - struct svc_req *, struct compound_state *);
178 + struct svc_req *, struct compound_state *);
176 179 static void rfs4_op_delegpurge(nfs_argop4 *, nfs_resop4 *,
177 - struct svc_req *, struct compound_state *);
180 + struct svc_req *, struct compound_state *);
178 181 static void rfs4_op_getattr(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
179 - struct compound_state *);
182 + struct compound_state *);
180 183 static void rfs4_op_getattr_free(nfs_resop4 *);
181 184 static void rfs4_op_getfh(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
182 - struct compound_state *);
185 + struct compound_state *);
183 186 static void rfs4_op_getfh_free(nfs_resop4 *);
184 187 static void rfs4_op_illegal(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
185 - struct compound_state *);
188 + struct compound_state *);
186 189 static void rfs4_op_link(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
187 - struct compound_state *);
190 + struct compound_state *);
188 191 static void rfs4_op_lock(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
189 - struct compound_state *);
192 + struct compound_state *);
190 193 static void lock_denied_free(nfs_resop4 *);
191 194 static void rfs4_op_locku(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
192 - struct compound_state *);
195 + struct compound_state *);
193 196 static void rfs4_op_lockt(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
194 - struct compound_state *);
197 + struct compound_state *);
195 198 static void rfs4_op_lookup(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
196 - struct compound_state *);
199 + struct compound_state *);
197 200 static void rfs4_op_lookupp(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
198 - struct compound_state *);
201 + struct compound_state *);
199 202 static void rfs4_op_openattr(nfs_argop4 *argop, nfs_resop4 *resop,
200 - struct svc_req *req, struct compound_state *cs);
203 + struct svc_req *req, struct compound_state *cs);
201 204 static void rfs4_op_nverify(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
202 - struct compound_state *);
205 + struct compound_state *);
203 206 static void rfs4_op_open(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
204 - struct compound_state *);
207 + struct compound_state *);
205 208 static void rfs4_op_open_confirm(nfs_argop4 *, nfs_resop4 *,
206 - struct svc_req *, struct compound_state *);
209 + struct svc_req *, struct compound_state *);
207 210 static void rfs4_op_open_downgrade(nfs_argop4 *, nfs_resop4 *,
208 - struct svc_req *, struct compound_state *);
211 + struct svc_req *, struct compound_state *);
209 212 static void rfs4_op_putfh(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
210 - struct compound_state *);
213 + struct compound_state *);
211 214 static void rfs4_op_putpubfh(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
212 - struct compound_state *);
215 + struct compound_state *);
213 216 static void rfs4_op_putrootfh(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
214 - struct compound_state *);
217 + struct compound_state *);
215 218 static void rfs4_op_read(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
216 - struct compound_state *);
219 + struct compound_state *);
217 220 static void rfs4_op_read_free(nfs_resop4 *);
218 221 static void rfs4_op_readdir_free(nfs_resop4 *resop);
219 222 static void rfs4_op_readlink(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
220 - struct compound_state *);
223 + struct compound_state *);
221 224 static void rfs4_op_readlink_free(nfs_resop4 *);
222 225 static void rfs4_op_release_lockowner(nfs_argop4 *, nfs_resop4 *,
223 - struct svc_req *, struct compound_state *);
226 + struct svc_req *, struct compound_state *);
224 227 static void rfs4_op_remove(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
225 - struct compound_state *);
228 + struct compound_state *);
226 229 static void rfs4_op_rename(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
227 - struct compound_state *);
230 + struct compound_state *);
228 231 static void rfs4_op_renew(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
229 - struct compound_state *);
232 + struct compound_state *);
230 233 static void rfs4_op_restorefh(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
231 - struct compound_state *);
234 + struct compound_state *);
232 235 static void rfs4_op_savefh(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
233 - struct compound_state *);
236 + struct compound_state *);
234 237 static void rfs4_op_setattr(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
235 - struct compound_state *);
238 + struct compound_state *);
236 239 static void rfs4_op_verify(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
237 - struct compound_state *);
240 + struct compound_state *);
238 241 static void rfs4_op_write(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
239 - struct compound_state *);
242 + struct compound_state *);
240 243 static void rfs4_op_setclientid(nfs_argop4 *, nfs_resop4 *,
241 - struct svc_req *, struct compound_state *);
244 + struct svc_req *, struct compound_state *);
242 245 static void rfs4_op_setclientid_confirm(nfs_argop4 *, nfs_resop4 *,
243 - struct svc_req *req, struct compound_state *);
246 + struct svc_req *req, struct compound_state *);
244 247 static void rfs4_op_secinfo(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
245 - struct compound_state *);
248 + struct compound_state *);
246 249 static void rfs4_op_secinfo_free(nfs_resop4 *);
247 250
248 -static nfsstat4 check_open_access(uint32_t,
249 - struct compound_state *, struct svc_req *);
250 -nfsstat4 rfs4_client_sysid(rfs4_client_t *, sysid_t *);
251 -void rfs4_ss_clid(rfs4_client_t *);
251 +static nfsstat4 check_open_access(uint32_t, struct compound_state *,
252 + struct svc_req *);
253 +nfsstat4 rfs4_client_sysid(rfs4_client_t *, sysid_t *);
254 +void rfs4_ss_clid(nfs4_srv_t *, rfs4_client_t *);
252 255
256 +
253 257 /*
254 258 * translation table for attrs
255 259 */
256 260 struct nfs4_ntov_table {
257 261 union nfs4_attr_u *na;
258 262 uint8_t amap[NFS4_MAXNUM_ATTRS];
259 263 int attrcnt;
260 264 bool_t vfsstat;
261 265 };
262 266
263 267 static void nfs4_ntov_table_init(struct nfs4_ntov_table *ntovp);
264 268 static void nfs4_ntov_table_free(struct nfs4_ntov_table *ntovp,
265 - struct nfs4_svgetit_arg *sargp);
269 + struct nfs4_svgetit_arg *sargp);
266 270
267 271 static nfsstat4 do_rfs4_set_attrs(bitmap4 *resp, fattr4 *fattrp,
268 272 struct compound_state *cs, struct nfs4_svgetit_arg *sargp,
269 273 struct nfs4_ntov_table *ntovp, nfs4_attr_cmd_t cmd);
270 274
275 +static void hanfsv4_failover(nfs4_srv_t *);
276 +
271 277 fem_t *deleg_rdops;
272 278 fem_t *deleg_wrops;
273 279
274 -rfs4_servinst_t *rfs4_cur_servinst = NULL; /* current server instance */
275 -kmutex_t rfs4_servinst_lock; /* protects linked list */
276 -int rfs4_seen_first_compound; /* set first time we see one */
277 -
278 280 /*
279 281 * NFS4 op dispatch table
280 282 */
281 283
282 284 struct rfsv4disp {
283 285 void (*dis_proc)(); /* proc to call */
284 286 void (*dis_resfree)(); /* frees space allocated by proc */
285 287 int dis_flags; /* RPC_IDEMPOTENT, etc... */
288 + int op_type; /* operation type, see below */
286 289 };
287 290
291 +/*
292 + * operation types; used primarily for the per-exportinfo kstat implementation
293 + */
294 +#define NFS4_OP_NOFH 0 /* The operation does not operate with any */
295 + /* particular filehandle; we cannot associate */
296 + /* it with any exportinfo. */
297 +
298 +#define NFS4_OP_CFH 1 /* The operation works with the current */
299 + /* filehandle; we associate the operation */
300 + /* with the exportinfo related to the current */
301 + /* filehandle (as set before the operation is */
302 + /* executed). */
303 +
304 +#define NFS4_OP_SFH 2 /* The operation works with the saved */
305 + /* filehandle; we associate the operation */
306 + /* with the exportinfo related to the saved */
307 + /* filehandle (as set before the operation is */
308 + /* executed). */
309 +
310 +#define NFS4_OP_POSTCFH 3 /* The operation ignores the current */
311 + /* filehandle, but sets the new current */
312 + /* filehandle instead; we associate the */
313 + /* operation with the exportinfo related to */
314 + /* the current filehandle as set after the */
315 + /* operation is successfuly executed. Since */
316 + /* we do not know the particular exportinfo */
317 + /* (and thus the kstat) before the operation */
318 + /* is done, there is no simple way how to */
319 + /* update some I/O kstat statistics related */
320 + /* to kstat_queue(9F). */
321 +
288 322 static struct rfsv4disp rfsv4disptab[] = {
289 323 /*
290 324 * NFS VERSION 4
291 325 */
292 326
293 327 /* RFS_NULL = 0 */
294 - {rfs4_op_illegal, nullfree, 0},
328 + {rfs4_op_illegal, nullfree, 0, NFS4_OP_NOFH},
295 329
296 330 /* UNUSED = 1 */
297 - {rfs4_op_illegal, nullfree, 0},
331 + {rfs4_op_illegal, nullfree, 0, NFS4_OP_NOFH},
298 332
299 333 /* UNUSED = 2 */
300 - {rfs4_op_illegal, nullfree, 0},
334 + {rfs4_op_illegal, nullfree, 0, NFS4_OP_NOFH},
301 335
302 336 /* OP_ACCESS = 3 */
303 - {rfs4_op_access, nullfree, RPC_IDEMPOTENT},
337 + {rfs4_op_access, nullfree, RPC_IDEMPOTENT, NFS4_OP_CFH},
304 338
305 339 /* OP_CLOSE = 4 */
306 - {rfs4_op_close, nullfree, 0},
340 + {rfs4_op_close, nullfree, 0, NFS4_OP_CFH},
307 341
308 342 /* OP_COMMIT = 5 */
309 - {rfs4_op_commit, nullfree, RPC_IDEMPOTENT},
343 + {rfs4_op_commit, nullfree, RPC_IDEMPOTENT, NFS4_OP_CFH},
310 344
311 345 /* OP_CREATE = 6 */
312 - {rfs4_op_create, nullfree, 0},
346 + {rfs4_op_create, nullfree, 0, NFS4_OP_CFH},
313 347
314 348 /* OP_DELEGPURGE = 7 */
315 - {rfs4_op_delegpurge, nullfree, 0},
349 + {rfs4_op_delegpurge, nullfree, 0, NFS4_OP_NOFH},
316 350
317 351 /* OP_DELEGRETURN = 8 */
318 - {rfs4_op_delegreturn, nullfree, 0},
352 + {rfs4_op_delegreturn, nullfree, 0, NFS4_OP_CFH},
319 353
320 354 /* OP_GETATTR = 9 */
321 - {rfs4_op_getattr, rfs4_op_getattr_free, RPC_IDEMPOTENT},
355 + {rfs4_op_getattr, rfs4_op_getattr_free, RPC_IDEMPOTENT, NFS4_OP_CFH},
322 356
323 357 /* OP_GETFH = 10 */
324 - {rfs4_op_getfh, rfs4_op_getfh_free, RPC_ALL},
358 + {rfs4_op_getfh, rfs4_op_getfh_free, RPC_ALL, NFS4_OP_CFH},
325 359
326 360 /* OP_LINK = 11 */
327 - {rfs4_op_link, nullfree, 0},
361 + {rfs4_op_link, nullfree, 0, NFS4_OP_CFH},
328 362
329 363 /* OP_LOCK = 12 */
330 - {rfs4_op_lock, lock_denied_free, 0},
364 + {rfs4_op_lock, lock_denied_free, 0, NFS4_OP_CFH},
331 365
332 366 /* OP_LOCKT = 13 */
333 - {rfs4_op_lockt, lock_denied_free, 0},
367 + {rfs4_op_lockt, lock_denied_free, 0, NFS4_OP_CFH},
334 368
335 369 /* OP_LOCKU = 14 */
336 - {rfs4_op_locku, nullfree, 0},
370 + {rfs4_op_locku, nullfree, 0, NFS4_OP_CFH},
337 371
338 372 /* OP_LOOKUP = 15 */
339 - {rfs4_op_lookup, nullfree, (RPC_IDEMPOTENT | RPC_PUBLICFH_OK)},
373 + {rfs4_op_lookup, nullfree, (RPC_IDEMPOTENT | RPC_PUBLICFH_OK),
374 + NFS4_OP_CFH},
340 375
341 376 /* OP_LOOKUPP = 16 */
342 - {rfs4_op_lookupp, nullfree, (RPC_IDEMPOTENT | RPC_PUBLICFH_OK)},
377 + {rfs4_op_lookupp, nullfree, (RPC_IDEMPOTENT | RPC_PUBLICFH_OK),
378 + NFS4_OP_CFH},
343 379
344 380 /* OP_NVERIFY = 17 */
345 - {rfs4_op_nverify, nullfree, RPC_IDEMPOTENT},
381 + {rfs4_op_nverify, nullfree, RPC_IDEMPOTENT, NFS4_OP_CFH},
346 382
347 383 /* OP_OPEN = 18 */
348 - {rfs4_op_open, rfs4_free_reply, 0},
384 + {rfs4_op_open, rfs4_free_reply, 0, NFS4_OP_CFH},
349 385
350 386 /* OP_OPENATTR = 19 */
351 - {rfs4_op_openattr, nullfree, 0},
387 + {rfs4_op_openattr, nullfree, 0, NFS4_OP_CFH},
352 388
353 389 /* OP_OPEN_CONFIRM = 20 */
354 - {rfs4_op_open_confirm, nullfree, 0},
390 + {rfs4_op_open_confirm, nullfree, 0, NFS4_OP_CFH},
355 391
356 392 /* OP_OPEN_DOWNGRADE = 21 */
357 - {rfs4_op_open_downgrade, nullfree, 0},
393 + {rfs4_op_open_downgrade, nullfree, 0, NFS4_OP_CFH},
358 394
359 395 /* OP_OPEN_PUTFH = 22 */
360 - {rfs4_op_putfh, nullfree, RPC_ALL},
396 + {rfs4_op_putfh, nullfree, RPC_ALL, NFS4_OP_POSTCFH},
361 397
362 398 /* OP_PUTPUBFH = 23 */
363 - {rfs4_op_putpubfh, nullfree, RPC_ALL},
399 + {rfs4_op_putpubfh, nullfree, RPC_ALL, NFS4_OP_POSTCFH},
364 400
365 401 /* OP_PUTROOTFH = 24 */
366 - {rfs4_op_putrootfh, nullfree, RPC_ALL},
402 + {rfs4_op_putrootfh, nullfree, RPC_ALL, NFS4_OP_POSTCFH},
367 403
368 404 /* OP_READ = 25 */
369 - {rfs4_op_read, rfs4_op_read_free, RPC_IDEMPOTENT},
405 + {rfs4_op_read, rfs4_op_read_free, RPC_IDEMPOTENT, NFS4_OP_CFH},
370 406
371 407 /* OP_READDIR = 26 */
372 - {rfs4_op_readdir, rfs4_op_readdir_free, RPC_IDEMPOTENT},
408 + {rfs4_op_readdir, rfs4_op_readdir_free, RPC_IDEMPOTENT, NFS4_OP_CFH},
373 409
374 410 /* OP_READLINK = 27 */
375 - {rfs4_op_readlink, rfs4_op_readlink_free, RPC_IDEMPOTENT},
411 + {rfs4_op_readlink, rfs4_op_readlink_free, RPC_IDEMPOTENT, NFS4_OP_CFH},
376 412
377 413 /* OP_REMOVE = 28 */
378 - {rfs4_op_remove, nullfree, 0},
414 + {rfs4_op_remove, nullfree, 0, NFS4_OP_CFH},
379 415
380 416 /* OP_RENAME = 29 */
381 - {rfs4_op_rename, nullfree, 0},
417 + {rfs4_op_rename, nullfree, 0, NFS4_OP_CFH},
382 418
383 419 /* OP_RENEW = 30 */
384 - {rfs4_op_renew, nullfree, 0},
420 + {rfs4_op_renew, nullfree, 0, NFS4_OP_NOFH},
385 421
386 422 /* OP_RESTOREFH = 31 */
387 - {rfs4_op_restorefh, nullfree, RPC_ALL},
423 + {rfs4_op_restorefh, nullfree, RPC_ALL, NFS4_OP_SFH},
388 424
389 425 /* OP_SAVEFH = 32 */
390 - {rfs4_op_savefh, nullfree, RPC_ALL},
426 + {rfs4_op_savefh, nullfree, RPC_ALL, NFS4_OP_CFH},
391 427
392 428 /* OP_SECINFO = 33 */
393 - {rfs4_op_secinfo, rfs4_op_secinfo_free, 0},
429 + {rfs4_op_secinfo, rfs4_op_secinfo_free, 0, NFS4_OP_CFH},
394 430
395 431 /* OP_SETATTR = 34 */
396 - {rfs4_op_setattr, nullfree, 0},
432 + {rfs4_op_setattr, nullfree, 0, NFS4_OP_CFH},
397 433
398 434 /* OP_SETCLIENTID = 35 */
399 - {rfs4_op_setclientid, nullfree, 0},
435 + {rfs4_op_setclientid, nullfree, 0, NFS4_OP_NOFH},
400 436
401 437 /* OP_SETCLIENTID_CONFIRM = 36 */
402 - {rfs4_op_setclientid_confirm, nullfree, 0},
438 + {rfs4_op_setclientid_confirm, nullfree, 0, NFS4_OP_NOFH},
403 439
404 440 /* OP_VERIFY = 37 */
405 - {rfs4_op_verify, nullfree, RPC_IDEMPOTENT},
441 + {rfs4_op_verify, nullfree, RPC_IDEMPOTENT, NFS4_OP_CFH},
406 442
407 443 /* OP_WRITE = 38 */
408 - {rfs4_op_write, nullfree, 0},
444 + {rfs4_op_write, nullfree, 0, NFS4_OP_CFH},
409 445
410 446 /* OP_RELEASE_LOCKOWNER = 39 */
411 - {rfs4_op_release_lockowner, nullfree, 0},
447 + {rfs4_op_release_lockowner, nullfree, 0, NFS4_OP_NOFH},
412 448 };
413 449
414 450 static uint_t rfsv4disp_cnt = sizeof (rfsv4disptab) / sizeof (rfsv4disptab[0]);
415 451
416 452 #define OP_ILLEGAL_IDX (rfsv4disp_cnt)
417 453
418 454 #ifdef DEBUG
419 455
420 456 int rfs4_fillone_debug = 0;
421 457 int rfs4_no_stub_access = 1;
422 458 int rfs4_rddir_debug = 0;
423 459
424 460 static char *rfs4_op_string[] = {
425 461 "rfs4_op_null",
426 462 "rfs4_op_1 unused",
427 463 "rfs4_op_2 unused",
428 464 "rfs4_op_access",
429 465 "rfs4_op_close",
430 466 "rfs4_op_commit",
431 467 "rfs4_op_create",
432 468 "rfs4_op_delegpurge",
433 469 "rfs4_op_delegreturn",
434 470 "rfs4_op_getattr",
435 471 "rfs4_op_getfh",
436 472 "rfs4_op_link",
437 473 "rfs4_op_lock",
438 474 "rfs4_op_lockt",
439 475 "rfs4_op_locku",
440 476 "rfs4_op_lookup",
441 477 "rfs4_op_lookupp",
442 478 "rfs4_op_nverify",
443 479 "rfs4_op_open",
444 480 "rfs4_op_openattr",
445 481 "rfs4_op_open_confirm",
446 482 "rfs4_op_open_downgrade",
447 483 "rfs4_op_putfh",
448 484 "rfs4_op_putpubfh",
449 485 "rfs4_op_putrootfh",
450 486 "rfs4_op_read",
451 487 "rfs4_op_readdir",
452 488 "rfs4_op_readlink",
453 489 "rfs4_op_remove",
454 490 "rfs4_op_rename",
455 491 "rfs4_op_renew",
456 492 "rfs4_op_restorefh",
457 493 "rfs4_op_savefh",
458 494 "rfs4_op_secinfo",
|
↓ open down ↓ |
37 lines elided |
↑ open up ↑ |
459 495 "rfs4_op_setattr",
460 496 "rfs4_op_setclientid",
461 497 "rfs4_op_setclient_confirm",
462 498 "rfs4_op_verify",
463 499 "rfs4_op_write",
464 500 "rfs4_op_release_lockowner",
465 501 "rfs4_op_illegal"
466 502 };
467 503 #endif
468 504
469 -void rfs4_ss_chkclid(rfs4_client_t *);
505 +void rfs4_ss_chkclid(nfs4_srv_t *, rfs4_client_t *);
470 506
471 507 extern size_t strlcpy(char *dst, const char *src, size_t dstsize);
472 508
473 509 extern void rfs4_free_fs_locations4(fs_locations4 *);
474 510
475 511 #ifdef nextdp
476 512 #undef nextdp
477 513 #endif
478 514 #define nextdp(dp) ((struct dirent64 *)((char *)(dp) + (dp)->d_reclen))
479 515
480 516 static const fs_operation_def_t nfs4_rd_deleg_tmpl[] = {
481 517 VOPNAME_OPEN, { .femop_open = deleg_rd_open },
482 518 VOPNAME_WRITE, { .femop_write = deleg_rd_write },
483 519 VOPNAME_SETATTR, { .femop_setattr = deleg_rd_setattr },
484 520 VOPNAME_RWLOCK, { .femop_rwlock = deleg_rd_rwlock },
485 521 VOPNAME_SPACE, { .femop_space = deleg_rd_space },
486 522 VOPNAME_SETSECATTR, { .femop_setsecattr = deleg_rd_setsecattr },
487 523 VOPNAME_VNEVENT, { .femop_vnevent = deleg_rd_vnevent },
488 524 NULL, NULL
489 525 };
490 526 static const fs_operation_def_t nfs4_wr_deleg_tmpl[] = {
491 527 VOPNAME_OPEN, { .femop_open = deleg_wr_open },
|
↓ open down ↓ |
12 lines elided |
↑ open up ↑ |
492 528 VOPNAME_READ, { .femop_read = deleg_wr_read },
493 529 VOPNAME_WRITE, { .femop_write = deleg_wr_write },
494 530 VOPNAME_SETATTR, { .femop_setattr = deleg_wr_setattr },
495 531 VOPNAME_RWLOCK, { .femop_rwlock = deleg_wr_rwlock },
496 532 VOPNAME_SPACE, { .femop_space = deleg_wr_space },
497 533 VOPNAME_SETSECATTR, { .femop_setsecattr = deleg_wr_setsecattr },
498 534 VOPNAME_VNEVENT, { .femop_vnevent = deleg_wr_vnevent },
499 535 NULL, NULL
500 536 };
501 537
502 -int
503 -rfs4_srvrinit(void)
538 +/* ARGSUSED */
539 +static void *
540 +rfs4_zone_init(zoneid_t zoneid)
504 541 {
542 + nfs4_srv_t *nsrv4;
505 543 timespec32_t verf;
506 - int error;
507 - extern void rfs4_attr_init();
508 - extern krwlock_t rfs4_deleg_policy_lock;
509 544
545 + nsrv4 = kmem_zalloc(sizeof (*nsrv4), KM_SLEEP);
546 +
510 547 /*
511 548 * The following algorithm attempts to find a unique verifier
512 549 * to be used as the write verifier returned from the server
513 550 * to the client. It is important that this verifier change
514 551 * whenever the server reboots. Of secondary importance, it
515 552 * is important for the verifier to be unique between two
516 553 * different servers.
517 554 *
518 555 * Thus, an attempt is made to use the system hostid and the
519 556 * current time in seconds when the nfssrv kernel module is
520 557 * loaded. It is assumed that an NFS server will not be able
521 558 * to boot and then to reboot in less than a second. If the
522 559 * hostid has not been set, then the current high resolution
523 560 * time is used. This will ensure different verifiers each
524 561 * time the server reboots and minimize the chances that two
525 562 * different servers will have the same verifier.
526 563 * XXX - this is broken on LP64 kernels.
527 564 */
|
↓ open down ↓ |
8 lines elided |
↑ open up ↑ |
528 565 verf.tv_sec = (time_t)zone_get_hostid(NULL);
529 566 if (verf.tv_sec != 0) {
530 567 verf.tv_nsec = gethrestime_sec();
531 568 } else {
532 569 timespec_t tverf;
533 570
534 571 gethrestime(&tverf);
535 572 verf.tv_sec = (time_t)tverf.tv_sec;
536 573 verf.tv_nsec = tverf.tv_nsec;
537 574 }
575 + nsrv4->write4verf = *(uint64_t *)&verf;
538 576
539 - Write4verf = *(uint64_t *)&verf;
577 + /* Used to manage create/destroy of server state */
578 + nsrv4->nfs4_server_state = NULL;
579 + nsrv4->nfs4_cur_servinst = NULL;
580 + nsrv4->nfs4_deleg_policy = SRV_NEVER_DELEGATE;
581 + mutex_init(&nsrv4->deleg_lock, NULL, MUTEX_DEFAULT, NULL);
582 + mutex_init(&nsrv4->state_lock, NULL, MUTEX_DEFAULT, NULL);
583 + mutex_init(&nsrv4->servinst_lock, NULL, MUTEX_DEFAULT, NULL);
584 + rw_init(&nsrv4->deleg_policy_lock, NULL, RW_DEFAULT, NULL);
540 585
541 - rfs4_attr_init();
542 - mutex_init(&rfs4_deleg_lock, NULL, MUTEX_DEFAULT, NULL);
586 + return (nsrv4);
587 +}
543 588
544 - /* Used to manage create/destroy of server state */
545 - mutex_init(&rfs4_state_lock, NULL, MUTEX_DEFAULT, NULL);
589 +/* ARGSUSED */
590 +static void
591 +rfs4_zone_fini(zoneid_t zoneid, void *data)
592 +{
593 + nfs4_srv_t *nsrv4 = data;
546 594
547 - /* Used to manage access to server instance linked list */
548 - mutex_init(&rfs4_servinst_lock, NULL, MUTEX_DEFAULT, NULL);
595 + mutex_destroy(&nsrv4->deleg_lock);
596 + mutex_destroy(&nsrv4->state_lock);
597 + mutex_destroy(&nsrv4->servinst_lock);
598 + rw_destroy(&nsrv4->deleg_policy_lock);
549 599
550 - /* Used to manage access to rfs4_deleg_policy */
551 - rw_init(&rfs4_deleg_policy_lock, NULL, RW_DEFAULT, NULL);
600 + kmem_free(nsrv4, sizeof (*nsrv4));
601 +}
552 602
553 - error = fem_create("deleg_rdops", nfs4_rd_deleg_tmpl, &deleg_rdops);
554 - if (error != 0) {
603 +void
604 +rfs4_srvrinit(void)
605 +{
606 + extern void rfs4_attr_init();
607 +
608 + zone_key_create(&rfs4_zone_key, rfs4_zone_init, NULL, rfs4_zone_fini);
609 +
610 + rfs4_attr_init();
611 +
612 +
613 + if (fem_create("deleg_rdops", nfs4_rd_deleg_tmpl, &deleg_rdops) != 0) {
555 614 rfs4_disable_delegation();
556 - } else {
557 - error = fem_create("deleg_wrops", nfs4_wr_deleg_tmpl,
558 - &deleg_wrops);
559 - if (error != 0) {
560 - rfs4_disable_delegation();
561 - fem_free(deleg_rdops);
562 - }
615 + } else if (fem_create("deleg_wrops", nfs4_wr_deleg_tmpl,
616 + &deleg_wrops) != 0) {
617 + rfs4_disable_delegation();
618 + fem_free(deleg_rdops);
563 619 }
564 620
565 621 nfs4_srv_caller_id = fs_new_caller_id();
566 -
567 622 lockt_sysid = lm_alloc_sysidt();
568 -
569 623 vsd_create(&nfs4_srv_vkey, NULL);
570 -
571 - return (0);
624 + rfs4_state_g_init();
572 625 }
573 626
574 627 void
575 628 rfs4_srvrfini(void)
576 629 {
577 - extern krwlock_t rfs4_deleg_policy_lock;
578 -
579 630 if (lockt_sysid != LM_NOSYSID) {
580 631 lm_free_sysidt(lockt_sysid);
581 632 lockt_sysid = LM_NOSYSID;
582 633 }
583 634
584 - mutex_destroy(&rfs4_deleg_lock);
585 - mutex_destroy(&rfs4_state_lock);
586 - rw_destroy(&rfs4_deleg_policy_lock);
635 + rfs4_state_g_fini();
587 636
588 637 fem_free(deleg_rdops);
589 638 fem_free(deleg_wrops);
639 +
640 + (void) zone_key_delete(rfs4_zone_key);
590 641 }
591 642
592 643 void
644 +rfs4_do_server_start(int server_upordown,
645 + int srv_delegation, int cluster_booted)
646 +{
647 + nfs4_srv_t *nsrv4 = zone_getspecific(rfs4_zone_key, curzone);
648 +
649 + /* Is this a warm start? */
650 + if (server_upordown == NFS_SERVER_QUIESCED) {
651 + cmn_err(CE_NOTE, "nfs4_srv: "
652 + "server was previously quiesced; "
653 + "existing NFSv4 state will be re-used");
654 +
655 + /*
656 + * HA-NFSv4: this is also the signal
657 + * that a Resource Group failover has
658 + * occurred.
659 + */
660 + if (cluster_booted)
661 + hanfsv4_failover(nsrv4);
662 + } else {
663 + /* Cold start */
664 + nsrv4->rfs4_start_time = 0;
665 + rfs4_state_zone_init(nsrv4);
666 + nsrv4->nfs4_drc = rfs4_init_drc(nfs4_drc_max,
667 + nfs4_drc_hash);
668 + }
669 +
670 + /* Check if delegation is to be enabled */
671 + if (srv_delegation != FALSE)
672 + rfs4_set_deleg_policy(nsrv4, SRV_NORMAL_DELEGATE);
673 +}
674 +
675 +void
593 676 rfs4_init_compound_state(struct compound_state *cs)
594 677 {
595 678 bzero(cs, sizeof (*cs));
596 679 cs->cont = TRUE;
597 680 cs->access = CS_ACCESS_DENIED;
598 681 cs->deleg = FALSE;
599 682 cs->mandlock = FALSE;
600 683 cs->fh.nfs_fh4_val = cs->fhbuf;
684 + cs->statusp = NULL;
601 685 }
602 686
603 687 void
604 688 rfs4_grace_start(rfs4_servinst_t *sip)
605 689 {
606 690 rw_enter(&sip->rwlock, RW_WRITER);
607 691 sip->start_time = (time_t)TICK_TO_SEC(ddi_get_lbolt());
608 692 sip->grace_period = rfs4_grace_period;
609 693 rw_exit(&sip->rwlock);
610 694 }
611 695
612 696 /*
613 697 * returns true if the instance's grace period has never been started
614 698 */
615 699 int
616 700 rfs4_servinst_grace_new(rfs4_servinst_t *sip)
617 701 {
618 702 time_t start_time;
619 703
620 704 rw_enter(&sip->rwlock, RW_READER);
621 705 start_time = sip->start_time;
622 706 rw_exit(&sip->rwlock);
623 707
624 708 return (start_time == 0);
625 709 }
626 710
627 711 /*
628 712 * Indicates if server instance is within the
629 713 * grace period.
630 714 */
631 715 int
632 716 rfs4_servinst_in_grace(rfs4_servinst_t *sip)
633 717 {
634 718 time_t grace_expiry;
635 719
636 720 rw_enter(&sip->rwlock, RW_READER);
637 721 grace_expiry = sip->start_time + sip->grace_period;
638 722 rw_exit(&sip->rwlock);
639 723
640 724 return (((time_t)TICK_TO_SEC(ddi_get_lbolt())) < grace_expiry);
641 725 }
642 726
643 727 int
644 728 rfs4_clnt_in_grace(rfs4_client_t *cp)
|
↓ open down ↓ |
34 lines elided |
↑ open up ↑ |
645 729 {
646 730 ASSERT(rfs4_dbe_refcnt(cp->rc_dbe) > 0);
647 731
648 732 return (rfs4_servinst_in_grace(cp->rc_server_instance));
649 733 }
650 734
651 735 /*
652 736 * reset all currently active grace periods
653 737 */
654 738 void
655 -rfs4_grace_reset_all(void)
739 +rfs4_grace_reset_all(nfs4_srv_t *nsrv4)
656 740 {
657 741 rfs4_servinst_t *sip;
658 742
659 - mutex_enter(&rfs4_servinst_lock);
660 - for (sip = rfs4_cur_servinst; sip != NULL; sip = sip->prev)
743 + mutex_enter(&nsrv4->servinst_lock);
744 + for (sip = nsrv4->nfs4_cur_servinst; sip != NULL; sip = sip->prev)
661 745 if (rfs4_servinst_in_grace(sip))
662 746 rfs4_grace_start(sip);
663 - mutex_exit(&rfs4_servinst_lock);
747 + mutex_exit(&nsrv4->servinst_lock);
664 748 }
665 749
666 750 /*
667 751 * start any new instances' grace periods
668 752 */
669 753 void
670 -rfs4_grace_start_new(void)
754 +rfs4_grace_start_new(nfs4_srv_t *nsrv4)
671 755 {
672 756 rfs4_servinst_t *sip;
673 757
674 - mutex_enter(&rfs4_servinst_lock);
675 - for (sip = rfs4_cur_servinst; sip != NULL; sip = sip->prev)
758 + mutex_enter(&nsrv4->servinst_lock);
759 + for (sip = nsrv4->nfs4_cur_servinst; sip != NULL; sip = sip->prev)
676 760 if (rfs4_servinst_grace_new(sip))
677 761 rfs4_grace_start(sip);
678 - mutex_exit(&rfs4_servinst_lock);
762 + mutex_exit(&nsrv4->servinst_lock);
679 763 }
680 764
681 765 static rfs4_dss_path_t *
682 -rfs4_dss_newpath(rfs4_servinst_t *sip, char *path, unsigned index)
766 +rfs4_dss_newpath(nfs4_srv_t *nsrv4, rfs4_servinst_t *sip,
767 + char *path, unsigned index)
683 768 {
684 769 size_t len;
685 770 rfs4_dss_path_t *dss_path;
686 771
687 772 dss_path = kmem_alloc(sizeof (rfs4_dss_path_t), KM_SLEEP);
688 773
689 774 /*
690 775 * Take a copy of the string, since the original may be overwritten.
691 776 * Sadly, no strdup() in the kernel.
692 777 */
693 778 /* allow for NUL */
694 779 len = strlen(path) + 1;
695 780 dss_path->path = kmem_alloc(len, KM_SLEEP);
|
↓ open down ↓ |
3 lines elided |
↑ open up ↑ |
696 781 (void) strlcpy(dss_path->path, path, len);
697 782
698 783 /* associate with servinst */
699 784 dss_path->sip = sip;
700 785 dss_path->index = index;
701 786
702 787 /*
703 788 * Add to list of served paths.
704 789 * No locking required, as we're only ever called at startup.
705 790 */
706 - if (rfs4_dss_pathlist == NULL) {
791 + if (nsrv4->dss_pathlist == NULL) {
707 792 /* this is the first dss_path_t */
708 793
709 794 /* needed for insque/remque */
710 795 dss_path->next = dss_path->prev = dss_path;
711 796
712 - rfs4_dss_pathlist = dss_path;
797 + nsrv4->dss_pathlist = dss_path;
713 798 } else {
714 - insque(dss_path, rfs4_dss_pathlist);
799 + insque(dss_path, nsrv4->dss_pathlist);
715 800 }
716 801
717 802 return (dss_path);
718 803 }
719 804
720 805 /*
721 806 * Create a new server instance, and make it the currently active instance.
722 807 * Note that starting the grace period too early will reduce the clients'
723 808 * recovery window.
724 809 */
725 810 void
726 -rfs4_servinst_create(int start_grace, int dss_npaths, char **dss_paths)
811 +rfs4_servinst_create(nfs4_srv_t *nsrv4, int start_grace,
812 + int dss_npaths, char **dss_paths)
727 813 {
728 814 unsigned i;
729 815 rfs4_servinst_t *sip;
730 816 rfs4_oldstate_t *oldstate;
731 817
732 818 sip = kmem_alloc(sizeof (rfs4_servinst_t), KM_SLEEP);
733 819 rw_init(&sip->rwlock, NULL, RW_DEFAULT, NULL);
734 820
735 821 sip->start_time = (time_t)0;
736 822 sip->grace_period = (time_t)0;
737 823 sip->next = NULL;
738 824 sip->prev = NULL;
739 825
740 826 rw_init(&sip->oldstate_lock, NULL, RW_DEFAULT, NULL);
741 827 /*
742 828 * This initial dummy entry is required to setup for insque/remque.
743 829 * It must be skipped over whenever the list is traversed.
744 830 */
745 831 oldstate = kmem_alloc(sizeof (rfs4_oldstate_t), KM_SLEEP);
746 832 /* insque/remque require initial list entry to be self-terminated */
|
↓ open down ↓ |
10 lines elided |
↑ open up ↑ |
747 833 oldstate->next = oldstate;
748 834 oldstate->prev = oldstate;
749 835 sip->oldstate = oldstate;
750 836
751 837
752 838 sip->dss_npaths = dss_npaths;
753 839 sip->dss_paths = kmem_alloc(dss_npaths *
754 840 sizeof (rfs4_dss_path_t *), KM_SLEEP);
755 841
756 842 for (i = 0; i < dss_npaths; i++) {
757 - sip->dss_paths[i] = rfs4_dss_newpath(sip, dss_paths[i], i);
843 + /* CSTYLED */
844 + sip->dss_paths[i] = rfs4_dss_newpath(nsrv4, sip, dss_paths[i], i);
758 845 }
759 846
760 - mutex_enter(&rfs4_servinst_lock);
761 - if (rfs4_cur_servinst != NULL) {
847 + mutex_enter(&nsrv4->servinst_lock);
848 + if (nsrv4->nfs4_cur_servinst != NULL) {
762 849 /* add to linked list */
763 - sip->prev = rfs4_cur_servinst;
764 - rfs4_cur_servinst->next = sip;
850 + sip->prev = nsrv4->nfs4_cur_servinst;
851 + nsrv4->nfs4_cur_servinst->next = sip;
765 852 }
766 853 if (start_grace)
767 854 rfs4_grace_start(sip);
768 855 /* make the new instance "current" */
769 - rfs4_cur_servinst = sip;
856 + nsrv4->nfs4_cur_servinst = sip;
770 857
771 - mutex_exit(&rfs4_servinst_lock);
858 + mutex_exit(&nsrv4->servinst_lock);
772 859 }
773 860
774 861 /*
775 862 * In future, we might add a rfs4_servinst_destroy(sip) but, for now, destroy
776 863 * all instances directly.
777 864 */
778 865 void
779 -rfs4_servinst_destroy_all(void)
866 +rfs4_servinst_destroy_all(nfs4_srv_t *nsrv4)
780 867 {
781 868 rfs4_servinst_t *sip, *prev, *current;
782 869 #ifdef DEBUG
783 870 int n = 0;
784 871 #endif
785 872
786 - mutex_enter(&rfs4_servinst_lock);
787 - ASSERT(rfs4_cur_servinst != NULL);
788 - current = rfs4_cur_servinst;
789 - rfs4_cur_servinst = NULL;
873 + mutex_enter(&nsrv4->servinst_lock);
874 + ASSERT(nsrv4->nfs4_cur_servinst != NULL);
875 + current = nsrv4->nfs4_cur_servinst;
876 + nsrv4->nfs4_cur_servinst = NULL;
790 877 for (sip = current; sip != NULL; sip = prev) {
791 878 prev = sip->prev;
792 879 rw_destroy(&sip->rwlock);
793 880 if (sip->oldstate)
794 881 kmem_free(sip->oldstate, sizeof (rfs4_oldstate_t));
795 882 if (sip->dss_paths)
796 883 kmem_free(sip->dss_paths,
797 884 sip->dss_npaths * sizeof (rfs4_dss_path_t *));
798 885 kmem_free(sip, sizeof (rfs4_servinst_t));
799 886 #ifdef DEBUG
800 887 n++;
801 888 #endif
802 889 }
803 - mutex_exit(&rfs4_servinst_lock);
890 + mutex_exit(&nsrv4->servinst_lock);
804 891 }
805 892
806 893 /*
807 894 * Assign the current server instance to a client_t.
808 895 * Should be called with cp->rc_dbe held.
809 896 */
810 897 void
811 -rfs4_servinst_assign(rfs4_client_t *cp, rfs4_servinst_t *sip)
898 +rfs4_servinst_assign(nfs4_srv_t *nsrv4, rfs4_client_t *cp,
899 + rfs4_servinst_t *sip)
812 900 {
813 901 ASSERT(rfs4_dbe_refcnt(cp->rc_dbe) > 0);
814 902
815 903 /*
816 904 * The lock ensures that if the current instance is in the process
817 905 * of changing, we will see the new one.
818 906 */
819 - mutex_enter(&rfs4_servinst_lock);
907 + mutex_enter(&nsrv4->servinst_lock);
820 908 cp->rc_server_instance = sip;
821 - mutex_exit(&rfs4_servinst_lock);
909 + mutex_exit(&nsrv4->servinst_lock);
822 910 }
823 911
824 912 rfs4_servinst_t *
825 913 rfs4_servinst(rfs4_client_t *cp)
826 914 {
827 915 ASSERT(rfs4_dbe_refcnt(cp->rc_dbe) > 0);
828 916
829 917 return (cp->rc_server_instance);
830 918 }
831 919
832 920 /* ARGSUSED */
833 921 static void
834 922 nullfree(caddr_t resop)
835 923 {
836 924 }
837 925
838 926 /*
839 927 * This is a fall-through for invalid or not implemented (yet) ops
840 928 */
841 929 /* ARGSUSED */
842 930 static void
843 931 rfs4_op_inval(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
844 932 struct compound_state *cs)
845 933 {
846 934 *cs->statusp = *((nfsstat4 *)&(resop)->nfs_resop4_u) = NFS4ERR_INVAL;
847 935 }
848 936
849 937 /*
850 938 * Check if the security flavor, nfsnum, is in the flavor_list.
851 939 */
852 940 bool_t
853 941 in_flavor_list(int nfsnum, int *flavor_list, int count)
854 942 {
855 943 int i;
856 944
857 945 for (i = 0; i < count; i++) {
858 946 if (nfsnum == flavor_list[i])
859 947 return (TRUE);
860 948 }
861 949 return (FALSE);
862 950 }
863 951
864 952 /*
865 953 * Used by rfs4_op_secinfo to get the security information from the
866 954 * export structure associated with the component.
867 955 */
868 956 /* ARGSUSED */
869 957 static nfsstat4
870 958 do_rfs4_op_secinfo(struct compound_state *cs, char *nm, SECINFO4res *resp)
871 959 {
|
↓ open down ↓ |
40 lines elided |
↑ open up ↑ |
872 960 int error, different_export = 0;
873 961 vnode_t *dvp, *vp;
874 962 struct exportinfo *exi = NULL;
875 963 fid_t fid;
876 964 uint_t count, i;
877 965 secinfo4 *resok_val;
878 966 struct secinfo *secp;
879 967 seconfig_t *si;
880 968 bool_t did_traverse = FALSE;
881 969 int dotdot, walk;
970 + nfs_export_t *ne = nfs_get_export();
882 971
883 972 dvp = cs->vp;
884 973 dotdot = (nm[0] == '.' && nm[1] == '.' && nm[2] == '\0');
885 974
886 975 /*
887 976 * If dotdotting, then need to check whether it's above the
888 977 * root of a filesystem, or above an export point.
889 978 */
890 979 if (dotdot) {
891 980
892 981 /*
|
↓ open down ↓ |
1 lines elided |
↑ open up ↑ |
893 982 * If dotdotting at the root of a filesystem, then
894 983 * need to traverse back to the mounted-on filesystem
895 984 * and do the dotdot lookup there.
896 985 */
897 986 if (cs->vp->v_flag & VROOT) {
898 987
899 988 /*
900 989 * If at the system root, then can
901 990 * go up no further.
902 991 */
903 - if (VN_CMP(dvp, rootdir))
992 + if (VN_CMP(dvp, ZONE_ROOTVP()))
904 993 return (puterrno4(ENOENT));
905 994
906 995 /*
907 996 * Traverse back to the mounted-on filesystem
908 997 */
909 998 dvp = untraverse(cs->vp);
910 999
911 1000 /*
912 1001 * Set the different_export flag so we remember
913 1002 * to pick up a new exportinfo entry for
914 1003 * this new filesystem.
915 1004 */
916 1005 different_export = 1;
917 1006 } else {
918 1007
919 1008 /*
920 1009 * If dotdotting above an export point then set
921 1010 * the different_export to get new export info.
922 1011 */
923 1012 different_export = nfs_exported(cs->exi, cs->vp);
924 1013 }
925 1014 }
926 1015
927 1016 /*
928 1017 * Get the vnode for the component "nm".
929 1018 */
930 1019 error = VOP_LOOKUP(dvp, nm, &vp, NULL, 0, NULL, cs->cr,
931 1020 NULL, NULL, NULL);
932 1021 if (error)
933 1022 return (puterrno4(error));
934 1023
935 1024 /*
936 1025 * If the vnode is in a pseudo filesystem, or if the security flavor
937 1026 * used in the request is valid but not an explicitly shared flavor,
938 1027 * or the access bit indicates that this is a limited access,
939 1028 * check whether this vnode is visible.
940 1029 */
941 1030 if (!different_export &&
942 1031 (PSEUDO(cs->exi) || ! is_exported_sec(cs->nfsflavor, cs->exi) ||
943 1032 cs->access & CS_ACCESS_LIMITED)) {
944 1033 if (! nfs_visible(cs->exi, vp, &different_export)) {
945 1034 VN_RELE(vp);
946 1035 return (puterrno4(ENOENT));
947 1036 }
948 1037 }
949 1038
950 1039 /*
951 1040 * If it's a mountpoint, then traverse it.
952 1041 */
953 1042 if (vn_ismntpt(vp)) {
954 1043 if ((error = traverse(&vp)) != 0) {
955 1044 VN_RELE(vp);
956 1045 return (puterrno4(error));
957 1046 }
958 1047 /* remember that we had to traverse mountpoint */
959 1048 did_traverse = TRUE;
960 1049 different_export = 1;
961 1050 } else if (vp->v_vfsp != dvp->v_vfsp) {
962 1051 /*
963 1052 * If vp isn't a mountpoint and the vfs ptrs aren't the same,
964 1053 * then vp is probably an LOFS object. We don't need the
965 1054 * realvp, we just need to know that we might have crossed
966 1055 * a server fs boundary and need to call checkexport4.
967 1056 * (LOFS lookup hides server fs mountpoints, and actually calls
968 1057 * traverse)
969 1058 */
970 1059 different_export = 1;
971 1060 }
972 1061
973 1062 /*
974 1063 * Get the export information for it.
975 1064 */
976 1065 if (different_export) {
977 1066
978 1067 bzero(&fid, sizeof (fid));
979 1068 fid.fid_len = MAXFIDSZ;
980 1069 error = vop_fid_pseudo(vp, &fid);
981 1070 if (error) {
982 1071 VN_RELE(vp);
983 1072 return (puterrno4(error));
984 1073 }
985 1074
986 1075 if (dotdot)
987 1076 exi = nfs_vptoexi(NULL, vp, cs->cr, &walk, NULL, TRUE);
988 1077 else
989 1078 exi = checkexport4(&vp->v_vfsp->vfs_fsid, &fid, vp);
990 1079
991 1080 if (exi == NULL) {
992 1081 if (did_traverse == TRUE) {
993 1082 /*
994 1083 * If this vnode is a mounted-on vnode,
995 1084 * but the mounted-on file system is not
996 1085 * exported, send back the secinfo for
997 1086 * the exported node that the mounted-on
998 1087 * vnode lives in.
999 1088 */
1000 1089 exi = cs->exi;
1001 1090 } else {
1002 1091 VN_RELE(vp);
1003 1092 return (puterrno4(EACCES));
1004 1093 }
1005 1094 }
1006 1095 } else {
1007 1096 exi = cs->exi;
1008 1097 }
1009 1098 ASSERT(exi != NULL);
|
↓ open down ↓ |
96 lines elided |
↑ open up ↑ |
1010 1099
1011 1100
1012 1101 /*
1013 1102 * Create the secinfo result based on the security information
1014 1103 * from the exportinfo structure (exi).
1015 1104 *
1016 1105 * Return all flavors for a pseudo node.
1017 1106 * For a real export node, return the flavor that the client
1018 1107 * has access with.
1019 1108 */
1020 - ASSERT(RW_LOCK_HELD(&exported_lock));
1109 + ASSERT(RW_LOCK_HELD(&ne->exported_lock));
1021 1110 if (PSEUDO(exi)) {
1022 1111 count = exi->exi_export.ex_seccnt; /* total sec count */
1023 1112 resok_val = kmem_alloc(count * sizeof (secinfo4), KM_SLEEP);
1024 1113 secp = exi->exi_export.ex_secinfo;
1025 1114
1026 1115 for (i = 0; i < count; i++) {
1027 1116 si = &secp[i].s_secinfo;
1028 1117 resok_val[i].flavor = si->sc_rpcnum;
1029 1118 if (resok_val[i].flavor == RPCSEC_GSS) {
1030 1119 rpcsec_gss_info *info;
1031 1120
1032 1121 info = &resok_val[i].flavor_info;
1033 1122 info->qop = si->sc_qop;
1034 1123 info->service = (rpc_gss_svc_t)si->sc_service;
1035 1124
1036 1125 /* get oid opaque data */
1037 1126 info->oid.sec_oid4_len =
1038 1127 si->sc_gss_mech_type->length;
1039 1128 info->oid.sec_oid4_val = kmem_alloc(
1040 1129 si->sc_gss_mech_type->length, KM_SLEEP);
1041 1130 bcopy(
1042 1131 si->sc_gss_mech_type->elements,
1043 1132 info->oid.sec_oid4_val,
1044 1133 info->oid.sec_oid4_len);
1045 1134 }
1046 1135 }
1047 1136 resp->SECINFO4resok_len = count;
1048 1137 resp->SECINFO4resok_val = resok_val;
1049 1138 } else {
1050 1139 int ret_cnt = 0, k = 0;
1051 1140 int *flavor_list;
1052 1141
1053 1142 count = exi->exi_export.ex_seccnt; /* total sec count */
1054 1143 secp = exi->exi_export.ex_secinfo;
1055 1144
1056 1145 flavor_list = kmem_alloc(count * sizeof (int), KM_SLEEP);
1057 1146 /* find out which flavors to return */
1058 1147 for (i = 0; i < count; i ++) {
1059 1148 int access, flavor, perm;
1060 1149
1061 1150 flavor = secp[i].s_secinfo.sc_nfsnum;
1062 1151 perm = secp[i].s_flags;
1063 1152
1064 1153 access = nfsauth4_secinfo_access(exi, cs->req,
1065 1154 flavor, perm, cs->basecr);
1066 1155
1067 1156 if (! (access & NFSAUTH_DENIED) &&
1068 1157 ! (access & NFSAUTH_WRONGSEC)) {
1069 1158 flavor_list[ret_cnt] = flavor;
1070 1159 ret_cnt++;
1071 1160 }
1072 1161 }
1073 1162
1074 1163 /* Create the returning SECINFO value */
1075 1164 resok_val = kmem_alloc(ret_cnt * sizeof (secinfo4), KM_SLEEP);
1076 1165
1077 1166 for (i = 0; i < count; i++) {
1078 1167 /*
1079 1168 * If the flavor is in the flavor list,
1080 1169 * fill in resok_val.
1081 1170 */
1082 1171 si = &secp[i].s_secinfo;
1083 1172 if (in_flavor_list(si->sc_nfsnum,
1084 1173 flavor_list, ret_cnt)) {
1085 1174 resok_val[k].flavor = si->sc_rpcnum;
1086 1175 if (resok_val[k].flavor == RPCSEC_GSS) {
1087 1176 rpcsec_gss_info *info;
1088 1177
1089 1178 info = &resok_val[k].flavor_info;
1090 1179 info->qop = si->sc_qop;
1091 1180 info->service = (rpc_gss_svc_t)
1092 1181 si->sc_service;
1093 1182
1094 1183 /* get oid opaque data */
1095 1184 info->oid.sec_oid4_len =
1096 1185 si->sc_gss_mech_type->length;
1097 1186 info->oid.sec_oid4_val = kmem_alloc(
1098 1187 si->sc_gss_mech_type->length,
1099 1188 KM_SLEEP);
1100 1189 bcopy(si->sc_gss_mech_type->elements,
1101 1190 info->oid.sec_oid4_val,
1102 1191 info->oid.sec_oid4_len);
1103 1192 }
1104 1193 k++;
1105 1194 }
1106 1195 if (k >= ret_cnt)
1107 1196 break;
1108 1197 }
1109 1198 resp->SECINFO4resok_len = ret_cnt;
1110 1199 resp->SECINFO4resok_val = resok_val;
1111 1200 kmem_free(flavor_list, count * sizeof (int));
1112 1201 }
1113 1202
1114 1203 VN_RELE(vp);
1115 1204 return (NFS4_OK);
1116 1205 }
1117 1206
1118 1207 /*
1119 1208 * SECINFO (Operation 33): Obtain required security information on
1120 1209 * the component name in the format of (security-mechanism-oid, qop, service)
1121 1210 * triplets.
1122 1211 */
1123 1212 /* ARGSUSED */
1124 1213 static void
1125 1214 rfs4_op_secinfo(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
1126 1215 struct compound_state *cs)
1127 1216 {
1128 1217 SECINFO4args *args = &argop->nfs_argop4_u.opsecinfo;
1129 1218 SECINFO4res *resp = &resop->nfs_resop4_u.opsecinfo;
1130 1219 utf8string *utfnm = &args->name;
1131 1220 uint_t len;
1132 1221 char *nm;
1133 1222 struct sockaddr *ca;
1134 1223 char *name = NULL;
1135 1224 nfsstat4 status = NFS4_OK;
1136 1225
1137 1226 DTRACE_NFSV4_2(op__secinfo__start, struct compound_state *, cs,
1138 1227 SECINFO4args *, args);
1139 1228
1140 1229 /*
1141 1230 * Current file handle (cfh) should have been set before getting
1142 1231 * into this function. If not, return error.
1143 1232 */
1144 1233 if (cs->vp == NULL) {
1145 1234 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
1146 1235 goto out;
1147 1236 }
1148 1237
1149 1238 if (cs->vp->v_type != VDIR) {
1150 1239 *cs->statusp = resp->status = NFS4ERR_NOTDIR;
1151 1240 goto out;
1152 1241 }
1153 1242
1154 1243 /*
1155 1244 * Verify the component name. If failed, error out, but
1156 1245 * do not error out if the component name is a "..".
1157 1246 * SECINFO will return its parents secinfo data for SECINFO "..".
1158 1247 */
1159 1248 status = utf8_dir_verify(utfnm);
1160 1249 if (status != NFS4_OK) {
1161 1250 if (utfnm->utf8string_len != 2 ||
1162 1251 utfnm->utf8string_val[0] != '.' ||
1163 1252 utfnm->utf8string_val[1] != '.') {
1164 1253 *cs->statusp = resp->status = status;
1165 1254 goto out;
1166 1255 }
1167 1256 }
1168 1257
1169 1258 nm = utf8_to_str(utfnm, &len, NULL);
1170 1259 if (nm == NULL) {
1171 1260 *cs->statusp = resp->status = NFS4ERR_INVAL;
1172 1261 goto out;
1173 1262 }
1174 1263
1175 1264 if (len > MAXNAMELEN) {
1176 1265 *cs->statusp = resp->status = NFS4ERR_NAMETOOLONG;
1177 1266 kmem_free(nm, len);
1178 1267 goto out;
1179 1268 }
1180 1269
1181 1270 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
1182 1271 name = nfscmd_convname(ca, cs->exi, nm, NFSCMD_CONV_INBOUND,
1183 1272 MAXPATHLEN + 1);
1184 1273
1185 1274 if (name == NULL) {
1186 1275 *cs->statusp = resp->status = NFS4ERR_INVAL;
1187 1276 kmem_free(nm, len);
1188 1277 goto out;
1189 1278 }
1190 1279
1191 1280
1192 1281 *cs->statusp = resp->status = do_rfs4_op_secinfo(cs, name, resp);
1193 1282
1194 1283 if (name != nm)
1195 1284 kmem_free(name, MAXPATHLEN + 1);
1196 1285 kmem_free(nm, len);
1197 1286
1198 1287 out:
1199 1288 DTRACE_NFSV4_2(op__secinfo__done, struct compound_state *, cs,
1200 1289 SECINFO4res *, resp);
1201 1290 }
1202 1291
1203 1292 /*
1204 1293 * Free SECINFO result.
1205 1294 */
1206 1295 /* ARGSUSED */
1207 1296 static void
1208 1297 rfs4_op_secinfo_free(nfs_resop4 *resop)
1209 1298 {
1210 1299 SECINFO4res *resp = &resop->nfs_resop4_u.opsecinfo;
1211 1300 int count, i;
1212 1301 secinfo4 *resok_val;
1213 1302
1214 1303 /* If this is not an Ok result, nothing to free. */
1215 1304 if (resp->status != NFS4_OK) {
1216 1305 return;
1217 1306 }
1218 1307
1219 1308 count = resp->SECINFO4resok_len;
1220 1309 resok_val = resp->SECINFO4resok_val;
1221 1310
1222 1311 for (i = 0; i < count; i++) {
1223 1312 if (resok_val[i].flavor == RPCSEC_GSS) {
1224 1313 rpcsec_gss_info *info;
1225 1314
1226 1315 info = &resok_val[i].flavor_info;
1227 1316 kmem_free(info->oid.sec_oid4_val,
1228 1317 info->oid.sec_oid4_len);
1229 1318 }
1230 1319 }
1231 1320 kmem_free(resok_val, count * sizeof (secinfo4));
1232 1321 resp->SECINFO4resok_len = 0;
1233 1322 resp->SECINFO4resok_val = NULL;
1234 1323 }
1235 1324
1236 1325 /* ARGSUSED */
1237 1326 static void
1238 1327 rfs4_op_access(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
1239 1328 struct compound_state *cs)
1240 1329 {
1241 1330 ACCESS4args *args = &argop->nfs_argop4_u.opaccess;
1242 1331 ACCESS4res *resp = &resop->nfs_resop4_u.opaccess;
1243 1332 int error;
1244 1333 vnode_t *vp;
1245 1334 struct vattr va;
1246 1335 int checkwriteperm;
1247 1336 cred_t *cr = cs->cr;
1248 1337 bslabel_t *clabel, *slabel;
1249 1338 ts_label_t *tslabel;
1250 1339 boolean_t admin_low_client;
1251 1340
1252 1341 DTRACE_NFSV4_2(op__access__start, struct compound_state *, cs,
1253 1342 ACCESS4args *, args);
1254 1343
1255 1344 #if 0 /* XXX allow access even if !cs->access. Eventually only pseudo fs */
1256 1345 if (cs->access == CS_ACCESS_DENIED) {
1257 1346 *cs->statusp = resp->status = NFS4ERR_ACCESS;
1258 1347 goto out;
1259 1348 }
1260 1349 #endif
1261 1350 if (cs->vp == NULL) {
1262 1351 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
1263 1352 goto out;
1264 1353 }
1265 1354
1266 1355 ASSERT(cr != NULL);
1267 1356
1268 1357 vp = cs->vp;
1269 1358
1270 1359 /*
1271 1360 * If the file system is exported read only, it is not appropriate
1272 1361 * to check write permissions for regular files and directories.
1273 1362 * Special files are interpreted by the client, so the underlying
1274 1363 * permissions are sent back to the client for interpretation.
1275 1364 */
1276 1365 if (rdonly4(req, cs) &&
1277 1366 (vp->v_type == VREG || vp->v_type == VDIR))
1278 1367 checkwriteperm = 0;
1279 1368 else
1280 1369 checkwriteperm = 1;
1281 1370
1282 1371 /*
1283 1372 * XXX
1284 1373 * We need the mode so that we can correctly determine access
1285 1374 * permissions relative to a mandatory lock file. Access to
1286 1375 * mandatory lock files is denied on the server, so it might
1287 1376 * as well be reflected to the server during the open.
1288 1377 */
1289 1378 va.va_mask = AT_MODE;
1290 1379 error = VOP_GETATTR(vp, &va, 0, cr, NULL);
1291 1380 if (error) {
1292 1381 *cs->statusp = resp->status = puterrno4(error);
1293 1382 goto out;
1294 1383 }
1295 1384 resp->access = 0;
1296 1385 resp->supported = 0;
1297 1386
1298 1387 if (is_system_labeled()) {
1299 1388 ASSERT(req->rq_label != NULL);
1300 1389 clabel = req->rq_label;
1301 1390 DTRACE_PROBE2(tx__rfs4__log__info__opaccess__clabel, char *,
1302 1391 "got client label from request(1)",
1303 1392 struct svc_req *, req);
1304 1393 if (!blequal(&l_admin_low->tsl_label, clabel)) {
1305 1394 if ((tslabel = nfs_getflabel(vp, cs->exi)) == NULL) {
1306 1395 *cs->statusp = resp->status = puterrno4(EACCES);
1307 1396 goto out;
1308 1397 }
1309 1398 slabel = label2bslabel(tslabel);
1310 1399 DTRACE_PROBE3(tx__rfs4__log__info__opaccess__slabel,
1311 1400 char *, "got server label(1) for vp(2)",
1312 1401 bslabel_t *, slabel, vnode_t *, vp);
1313 1402
1314 1403 admin_low_client = B_FALSE;
1315 1404 } else
1316 1405 admin_low_client = B_TRUE;
1317 1406 }
1318 1407
1319 1408 if (args->access & ACCESS4_READ) {
1320 1409 error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
1321 1410 if (!error && !MANDLOCK(vp, va.va_mode) &&
1322 1411 (!is_system_labeled() || admin_low_client ||
1323 1412 bldominates(clabel, slabel)))
1324 1413 resp->access |= ACCESS4_READ;
1325 1414 resp->supported |= ACCESS4_READ;
1326 1415 }
1327 1416 if ((args->access & ACCESS4_LOOKUP) && vp->v_type == VDIR) {
1328 1417 error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL);
1329 1418 if (!error && (!is_system_labeled() || admin_low_client ||
1330 1419 bldominates(clabel, slabel)))
1331 1420 resp->access |= ACCESS4_LOOKUP;
1332 1421 resp->supported |= ACCESS4_LOOKUP;
1333 1422 }
1334 1423 if (checkwriteperm &&
1335 1424 (args->access & (ACCESS4_MODIFY|ACCESS4_EXTEND))) {
1336 1425 error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL);
1337 1426 if (!error && !MANDLOCK(vp, va.va_mode) &&
1338 1427 (!is_system_labeled() || admin_low_client ||
1339 1428 blequal(clabel, slabel)))
1340 1429 resp->access |=
1341 1430 (args->access & (ACCESS4_MODIFY | ACCESS4_EXTEND));
1342 1431 resp->supported |=
1343 1432 resp->access & (ACCESS4_MODIFY | ACCESS4_EXTEND);
1344 1433 }
1345 1434
1346 1435 if (checkwriteperm &&
1347 1436 (args->access & ACCESS4_DELETE) && vp->v_type == VDIR) {
1348 1437 error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL);
1349 1438 if (!error && (!is_system_labeled() || admin_low_client ||
1350 1439 blequal(clabel, slabel)))
1351 1440 resp->access |= ACCESS4_DELETE;
1352 1441 resp->supported |= ACCESS4_DELETE;
1353 1442 }
1354 1443 if (args->access & ACCESS4_EXECUTE && vp->v_type != VDIR) {
1355 1444 error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL);
1356 1445 if (!error && !MANDLOCK(vp, va.va_mode) &&
1357 1446 (!is_system_labeled() || admin_low_client ||
1358 1447 bldominates(clabel, slabel)))
1359 1448 resp->access |= ACCESS4_EXECUTE;
1360 1449 resp->supported |= ACCESS4_EXECUTE;
1361 1450 }
1362 1451
1363 1452 if (is_system_labeled() && !admin_low_client)
1364 1453 label_rele(tslabel);
1365 1454
1366 1455 *cs->statusp = resp->status = NFS4_OK;
1367 1456 out:
1368 1457 DTRACE_NFSV4_2(op__access__done, struct compound_state *, cs,
1369 1458 ACCESS4res *, resp);
1370 1459 }
1371 1460
1372 1461 /* ARGSUSED */
|
↓ open down ↓ |
342 lines elided |
↑ open up ↑ |
1373 1462 static void
1374 1463 rfs4_op_commit(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
1375 1464 struct compound_state *cs)
1376 1465 {
1377 1466 COMMIT4args *args = &argop->nfs_argop4_u.opcommit;
1378 1467 COMMIT4res *resp = &resop->nfs_resop4_u.opcommit;
1379 1468 int error;
1380 1469 vnode_t *vp = cs->vp;
1381 1470 cred_t *cr = cs->cr;
1382 1471 vattr_t va;
1472 + nfs4_srv_t *nsrv4;
1383 1473
1384 1474 DTRACE_NFSV4_2(op__commit__start, struct compound_state *, cs,
1385 1475 COMMIT4args *, args);
1386 1476
1387 1477 if (vp == NULL) {
1388 1478 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
1389 1479 goto out;
1390 1480 }
1391 1481 if (cs->access == CS_ACCESS_DENIED) {
1392 1482 *cs->statusp = resp->status = NFS4ERR_ACCESS;
1393 1483 goto out;
1394 1484 }
1395 1485
1396 1486 if (args->offset + args->count < args->offset) {
1397 1487 *cs->statusp = resp->status = NFS4ERR_INVAL;
1398 1488 goto out;
1399 1489 }
1400 1490
1401 1491 va.va_mask = AT_UID;
1402 1492 error = VOP_GETATTR(vp, &va, 0, cr, NULL);
1403 1493
1404 1494 /*
1405 1495 * If we can't get the attributes, then we can't do the
1406 1496 * right access checking. So, we'll fail the request.
1407 1497 */
1408 1498 if (error) {
1409 1499 *cs->statusp = resp->status = puterrno4(error);
1410 1500 goto out;
1411 1501 }
1412 1502 if (rdonly4(req, cs)) {
1413 1503 *cs->statusp = resp->status = NFS4ERR_ROFS;
1414 1504 goto out;
1415 1505 }
1416 1506
1417 1507 if (vp->v_type != VREG) {
1418 1508 if (vp->v_type == VDIR)
1419 1509 resp->status = NFS4ERR_ISDIR;
1420 1510 else
1421 1511 resp->status = NFS4ERR_INVAL;
1422 1512 *cs->statusp = resp->status;
1423 1513 goto out;
1424 1514 }
1425 1515
1426 1516 if (crgetuid(cr) != va.va_uid &&
1427 1517 (error = VOP_ACCESS(vp, VWRITE, 0, cs->cr, NULL))) {
1428 1518 *cs->statusp = resp->status = puterrno4(error);
|
↓ open down ↓ |
36 lines elided |
↑ open up ↑ |
1429 1519 goto out;
1430 1520 }
1431 1521
1432 1522 error = VOP_FSYNC(vp, FSYNC, cr, NULL);
1433 1523
1434 1524 if (error) {
1435 1525 *cs->statusp = resp->status = puterrno4(error);
1436 1526 goto out;
1437 1527 }
1438 1528
1529 + nsrv4 = zone_getspecific(rfs4_zone_key, curzone);
1439 1530 *cs->statusp = resp->status = NFS4_OK;
1440 - resp->writeverf = Write4verf;
1531 + resp->writeverf = nsrv4->write4verf;
1441 1532 out:
1442 1533 DTRACE_NFSV4_2(op__commit__done, struct compound_state *, cs,
1443 1534 COMMIT4res *, resp);
1444 1535 }
1445 1536
1446 1537 /*
1447 1538 * rfs4_op_mknod is called from rfs4_op_create after all initial verification
1448 1539 * was completed. It does the nfsv4 create for special files.
1449 1540 */
1450 1541 /* ARGSUSED */
1451 1542 static vnode_t *
1452 1543 do_rfs4_op_mknod(CREATE4args *args, CREATE4res *resp, struct svc_req *req,
1453 1544 struct compound_state *cs, vattr_t *vap, char *nm)
1454 1545 {
1455 1546 int error;
1456 1547 cred_t *cr = cs->cr;
1457 1548 vnode_t *dvp = cs->vp;
1458 1549 vnode_t *vp = NULL;
1459 1550 int mode;
1460 1551 enum vcexcl excl;
1461 1552
1462 1553 switch (args->type) {
1463 1554 case NF4CHR:
1464 1555 case NF4BLK:
1465 1556 if (secpolicy_sys_devices(cr) != 0) {
1466 1557 *cs->statusp = resp->status = NFS4ERR_PERM;
1467 1558 return (NULL);
1468 1559 }
1469 1560 if (args->type == NF4CHR)
1470 1561 vap->va_type = VCHR;
1471 1562 else
1472 1563 vap->va_type = VBLK;
1473 1564 vap->va_rdev = makedevice(args->ftype4_u.devdata.specdata1,
1474 1565 args->ftype4_u.devdata.specdata2);
1475 1566 vap->va_mask |= AT_RDEV;
1476 1567 break;
1477 1568 case NF4SOCK:
1478 1569 vap->va_type = VSOCK;
1479 1570 break;
1480 1571 case NF4FIFO:
1481 1572 vap->va_type = VFIFO;
1482 1573 break;
1483 1574 default:
1484 1575 *cs->statusp = resp->status = NFS4ERR_BADTYPE;
1485 1576 return (NULL);
1486 1577 }
1487 1578
1488 1579 /*
1489 1580 * Must specify the mode.
1490 1581 */
1491 1582 if (!(vap->va_mask & AT_MODE)) {
1492 1583 *cs->statusp = resp->status = NFS4ERR_INVAL;
1493 1584 return (NULL);
1494 1585 }
1495 1586
1496 1587 excl = EXCL;
1497 1588
1498 1589 mode = 0;
1499 1590
1500 1591 error = VOP_CREATE(dvp, nm, vap, excl, mode, &vp, cr, 0, NULL, NULL);
1501 1592 if (error) {
1502 1593 *cs->statusp = resp->status = puterrno4(error);
1503 1594 return (NULL);
1504 1595 }
1505 1596 return (vp);
1506 1597 }
1507 1598
1508 1599 /*
1509 1600 * nfsv4 create is used to create non-regular files. For regular files,
1510 1601 * use nfsv4 open.
1511 1602 */
1512 1603 /* ARGSUSED */
1513 1604 static void
1514 1605 rfs4_op_create(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
1515 1606 struct compound_state *cs)
1516 1607 {
1517 1608 CREATE4args *args = &argop->nfs_argop4_u.opcreate;
1518 1609 CREATE4res *resp = &resop->nfs_resop4_u.opcreate;
1519 1610 int error;
1520 1611 struct vattr bva, iva, iva2, ava, *vap;
1521 1612 cred_t *cr = cs->cr;
1522 1613 vnode_t *dvp = cs->vp;
1523 1614 vnode_t *vp = NULL;
1524 1615 vnode_t *realvp;
1525 1616 char *nm, *lnm;
1526 1617 uint_t len, llen;
1527 1618 int syncval = 0;
1528 1619 struct nfs4_svgetit_arg sarg;
1529 1620 struct nfs4_ntov_table ntov;
1530 1621 struct statvfs64 sb;
1531 1622 nfsstat4 status;
1532 1623 struct sockaddr *ca;
1533 1624 char *name = NULL;
1534 1625 char *lname = NULL;
1535 1626
1536 1627 DTRACE_NFSV4_2(op__create__start, struct compound_state *, cs,
1537 1628 CREATE4args *, args);
1538 1629
1539 1630 resp->attrset = 0;
1540 1631
1541 1632 if (dvp == NULL) {
1542 1633 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
1543 1634 goto out;
1544 1635 }
1545 1636
1546 1637 /*
1547 1638 * If there is an unshared filesystem mounted on this vnode,
1548 1639 * do not allow to create an object in this directory.
1549 1640 */
1550 1641 if (vn_ismntpt(dvp)) {
1551 1642 *cs->statusp = resp->status = NFS4ERR_ACCESS;
1552 1643 goto out;
1553 1644 }
1554 1645
1555 1646 /* Verify that type is correct */
1556 1647 switch (args->type) {
1557 1648 case NF4LNK:
1558 1649 case NF4BLK:
1559 1650 case NF4CHR:
1560 1651 case NF4SOCK:
1561 1652 case NF4FIFO:
1562 1653 case NF4DIR:
1563 1654 break;
1564 1655 default:
1565 1656 *cs->statusp = resp->status = NFS4ERR_BADTYPE;
1566 1657 goto out;
1567 1658 };
1568 1659
1569 1660 if (cs->access == CS_ACCESS_DENIED) {
1570 1661 *cs->statusp = resp->status = NFS4ERR_ACCESS;
1571 1662 goto out;
1572 1663 }
1573 1664 if (dvp->v_type != VDIR) {
1574 1665 *cs->statusp = resp->status = NFS4ERR_NOTDIR;
1575 1666 goto out;
1576 1667 }
1577 1668 status = utf8_dir_verify(&args->objname);
1578 1669 if (status != NFS4_OK) {
1579 1670 *cs->statusp = resp->status = status;
1580 1671 goto out;
1581 1672 }
1582 1673
1583 1674 if (rdonly4(req, cs)) {
1584 1675 *cs->statusp = resp->status = NFS4ERR_ROFS;
1585 1676 goto out;
1586 1677 }
1587 1678
1588 1679 /*
1589 1680 * Name of newly created object
1590 1681 */
1591 1682 nm = utf8_to_fn(&args->objname, &len, NULL);
1592 1683 if (nm == NULL) {
1593 1684 *cs->statusp = resp->status = NFS4ERR_INVAL;
1594 1685 goto out;
1595 1686 }
1596 1687
1597 1688 if (len > MAXNAMELEN) {
1598 1689 *cs->statusp = resp->status = NFS4ERR_NAMETOOLONG;
1599 1690 kmem_free(nm, len);
1600 1691 goto out;
1601 1692 }
1602 1693
1603 1694 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
1604 1695 name = nfscmd_convname(ca, cs->exi, nm, NFSCMD_CONV_INBOUND,
1605 1696 MAXPATHLEN + 1);
1606 1697
1607 1698 if (name == NULL) {
1608 1699 *cs->statusp = resp->status = NFS4ERR_INVAL;
1609 1700 kmem_free(nm, len);
1610 1701 goto out;
1611 1702 }
1612 1703
1613 1704 resp->attrset = 0;
1614 1705
1615 1706 sarg.sbp = &sb;
1616 1707 sarg.is_referral = B_FALSE;
1617 1708 nfs4_ntov_table_init(&ntov);
1618 1709
1619 1710 status = do_rfs4_set_attrs(&resp->attrset,
1620 1711 &args->createattrs, cs, &sarg, &ntov, NFS4ATTR_SETIT);
1621 1712
1622 1713 if (sarg.vap->va_mask == 0 && status == NFS4_OK)
1623 1714 status = NFS4ERR_INVAL;
1624 1715
1625 1716 if (status != NFS4_OK) {
1626 1717 *cs->statusp = resp->status = status;
1627 1718 if (name != nm)
1628 1719 kmem_free(name, MAXPATHLEN + 1);
1629 1720 kmem_free(nm, len);
1630 1721 nfs4_ntov_table_free(&ntov, &sarg);
1631 1722 resp->attrset = 0;
1632 1723 goto out;
1633 1724 }
1634 1725
1635 1726 /* Get "before" change value */
1636 1727 bva.va_mask = AT_CTIME|AT_SEQ|AT_MODE;
1637 1728 error = VOP_GETATTR(dvp, &bva, 0, cr, NULL);
1638 1729 if (error) {
1639 1730 *cs->statusp = resp->status = puterrno4(error);
1640 1731 if (name != nm)
1641 1732 kmem_free(name, MAXPATHLEN + 1);
1642 1733 kmem_free(nm, len);
1643 1734 nfs4_ntov_table_free(&ntov, &sarg);
1644 1735 resp->attrset = 0;
1645 1736 goto out;
1646 1737 }
1647 1738 NFS4_SET_FATTR4_CHANGE(resp->cinfo.before, bva.va_ctime)
1648 1739
1649 1740 vap = sarg.vap;
1650 1741
1651 1742 /*
1652 1743 * Set the default initial values for attributes when the parent
1653 1744 * directory does not have the VSUID/VSGID bit set and they have
1654 1745 * not been specified in createattrs.
1655 1746 */
1656 1747 if (!(bva.va_mode & VSUID) && (vap->va_mask & AT_UID) == 0) {
1657 1748 vap->va_uid = crgetuid(cr);
1658 1749 vap->va_mask |= AT_UID;
1659 1750 }
1660 1751 if (!(bva.va_mode & VSGID) && (vap->va_mask & AT_GID) == 0) {
1661 1752 vap->va_gid = crgetgid(cr);
1662 1753 vap->va_mask |= AT_GID;
1663 1754 }
1664 1755
1665 1756 vap->va_mask |= AT_TYPE;
1666 1757 switch (args->type) {
1667 1758 case NF4DIR:
1668 1759 vap->va_type = VDIR;
1669 1760 if ((vap->va_mask & AT_MODE) == 0) {
1670 1761 vap->va_mode = 0700; /* default: owner rwx only */
1671 1762 vap->va_mask |= AT_MODE;
1672 1763 }
1673 1764 error = VOP_MKDIR(dvp, name, vap, &vp, cr, NULL, 0, NULL);
1674 1765 if (error)
1675 1766 break;
1676 1767
1677 1768 /*
1678 1769 * Get the initial "after" sequence number, if it fails,
1679 1770 * set to zero
1680 1771 */
1681 1772 iva.va_mask = AT_SEQ;
1682 1773 if (VOP_GETATTR(dvp, &iva, 0, cs->cr, NULL))
1683 1774 iva.va_seq = 0;
1684 1775 break;
1685 1776 case NF4LNK:
1686 1777 vap->va_type = VLNK;
1687 1778 if ((vap->va_mask & AT_MODE) == 0) {
1688 1779 vap->va_mode = 0700; /* default: owner rwx only */
1689 1780 vap->va_mask |= AT_MODE;
1690 1781 }
1691 1782
1692 1783 /*
1693 1784 * symlink names must be treated as data
1694 1785 */
1695 1786 lnm = utf8_to_str((utf8string *)&args->ftype4_u.linkdata,
1696 1787 &llen, NULL);
1697 1788
1698 1789 if (lnm == NULL) {
1699 1790 *cs->statusp = resp->status = NFS4ERR_INVAL;
1700 1791 if (name != nm)
1701 1792 kmem_free(name, MAXPATHLEN + 1);
1702 1793 kmem_free(nm, len);
1703 1794 nfs4_ntov_table_free(&ntov, &sarg);
1704 1795 resp->attrset = 0;
1705 1796 goto out;
1706 1797 }
1707 1798
1708 1799 if (llen > MAXPATHLEN) {
1709 1800 *cs->statusp = resp->status = NFS4ERR_NAMETOOLONG;
1710 1801 if (name != nm)
1711 1802 kmem_free(name, MAXPATHLEN + 1);
1712 1803 kmem_free(nm, len);
1713 1804 kmem_free(lnm, llen);
1714 1805 nfs4_ntov_table_free(&ntov, &sarg);
1715 1806 resp->attrset = 0;
1716 1807 goto out;
1717 1808 }
1718 1809
1719 1810 lname = nfscmd_convname(ca, cs->exi, lnm,
1720 1811 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
1721 1812
1722 1813 if (lname == NULL) {
1723 1814 *cs->statusp = resp->status = NFS4ERR_SERVERFAULT;
1724 1815 if (name != nm)
1725 1816 kmem_free(name, MAXPATHLEN + 1);
1726 1817 kmem_free(nm, len);
1727 1818 kmem_free(lnm, llen);
1728 1819 nfs4_ntov_table_free(&ntov, &sarg);
1729 1820 resp->attrset = 0;
1730 1821 goto out;
1731 1822 }
1732 1823
1733 1824 error = VOP_SYMLINK(dvp, name, vap, lname, cr, NULL, 0);
1734 1825 if (lname != lnm)
1735 1826 kmem_free(lname, MAXPATHLEN + 1);
1736 1827 kmem_free(lnm, llen);
1737 1828 if (error)
1738 1829 break;
1739 1830
1740 1831 /*
1741 1832 * Get the initial "after" sequence number, if it fails,
1742 1833 * set to zero
1743 1834 */
1744 1835 iva.va_mask = AT_SEQ;
1745 1836 if (VOP_GETATTR(dvp, &iva, 0, cs->cr, NULL))
1746 1837 iva.va_seq = 0;
1747 1838
1748 1839 error = VOP_LOOKUP(dvp, name, &vp, NULL, 0, NULL, cr,
1749 1840 NULL, NULL, NULL);
1750 1841 if (error)
1751 1842 break;
1752 1843
1753 1844 /*
1754 1845 * va_seq is not safe over VOP calls, check it again
1755 1846 * if it has changed zero out iva to force atomic = FALSE.
1756 1847 */
1757 1848 iva2.va_mask = AT_SEQ;
1758 1849 if (VOP_GETATTR(dvp, &iva2, 0, cs->cr, NULL) ||
1759 1850 iva2.va_seq != iva.va_seq)
1760 1851 iva.va_seq = 0;
1761 1852 break;
1762 1853 default:
1763 1854 /*
1764 1855 * probably a special file.
1765 1856 */
1766 1857 if ((vap->va_mask & AT_MODE) == 0) {
1767 1858 vap->va_mode = 0600; /* default: owner rw only */
1768 1859 vap->va_mask |= AT_MODE;
1769 1860 }
1770 1861 syncval = FNODSYNC;
1771 1862 /*
1772 1863 * We know this will only generate one VOP call
1773 1864 */
1774 1865 vp = do_rfs4_op_mknod(args, resp, req, cs, vap, name);
1775 1866
1776 1867 if (vp == NULL) {
1777 1868 if (name != nm)
1778 1869 kmem_free(name, MAXPATHLEN + 1);
1779 1870 kmem_free(nm, len);
1780 1871 nfs4_ntov_table_free(&ntov, &sarg);
1781 1872 resp->attrset = 0;
1782 1873 goto out;
1783 1874 }
1784 1875
1785 1876 /*
1786 1877 * Get the initial "after" sequence number, if it fails,
1787 1878 * set to zero
1788 1879 */
1789 1880 iva.va_mask = AT_SEQ;
1790 1881 if (VOP_GETATTR(dvp, &iva, 0, cs->cr, NULL))
1791 1882 iva.va_seq = 0;
1792 1883
1793 1884 break;
1794 1885 }
1795 1886 if (name != nm)
1796 1887 kmem_free(name, MAXPATHLEN + 1);
1797 1888 kmem_free(nm, len);
1798 1889
1799 1890 if (error) {
1800 1891 *cs->statusp = resp->status = puterrno4(error);
1801 1892 }
1802 1893
1803 1894 /*
1804 1895 * Force modified data and metadata out to stable storage.
1805 1896 */
1806 1897 (void) VOP_FSYNC(dvp, 0, cr, NULL);
1807 1898
1808 1899 if (resp->status != NFS4_OK) {
1809 1900 if (vp != NULL)
1810 1901 VN_RELE(vp);
1811 1902 nfs4_ntov_table_free(&ntov, &sarg);
1812 1903 resp->attrset = 0;
1813 1904 goto out;
1814 1905 }
1815 1906
1816 1907 /*
1817 1908 * Finish setup of cinfo response, "before" value already set.
1818 1909 * Get "after" change value, if it fails, simply return the
1819 1910 * before value.
1820 1911 */
1821 1912 ava.va_mask = AT_CTIME|AT_SEQ;
1822 1913 if (VOP_GETATTR(dvp, &ava, 0, cr, NULL)) {
1823 1914 ava.va_ctime = bva.va_ctime;
1824 1915 ava.va_seq = 0;
1825 1916 }
1826 1917 NFS4_SET_FATTR4_CHANGE(resp->cinfo.after, ava.va_ctime);
1827 1918
1828 1919 /*
1829 1920 * True verification that object was created with correct
1830 1921 * attrs is impossible. The attrs could have been changed
1831 1922 * immediately after object creation. If attributes did
1832 1923 * not verify, the only recourse for the server is to
1833 1924 * destroy the object. Maybe if some attrs (like gid)
1834 1925 * are set incorrectly, the object should be destroyed;
1835 1926 * however, seems bad as a default policy. Do we really
1836 1927 * want to destroy an object over one of the times not
1837 1928 * verifying correctly? For these reasons, the server
1838 1929 * currently sets bits in attrset for createattrs
1839 1930 * that were set; however, no verification is done.
1840 1931 *
1841 1932 * vmask_to_nmask accounts for vattr bits set on create
1842 1933 * [do_rfs4_set_attrs() only sets resp bits for
1843 1934 * non-vattr/vfs bits.]
1844 1935 * Mask off any bits set by default so as not to return
1845 1936 * more attrset bits than were requested in createattrs
1846 1937 */
1847 1938 nfs4_vmask_to_nmask(sarg.vap->va_mask, &resp->attrset);
1848 1939 resp->attrset &= args->createattrs.attrmask;
1849 1940 nfs4_ntov_table_free(&ntov, &sarg);
1850 1941
1851 1942 error = makefh4(&cs->fh, vp, cs->exi);
1852 1943 if (error) {
1853 1944 *cs->statusp = resp->status = puterrno4(error);
1854 1945 }
1855 1946
1856 1947 /*
1857 1948 * The cinfo.atomic = TRUE only if we got no errors, we have
1858 1949 * non-zero va_seq's, and it has incremented by exactly one
1859 1950 * during the creation and it didn't change during the VOP_LOOKUP
1860 1951 * or VOP_FSYNC.
1861 1952 */
1862 1953 if (!error && bva.va_seq && iva.va_seq && ava.va_seq &&
1863 1954 iva.va_seq == (bva.va_seq + 1) && iva.va_seq == ava.va_seq)
1864 1955 resp->cinfo.atomic = TRUE;
1865 1956 else
1866 1957 resp->cinfo.atomic = FALSE;
1867 1958
1868 1959 /*
1869 1960 * Force modified metadata out to stable storage.
1870 1961 *
1871 1962 * if a underlying vp exists, pass it to VOP_FSYNC
1872 1963 */
1873 1964 if (VOP_REALVP(vp, &realvp, NULL) == 0)
1874 1965 (void) VOP_FSYNC(realvp, syncval, cr, NULL);
1875 1966 else
1876 1967 (void) VOP_FSYNC(vp, syncval, cr, NULL);
1877 1968
1878 1969 if (resp->status != NFS4_OK) {
1879 1970 VN_RELE(vp);
1880 1971 goto out;
1881 1972 }
1882 1973 if (cs->vp)
1883 1974 VN_RELE(cs->vp);
1884 1975
1885 1976 cs->vp = vp;
1886 1977 *cs->statusp = resp->status = NFS4_OK;
1887 1978 out:
1888 1979 DTRACE_NFSV4_2(op__create__done, struct compound_state *, cs,
1889 1980 CREATE4res *, resp);
1890 1981 }
1891 1982
1892 1983 /*ARGSUSED*/
1893 1984 static void
1894 1985 rfs4_op_delegpurge(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
1895 1986 struct compound_state *cs)
1896 1987 {
1897 1988 DTRACE_NFSV4_2(op__delegpurge__start, struct compound_state *, cs,
1898 1989 DELEGPURGE4args *, &argop->nfs_argop4_u.opdelegpurge);
1899 1990
1900 1991 rfs4_op_inval(argop, resop, req, cs);
1901 1992
1902 1993 DTRACE_NFSV4_2(op__delegpurge__done, struct compound_state *, cs,
1903 1994 DELEGPURGE4res *, &resop->nfs_resop4_u.opdelegpurge);
1904 1995 }
1905 1996
1906 1997 /*ARGSUSED*/
1907 1998 static void
1908 1999 rfs4_op_delegreturn(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
1909 2000 struct compound_state *cs)
1910 2001 {
1911 2002 DELEGRETURN4args *args = &argop->nfs_argop4_u.opdelegreturn;
1912 2003 DELEGRETURN4res *resp = &resop->nfs_resop4_u.opdelegreturn;
1913 2004 rfs4_deleg_state_t *dsp;
1914 2005 nfsstat4 status;
1915 2006
1916 2007 DTRACE_NFSV4_2(op__delegreturn__start, struct compound_state *, cs,
1917 2008 DELEGRETURN4args *, args);
1918 2009
1919 2010 status = rfs4_get_deleg_state(&args->deleg_stateid, &dsp);
1920 2011 resp->status = *cs->statusp = status;
1921 2012 if (status != NFS4_OK)
1922 2013 goto out;
1923 2014
1924 2015 /* Ensure specified filehandle matches */
1925 2016 if (cs->vp != dsp->rds_finfo->rf_vp) {
1926 2017 resp->status = *cs->statusp = NFS4ERR_BAD_STATEID;
1927 2018 } else
1928 2019 rfs4_return_deleg(dsp, FALSE);
1929 2020
1930 2021 rfs4_update_lease(dsp->rds_client);
1931 2022
1932 2023 rfs4_deleg_state_rele(dsp);
1933 2024 out:
1934 2025 DTRACE_NFSV4_2(op__delegreturn__done, struct compound_state *, cs,
1935 2026 DELEGRETURN4res *, resp);
1936 2027 }
1937 2028
1938 2029 /*
1939 2030 * Check to see if a given "flavor" is an explicitly shared flavor.
1940 2031 * The assumption of this routine is the "flavor" is already a valid
1941 2032 * flavor in the secinfo list of "exi".
1942 2033 *
1943 2034 * e.g.
1944 2035 * # share -o sec=flavor1 /export
1945 2036 * # share -o sec=flavor2 /export/home
1946 2037 *
1947 2038 * flavor2 is not an explicitly shared flavor for /export,
1948 2039 * however it is in the secinfo list for /export thru the
1949 2040 * server namespace setup.
1950 2041 */
1951 2042 int
1952 2043 is_exported_sec(int flavor, struct exportinfo *exi)
1953 2044 {
1954 2045 int i;
1955 2046 struct secinfo *sp;
1956 2047
1957 2048 sp = exi->exi_export.ex_secinfo;
1958 2049 for (i = 0; i < exi->exi_export.ex_seccnt; i++) {
1959 2050 if (flavor == sp[i].s_secinfo.sc_nfsnum ||
1960 2051 sp[i].s_secinfo.sc_nfsnum == AUTH_NONE) {
1961 2052 return (SEC_REF_EXPORTED(&sp[i]));
1962 2053 }
1963 2054 }
1964 2055
1965 2056 /* Should not reach this point based on the assumption */
1966 2057 return (0);
1967 2058 }
1968 2059
1969 2060 /*
1970 2061 * Check if the security flavor used in the request matches what is
1971 2062 * required at the export point or at the root pseudo node (exi_root).
1972 2063 *
1973 2064 * returns 1 if there's a match or if exported with AUTH_NONE; 0 otherwise.
1974 2065 *
1975 2066 */
1976 2067 static int
1977 2068 secinfo_match_or_authnone(struct compound_state *cs)
1978 2069 {
1979 2070 int i;
1980 2071 struct secinfo *sp;
1981 2072
1982 2073 /*
1983 2074 * Check cs->nfsflavor (from the request) against
1984 2075 * the current export data in cs->exi.
1985 2076 */
1986 2077 sp = cs->exi->exi_export.ex_secinfo;
1987 2078 for (i = 0; i < cs->exi->exi_export.ex_seccnt; i++) {
1988 2079 if (cs->nfsflavor == sp[i].s_secinfo.sc_nfsnum ||
1989 2080 sp[i].s_secinfo.sc_nfsnum == AUTH_NONE)
1990 2081 return (1);
1991 2082 }
1992 2083
1993 2084 return (0);
1994 2085 }
1995 2086
1996 2087 /*
1997 2088 * Check the access authority for the client and return the correct error.
1998 2089 */
1999 2090 nfsstat4
2000 2091 call_checkauth4(struct compound_state *cs, struct svc_req *req)
2001 2092 {
2002 2093 int authres;
2003 2094
2004 2095 /*
2005 2096 * First, check if the security flavor used in the request
2006 2097 * are among the flavors set in the server namespace.
2007 2098 */
2008 2099 if (!secinfo_match_or_authnone(cs)) {
2009 2100 *cs->statusp = NFS4ERR_WRONGSEC;
2010 2101 return (*cs->statusp);
2011 2102 }
2012 2103
2013 2104 authres = checkauth4(cs, req);
2014 2105
2015 2106 if (authres > 0) {
2016 2107 *cs->statusp = NFS4_OK;
2017 2108 if (! (cs->access & CS_ACCESS_LIMITED))
2018 2109 cs->access = CS_ACCESS_OK;
2019 2110 } else if (authres == 0) {
2020 2111 *cs->statusp = NFS4ERR_ACCESS;
2021 2112 } else if (authres == -2) {
2022 2113 *cs->statusp = NFS4ERR_WRONGSEC;
2023 2114 } else {
2024 2115 *cs->statusp = NFS4ERR_DELAY;
2025 2116 }
2026 2117 return (*cs->statusp);
2027 2118 }
2028 2119
2029 2120 /*
2030 2121 * bitmap4_to_attrmask is called by getattr and readdir.
2031 2122 * It sets up the vattr mask and determines whether vfsstat call is needed
2032 2123 * based on the input bitmap.
2033 2124 * Returns nfsv4 status.
2034 2125 */
2035 2126 static nfsstat4
2036 2127 bitmap4_to_attrmask(bitmap4 breq, struct nfs4_svgetit_arg *sargp)
2037 2128 {
2038 2129 int i;
2039 2130 uint_t va_mask;
2040 2131 struct statvfs64 *sbp = sargp->sbp;
2041 2132
2042 2133 sargp->sbp = NULL;
2043 2134 sargp->flag = 0;
2044 2135 sargp->rdattr_error = NFS4_OK;
2045 2136 sargp->mntdfid_set = FALSE;
2046 2137 if (sargp->cs->vp)
2047 2138 sargp->xattr = get_fh4_flag(&sargp->cs->fh,
2048 2139 FH4_ATTRDIR | FH4_NAMEDATTR);
2049 2140 else
2050 2141 sargp->xattr = 0;
2051 2142
2052 2143 /*
2053 2144 * Set rdattr_error_req to true if return error per
2054 2145 * failed entry rather than fail the readdir.
2055 2146 */
2056 2147 if (breq & FATTR4_RDATTR_ERROR_MASK)
2057 2148 sargp->rdattr_error_req = 1;
2058 2149 else
2059 2150 sargp->rdattr_error_req = 0;
2060 2151
2061 2152 /*
2062 2153 * generate the va_mask
2063 2154 * Handle the easy cases first
2064 2155 */
2065 2156 switch (breq) {
2066 2157 case NFS4_NTOV_ATTR_MASK:
2067 2158 sargp->vap->va_mask = NFS4_NTOV_ATTR_AT_MASK;
2068 2159 return (NFS4_OK);
2069 2160
2070 2161 case NFS4_FS_ATTR_MASK:
2071 2162 sargp->vap->va_mask = NFS4_FS_ATTR_AT_MASK;
2072 2163 sargp->sbp = sbp;
2073 2164 return (NFS4_OK);
2074 2165
2075 2166 case NFS4_NTOV_ATTR_CACHE_MASK:
2076 2167 sargp->vap->va_mask = NFS4_NTOV_ATTR_CACHE_AT_MASK;
2077 2168 return (NFS4_OK);
2078 2169
2079 2170 case FATTR4_LEASE_TIME_MASK:
2080 2171 sargp->vap->va_mask = 0;
2081 2172 return (NFS4_OK);
2082 2173
2083 2174 default:
2084 2175 va_mask = 0;
2085 2176 for (i = 0; i < nfs4_ntov_map_size; i++) {
2086 2177 if ((breq & nfs4_ntov_map[i].fbit) &&
2087 2178 nfs4_ntov_map[i].vbit)
2088 2179 va_mask |= nfs4_ntov_map[i].vbit;
2089 2180 }
2090 2181
2091 2182 /*
2092 2183 * Check is vfsstat is needed
2093 2184 */
2094 2185 if (breq & NFS4_FS_ATTR_MASK)
2095 2186 sargp->sbp = sbp;
2096 2187
2097 2188 sargp->vap->va_mask = va_mask;
2098 2189 return (NFS4_OK);
2099 2190 }
2100 2191 /* NOTREACHED */
2101 2192 }
2102 2193
2103 2194 /*
2104 2195 * bitmap4_get_sysattrs is called by getattr and readdir.
2105 2196 * It calls both VOP_GETATTR and VFS_STATVFS calls to get the attrs.
2106 2197 * Returns nfsv4 status.
2107 2198 */
2108 2199 static nfsstat4
2109 2200 bitmap4_get_sysattrs(struct nfs4_svgetit_arg *sargp)
2110 2201 {
2111 2202 int error;
2112 2203 struct compound_state *cs = sargp->cs;
2113 2204 vnode_t *vp = cs->vp;
2114 2205
2115 2206 if (sargp->sbp != NULL) {
2116 2207 if (error = VFS_STATVFS(vp->v_vfsp, sargp->sbp)) {
2117 2208 sargp->sbp = NULL; /* to identify error */
2118 2209 return (puterrno4(error));
2119 2210 }
2120 2211 }
2121 2212
2122 2213 return (rfs4_vop_getattr(vp, sargp->vap, 0, cs->cr));
2123 2214 }
2124 2215
2125 2216 static void
2126 2217 nfs4_ntov_table_init(struct nfs4_ntov_table *ntovp)
2127 2218 {
2128 2219 ntovp->na = kmem_zalloc(sizeof (union nfs4_attr_u) * nfs4_ntov_map_size,
2129 2220 KM_SLEEP);
2130 2221 ntovp->attrcnt = 0;
2131 2222 ntovp->vfsstat = FALSE;
2132 2223 }
2133 2224
2134 2225 static void
2135 2226 nfs4_ntov_table_free(struct nfs4_ntov_table *ntovp,
2136 2227 struct nfs4_svgetit_arg *sargp)
2137 2228 {
2138 2229 int i;
2139 2230 union nfs4_attr_u *na;
2140 2231 uint8_t *amap;
2141 2232
2142 2233 /*
2143 2234 * XXX Should do the same checks for whether the bit is set
2144 2235 */
2145 2236 for (i = 0, na = ntovp->na, amap = ntovp->amap;
2146 2237 i < ntovp->attrcnt; i++, na++, amap++) {
2147 2238 (void) (*nfs4_ntov_map[*amap].sv_getit)(
2148 2239 NFS4ATTR_FREEIT, sargp, na);
2149 2240 }
2150 2241 if ((sargp->op == NFS4ATTR_SETIT) || (sargp->op == NFS4ATTR_VERIT)) {
2151 2242 /*
2152 2243 * xdr_free for getattr will be done later
2153 2244 */
2154 2245 for (i = 0, na = ntovp->na, amap = ntovp->amap;
2155 2246 i < ntovp->attrcnt; i++, na++, amap++) {
2156 2247 xdr_free(nfs4_ntov_map[*amap].xfunc, (caddr_t)na);
2157 2248 }
2158 2249 }
2159 2250 kmem_free(ntovp->na, sizeof (union nfs4_attr_u) * nfs4_ntov_map_size);
2160 2251 }
2161 2252
2162 2253 /*
2163 2254 * do_rfs4_op_getattr gets the system attrs and converts into fattr4.
2164 2255 */
2165 2256 static nfsstat4
2166 2257 do_rfs4_op_getattr(bitmap4 breq, fattr4 *fattrp,
2167 2258 struct nfs4_svgetit_arg *sargp)
2168 2259 {
2169 2260 int error = 0;
2170 2261 int i, k;
2171 2262 struct nfs4_ntov_table ntov;
2172 2263 XDR xdr;
2173 2264 ulong_t xdr_size;
2174 2265 char *xdr_attrs;
2175 2266 nfsstat4 status = NFS4_OK;
2176 2267 nfsstat4 prev_rdattr_error = sargp->rdattr_error;
2177 2268 union nfs4_attr_u *na;
2178 2269 uint8_t *amap;
2179 2270
2180 2271 sargp->op = NFS4ATTR_GETIT;
2181 2272 sargp->flag = 0;
2182 2273
2183 2274 fattrp->attrmask = 0;
2184 2275 /* if no bits requested, then return empty fattr4 */
2185 2276 if (breq == 0) {
2186 2277 fattrp->attrlist4_len = 0;
2187 2278 fattrp->attrlist4 = NULL;
2188 2279 return (NFS4_OK);
2189 2280 }
2190 2281
2191 2282 /*
2192 2283 * return NFS4ERR_INVAL when client requests write-only attrs
2193 2284 */
2194 2285 if (breq & (FATTR4_TIME_ACCESS_SET_MASK | FATTR4_TIME_MODIFY_SET_MASK))
2195 2286 return (NFS4ERR_INVAL);
2196 2287
2197 2288 nfs4_ntov_table_init(&ntov);
2198 2289 na = ntov.na;
2199 2290 amap = ntov.amap;
2200 2291
2201 2292 /*
2202 2293 * Now loop to get or verify the attrs
2203 2294 */
2204 2295 for (i = 0; i < nfs4_ntov_map_size; i++) {
2205 2296 if (breq & nfs4_ntov_map[i].fbit) {
2206 2297 if ((*nfs4_ntov_map[i].sv_getit)(
2207 2298 NFS4ATTR_SUPPORTED, sargp, NULL) == 0) {
2208 2299
2209 2300 error = (*nfs4_ntov_map[i].sv_getit)(
2210 2301 NFS4ATTR_GETIT, sargp, na);
2211 2302
2212 2303 /*
2213 2304 * Possible error values:
2214 2305 * >0 if sv_getit failed to
2215 2306 * get the attr; 0 if succeeded;
2216 2307 * <0 if rdattr_error and the
2217 2308 * attribute cannot be returned.
2218 2309 */
2219 2310 if (error && !(sargp->rdattr_error_req))
2220 2311 goto done;
2221 2312 /*
2222 2313 * If error then just for entry
2223 2314 */
2224 2315 if (error == 0) {
2225 2316 fattrp->attrmask |=
2226 2317 nfs4_ntov_map[i].fbit;
2227 2318 *amap++ =
2228 2319 (uint8_t)nfs4_ntov_map[i].nval;
2229 2320 na++;
2230 2321 (ntov.attrcnt)++;
2231 2322 } else if ((error > 0) &&
2232 2323 (sargp->rdattr_error == NFS4_OK)) {
2233 2324 sargp->rdattr_error = puterrno4(error);
2234 2325 }
2235 2326 error = 0;
2236 2327 }
2237 2328 }
2238 2329 }
2239 2330
2240 2331 /*
2241 2332 * If rdattr_error was set after the return value for it was assigned,
2242 2333 * update it.
2243 2334 */
2244 2335 if (prev_rdattr_error != sargp->rdattr_error) {
2245 2336 na = ntov.na;
2246 2337 amap = ntov.amap;
2247 2338 for (i = 0; i < ntov.attrcnt; i++, na++, amap++) {
2248 2339 k = *amap;
2249 2340 if (k < FATTR4_RDATTR_ERROR) {
2250 2341 continue;
2251 2342 }
2252 2343 if ((k == FATTR4_RDATTR_ERROR) &&
2253 2344 ((*nfs4_ntov_map[k].sv_getit)(
2254 2345 NFS4ATTR_SUPPORTED, sargp, NULL) == 0)) {
2255 2346
2256 2347 (void) (*nfs4_ntov_map[k].sv_getit)(
2257 2348 NFS4ATTR_GETIT, sargp, na);
2258 2349 }
2259 2350 break;
2260 2351 }
2261 2352 }
2262 2353
2263 2354 xdr_size = 0;
2264 2355 na = ntov.na;
2265 2356 amap = ntov.amap;
2266 2357 for (i = 0; i < ntov.attrcnt; i++, na++, amap++) {
2267 2358 xdr_size += xdr_sizeof(nfs4_ntov_map[*amap].xfunc, na);
2268 2359 }
2269 2360
2270 2361 fattrp->attrlist4_len = xdr_size;
2271 2362 if (xdr_size) {
2272 2363 /* freed by rfs4_op_getattr_free() */
2273 2364 fattrp->attrlist4 = xdr_attrs = kmem_zalloc(xdr_size, KM_SLEEP);
2274 2365
2275 2366 xdrmem_create(&xdr, xdr_attrs, xdr_size, XDR_ENCODE);
2276 2367
2277 2368 na = ntov.na;
2278 2369 amap = ntov.amap;
2279 2370 for (i = 0; i < ntov.attrcnt; i++, na++, amap++) {
2280 2371 if (!(*nfs4_ntov_map[*amap].xfunc)(&xdr, na)) {
2281 2372 DTRACE_PROBE1(nfss__e__getattr4_encfail,
2282 2373 int, *amap);
2283 2374 status = NFS4ERR_SERVERFAULT;
2284 2375 break;
2285 2376 }
2286 2377 }
2287 2378 /* xdrmem_destroy(&xdrs); */ /* NO-OP */
2288 2379 } else {
2289 2380 fattrp->attrlist4 = NULL;
2290 2381 }
2291 2382 done:
2292 2383
2293 2384 nfs4_ntov_table_free(&ntov, sargp);
2294 2385
2295 2386 if (error != 0)
2296 2387 status = puterrno4(error);
2297 2388
2298 2389 return (status);
2299 2390 }
2300 2391
2301 2392 /* ARGSUSED */
2302 2393 static void
2303 2394 rfs4_op_getattr(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
2304 2395 struct compound_state *cs)
2305 2396 {
2306 2397 GETATTR4args *args = &argop->nfs_argop4_u.opgetattr;
2307 2398 GETATTR4res *resp = &resop->nfs_resop4_u.opgetattr;
2308 2399 struct nfs4_svgetit_arg sarg;
2309 2400 struct statvfs64 sb;
2310 2401 nfsstat4 status;
2311 2402
2312 2403 DTRACE_NFSV4_2(op__getattr__start, struct compound_state *, cs,
2313 2404 GETATTR4args *, args);
2314 2405
2315 2406 if (cs->vp == NULL) {
2316 2407 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
2317 2408 goto out;
2318 2409 }
2319 2410
2320 2411 if (cs->access == CS_ACCESS_DENIED) {
2321 2412 *cs->statusp = resp->status = NFS4ERR_ACCESS;
2322 2413 goto out;
2323 2414 }
2324 2415
2325 2416 sarg.sbp = &sb;
2326 2417 sarg.cs = cs;
2327 2418 sarg.is_referral = B_FALSE;
2328 2419
2329 2420 status = bitmap4_to_attrmask(args->attr_request, &sarg);
2330 2421 if (status == NFS4_OK) {
2331 2422
2332 2423 status = bitmap4_get_sysattrs(&sarg);
2333 2424 if (status == NFS4_OK) {
2334 2425
2335 2426 /* Is this a referral? */
2336 2427 if (vn_is_nfs_reparse(cs->vp, cs->cr)) {
2337 2428 /* Older V4 Solaris client sees a link */
2338 2429 if (client_is_downrev(req))
2339 2430 sarg.vap->va_type = VLNK;
2340 2431 else
2341 2432 sarg.is_referral = B_TRUE;
2342 2433 }
2343 2434
2344 2435 status = do_rfs4_op_getattr(args->attr_request,
2345 2436 &resp->obj_attributes, &sarg);
2346 2437 }
2347 2438 }
2348 2439 *cs->statusp = resp->status = status;
2349 2440 out:
2350 2441 DTRACE_NFSV4_2(op__getattr__done, struct compound_state *, cs,
2351 2442 GETATTR4res *, resp);
2352 2443 }
2353 2444
2354 2445 static void
2355 2446 rfs4_op_getattr_free(nfs_resop4 *resop)
2356 2447 {
2357 2448 GETATTR4res *resp = &resop->nfs_resop4_u.opgetattr;
2358 2449
2359 2450 nfs4_fattr4_free(&resp->obj_attributes);
2360 2451 }
2361 2452
2362 2453 /* ARGSUSED */
2363 2454 static void
2364 2455 rfs4_op_getfh(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
2365 2456 struct compound_state *cs)
2366 2457 {
2367 2458 GETFH4res *resp = &resop->nfs_resop4_u.opgetfh;
2368 2459
2369 2460 DTRACE_NFSV4_1(op__getfh__start, struct compound_state *, cs);
2370 2461
2371 2462 if (cs->vp == NULL) {
2372 2463 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
2373 2464 goto out;
2374 2465 }
2375 2466 if (cs->access == CS_ACCESS_DENIED) {
2376 2467 *cs->statusp = resp->status = NFS4ERR_ACCESS;
2377 2468 goto out;
2378 2469 }
2379 2470
2380 2471 /* check for reparse point at the share point */
2381 2472 if (cs->exi->exi_moved || vn_is_nfs_reparse(cs->exi->exi_vp, cs->cr)) {
2382 2473 /* it's all bad */
2383 2474 cs->exi->exi_moved = 1;
2384 2475 *cs->statusp = resp->status = NFS4ERR_MOVED;
2385 2476 DTRACE_PROBE2(nfs4serv__func__referral__shared__moved,
2386 2477 vnode_t *, cs->vp, char *, "rfs4_op_getfh");
2387 2478 return;
2388 2479 }
2389 2480
2390 2481 /* check for reparse point at vp */
2391 2482 if (vn_is_nfs_reparse(cs->vp, cs->cr) && !client_is_downrev(req)) {
2392 2483 /* it's not all bad */
2393 2484 *cs->statusp = resp->status = NFS4ERR_MOVED;
2394 2485 DTRACE_PROBE2(nfs4serv__func__referral__moved,
2395 2486 vnode_t *, cs->vp, char *, "rfs4_op_getfh");
2396 2487 return;
2397 2488 }
2398 2489
2399 2490 resp->object.nfs_fh4_val =
2400 2491 kmem_alloc(cs->fh.nfs_fh4_len, KM_SLEEP);
2401 2492 nfs_fh4_copy(&cs->fh, &resp->object);
2402 2493 *cs->statusp = resp->status = NFS4_OK;
2403 2494 out:
2404 2495 DTRACE_NFSV4_2(op__getfh__done, struct compound_state *, cs,
2405 2496 GETFH4res *, resp);
2406 2497 }
2407 2498
2408 2499 static void
2409 2500 rfs4_op_getfh_free(nfs_resop4 *resop)
2410 2501 {
2411 2502 GETFH4res *resp = &resop->nfs_resop4_u.opgetfh;
2412 2503
2413 2504 if (resp->status == NFS4_OK &&
2414 2505 resp->object.nfs_fh4_val != NULL) {
2415 2506 kmem_free(resp->object.nfs_fh4_val, resp->object.nfs_fh4_len);
2416 2507 resp->object.nfs_fh4_val = NULL;
2417 2508 resp->object.nfs_fh4_len = 0;
2418 2509 }
2419 2510 }
2420 2511
2421 2512 /*
2422 2513 * illegal: args: void
2423 2514 * res : status (NFS4ERR_OP_ILLEGAL)
2424 2515 */
2425 2516 /* ARGSUSED */
2426 2517 static void
2427 2518 rfs4_op_illegal(nfs_argop4 *argop, nfs_resop4 *resop,
2428 2519 struct svc_req *req, struct compound_state *cs)
2429 2520 {
2430 2521 ILLEGAL4res *resp = &resop->nfs_resop4_u.opillegal;
2431 2522
2432 2523 resop->resop = OP_ILLEGAL;
2433 2524 *cs->statusp = resp->status = NFS4ERR_OP_ILLEGAL;
2434 2525 }
2435 2526
2436 2527 /*
2437 2528 * link: args: SAVED_FH: file, CURRENT_FH: target directory
2438 2529 * res: status. If success - CURRENT_FH unchanged, return change_info
2439 2530 */
2440 2531 /* ARGSUSED */
2441 2532 static void
2442 2533 rfs4_op_link(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
2443 2534 struct compound_state *cs)
2444 2535 {
2445 2536 LINK4args *args = &argop->nfs_argop4_u.oplink;
2446 2537 LINK4res *resp = &resop->nfs_resop4_u.oplink;
2447 2538 int error;
2448 2539 vnode_t *vp;
2449 2540 vnode_t *dvp;
2450 2541 struct vattr bdva, idva, adva;
2451 2542 char *nm;
2452 2543 uint_t len;
2453 2544 struct sockaddr *ca;
2454 2545 char *name = NULL;
2455 2546 nfsstat4 status;
2456 2547
2457 2548 DTRACE_NFSV4_2(op__link__start, struct compound_state *, cs,
2458 2549 LINK4args *, args);
2459 2550
2460 2551 /* SAVED_FH: source object */
2461 2552 vp = cs->saved_vp;
2462 2553 if (vp == NULL) {
2463 2554 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
2464 2555 goto out;
2465 2556 }
2466 2557
2467 2558 /* CURRENT_FH: target directory */
2468 2559 dvp = cs->vp;
2469 2560 if (dvp == NULL) {
2470 2561 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
2471 2562 goto out;
2472 2563 }
2473 2564
2474 2565 /*
2475 2566 * If there is a non-shared filesystem mounted on this vnode,
2476 2567 * do not allow to link any file in this directory.
2477 2568 */
2478 2569 if (vn_ismntpt(dvp)) {
2479 2570 *cs->statusp = resp->status = NFS4ERR_ACCESS;
2480 2571 goto out;
2481 2572 }
2482 2573
2483 2574 if (cs->access == CS_ACCESS_DENIED) {
2484 2575 *cs->statusp = resp->status = NFS4ERR_ACCESS;
2485 2576 goto out;
2486 2577 }
2487 2578
2488 2579 /* Check source object's type validity */
2489 2580 if (vp->v_type == VDIR) {
2490 2581 *cs->statusp = resp->status = NFS4ERR_ISDIR;
2491 2582 goto out;
2492 2583 }
2493 2584
2494 2585 /* Check target directory's type */
2495 2586 if (dvp->v_type != VDIR) {
2496 2587 *cs->statusp = resp->status = NFS4ERR_NOTDIR;
2497 2588 goto out;
2498 2589 }
2499 2590
2500 2591 if (cs->saved_exi != cs->exi) {
2501 2592 *cs->statusp = resp->status = NFS4ERR_XDEV;
2502 2593 goto out;
2503 2594 }
2504 2595
2505 2596 status = utf8_dir_verify(&args->newname);
2506 2597 if (status != NFS4_OK) {
2507 2598 *cs->statusp = resp->status = status;
2508 2599 goto out;
2509 2600 }
2510 2601
2511 2602 nm = utf8_to_fn(&args->newname, &len, NULL);
2512 2603 if (nm == NULL) {
2513 2604 *cs->statusp = resp->status = NFS4ERR_INVAL;
2514 2605 goto out;
2515 2606 }
2516 2607
2517 2608 if (len > MAXNAMELEN) {
2518 2609 *cs->statusp = resp->status = NFS4ERR_NAMETOOLONG;
2519 2610 kmem_free(nm, len);
2520 2611 goto out;
2521 2612 }
2522 2613
2523 2614 if (rdonly4(req, cs)) {
2524 2615 *cs->statusp = resp->status = NFS4ERR_ROFS;
2525 2616 kmem_free(nm, len);
2526 2617 goto out;
2527 2618 }
2528 2619
2529 2620 /* Get "before" change value */
2530 2621 bdva.va_mask = AT_CTIME|AT_SEQ;
2531 2622 error = VOP_GETATTR(dvp, &bdva, 0, cs->cr, NULL);
2532 2623 if (error) {
2533 2624 *cs->statusp = resp->status = puterrno4(error);
2534 2625 kmem_free(nm, len);
2535 2626 goto out;
2536 2627 }
2537 2628
2538 2629 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
2539 2630 name = nfscmd_convname(ca, cs->exi, nm, NFSCMD_CONV_INBOUND,
2540 2631 MAXPATHLEN + 1);
2541 2632
2542 2633 if (name == NULL) {
2543 2634 *cs->statusp = resp->status = NFS4ERR_INVAL;
2544 2635 kmem_free(nm, len);
2545 2636 goto out;
2546 2637 }
2547 2638
2548 2639 NFS4_SET_FATTR4_CHANGE(resp->cinfo.before, bdva.va_ctime)
2549 2640
2550 2641 error = VOP_LINK(dvp, vp, name, cs->cr, NULL, 0);
2551 2642
2552 2643 if (nm != name)
2553 2644 kmem_free(name, MAXPATHLEN + 1);
2554 2645 kmem_free(nm, len);
2555 2646
2556 2647 /*
2557 2648 * Get the initial "after" sequence number, if it fails, set to zero
2558 2649 */
2559 2650 idva.va_mask = AT_SEQ;
2560 2651 if (VOP_GETATTR(dvp, &idva, 0, cs->cr, NULL))
2561 2652 idva.va_seq = 0;
2562 2653
2563 2654 /*
2564 2655 * Force modified data and metadata out to stable storage.
2565 2656 */
2566 2657 (void) VOP_FSYNC(vp, FNODSYNC, cs->cr, NULL);
2567 2658 (void) VOP_FSYNC(dvp, 0, cs->cr, NULL);
2568 2659
2569 2660 if (error) {
2570 2661 *cs->statusp = resp->status = puterrno4(error);
2571 2662 goto out;
2572 2663 }
2573 2664
2574 2665 /*
2575 2666 * Get "after" change value, if it fails, simply return the
2576 2667 * before value.
2577 2668 */
2578 2669 adva.va_mask = AT_CTIME|AT_SEQ;
2579 2670 if (VOP_GETATTR(dvp, &adva, 0, cs->cr, NULL)) {
2580 2671 adva.va_ctime = bdva.va_ctime;
2581 2672 adva.va_seq = 0;
2582 2673 }
2583 2674
2584 2675 NFS4_SET_FATTR4_CHANGE(resp->cinfo.after, adva.va_ctime)
2585 2676
2586 2677 /*
2587 2678 * The cinfo.atomic = TRUE only if we have
2588 2679 * non-zero va_seq's, and it has incremented by exactly one
2589 2680 * during the VOP_LINK and it didn't change during the VOP_FSYNC.
2590 2681 */
2591 2682 if (bdva.va_seq && idva.va_seq && adva.va_seq &&
2592 2683 idva.va_seq == (bdva.va_seq + 1) && idva.va_seq == adva.va_seq)
2593 2684 resp->cinfo.atomic = TRUE;
2594 2685 else
2595 2686 resp->cinfo.atomic = FALSE;
2596 2687
2597 2688 *cs->statusp = resp->status = NFS4_OK;
2598 2689 out:
2599 2690 DTRACE_NFSV4_2(op__link__done, struct compound_state *, cs,
2600 2691 LINK4res *, resp);
2601 2692 }
2602 2693
2603 2694 /*
2604 2695 * Used by rfs4_op_lookup and rfs4_op_lookupp to do the actual work.
2605 2696 */
2606 2697
2607 2698 /* ARGSUSED */
2608 2699 static nfsstat4
2609 2700 do_rfs4_op_lookup(char *nm, struct svc_req *req, struct compound_state *cs)
2610 2701 {
2611 2702 int error;
2612 2703 int different_export = 0;
2613 2704 vnode_t *vp, *pre_tvp = NULL, *oldvp = NULL;
2614 2705 struct exportinfo *exi = NULL, *pre_exi = NULL;
2615 2706 nfsstat4 stat;
2616 2707 fid_t fid;
2617 2708 int attrdir, dotdot, walk;
2618 2709 bool_t is_newvp = FALSE;
2619 2710
2620 2711 if (cs->vp->v_flag & V_XATTRDIR) {
2621 2712 attrdir = 1;
2622 2713 ASSERT(get_fh4_flag(&cs->fh, FH4_ATTRDIR));
2623 2714 } else {
2624 2715 attrdir = 0;
2625 2716 ASSERT(! get_fh4_flag(&cs->fh, FH4_ATTRDIR));
2626 2717 }
2627 2718
2628 2719 dotdot = (nm[0] == '.' && nm[1] == '.' && nm[2] == '\0');
2629 2720
2630 2721 /*
2631 2722 * If dotdotting, then need to check whether it's
2632 2723 * above the root of a filesystem, or above an
2633 2724 * export point.
2634 2725 */
2635 2726 if (dotdot) {
2636 2727
2637 2728 /*
|
↓ open down ↓ |
1187 lines elided |
↑ open up ↑ |
2638 2729 * If dotdotting at the root of a filesystem, then
2639 2730 * need to traverse back to the mounted-on filesystem
2640 2731 * and do the dotdot lookup there.
2641 2732 */
2642 2733 if (cs->vp->v_flag & VROOT) {
2643 2734
2644 2735 /*
2645 2736 * If at the system root, then can
2646 2737 * go up no further.
2647 2738 */
2648 - if (VN_CMP(cs->vp, rootdir))
2739 + if (VN_CMP(cs->vp, ZONE_ROOTVP()))
2649 2740 return (puterrno4(ENOENT));
2650 2741
2651 2742 /*
2652 2743 * Traverse back to the mounted-on filesystem
2653 2744 */
2654 2745 cs->vp = untraverse(cs->vp);
2655 2746
2656 2747 /*
2657 2748 * Set the different_export flag so we remember
2658 2749 * to pick up a new exportinfo entry for
2659 2750 * this new filesystem.
2660 2751 */
2661 2752 different_export = 1;
2662 2753 } else {
2663 2754
2664 2755 /*
2665 2756 * If dotdotting above an export point then set
2666 2757 * the different_export to get new export info.
2667 2758 */
2668 2759 different_export = nfs_exported(cs->exi, cs->vp);
2669 2760 }
2670 2761 }
2671 2762
2672 2763 error = VOP_LOOKUP(cs->vp, nm, &vp, NULL, 0, NULL, cs->cr,
2673 2764 NULL, NULL, NULL);
2674 2765 if (error)
2675 2766 return (puterrno4(error));
2676 2767
2677 2768 /*
2678 2769 * If the vnode is in a pseudo filesystem, check whether it is visible.
2679 2770 *
2680 2771 * XXX if the vnode is a symlink and it is not visible in
2681 2772 * a pseudo filesystem, return ENOENT (not following symlink).
2682 2773 * V4 client can not mount such symlink. This is a regression
2683 2774 * from V2/V3.
2684 2775 *
2685 2776 * In the same exported filesystem, if the security flavor used
2686 2777 * is not an explicitly shared flavor, limit the view to the visible
2687 2778 * list entries only. This is not a WRONGSEC case because it's already
2688 2779 * checked via PUTROOTFH/PUTPUBFH or PUTFH.
2689 2780 */
2690 2781 if (!different_export &&
2691 2782 (PSEUDO(cs->exi) || ! is_exported_sec(cs->nfsflavor, cs->exi) ||
2692 2783 cs->access & CS_ACCESS_LIMITED)) {
2693 2784 if (! nfs_visible(cs->exi, vp, &different_export)) {
2694 2785 VN_RELE(vp);
2695 2786 return (puterrno4(ENOENT));
2696 2787 }
2697 2788 }
2698 2789
2699 2790 /*
2700 2791 * If it's a mountpoint, then traverse it.
2701 2792 */
2702 2793 if (vn_ismntpt(vp)) {
2703 2794 pre_exi = cs->exi; /* save pre-traversed exportinfo */
2704 2795 pre_tvp = vp; /* save pre-traversed vnode */
2705 2796
2706 2797 /*
2707 2798 * hold pre_tvp to counteract rele by traverse. We will
2708 2799 * need pre_tvp below if checkexport4 fails
2709 2800 */
2710 2801 VN_HOLD(pre_tvp);
2711 2802 if ((error = traverse(&vp)) != 0) {
2712 2803 VN_RELE(vp);
2713 2804 VN_RELE(pre_tvp);
2714 2805 return (puterrno4(error));
2715 2806 }
2716 2807 different_export = 1;
2717 2808 } else if (vp->v_vfsp != cs->vp->v_vfsp) {
2718 2809 /*
2719 2810 * The vfsp comparison is to handle the case where
2720 2811 * a LOFS mount is shared. lo_lookup traverses mount points,
2721 2812 * and NFS is unaware of local fs transistions because
2722 2813 * v_vfsmountedhere isn't set. For this special LOFS case,
2723 2814 * the dir and the obj returned by lookup will have different
2724 2815 * vfs ptrs.
2725 2816 */
2726 2817 different_export = 1;
2727 2818 }
2728 2819
2729 2820 if (different_export) {
2730 2821
2731 2822 bzero(&fid, sizeof (fid));
2732 2823 fid.fid_len = MAXFIDSZ;
2733 2824 error = vop_fid_pseudo(vp, &fid);
2734 2825 if (error) {
2735 2826 VN_RELE(vp);
2736 2827 if (pre_tvp)
2737 2828 VN_RELE(pre_tvp);
2738 2829 return (puterrno4(error));
2739 2830 }
2740 2831
2741 2832 if (dotdot)
2742 2833 exi = nfs_vptoexi(NULL, vp, cs->cr, &walk, NULL, TRUE);
2743 2834 else
2744 2835 exi = checkexport4(&vp->v_vfsp->vfs_fsid, &fid, vp);
2745 2836
2746 2837 if (exi == NULL) {
2747 2838 if (pre_tvp) {
2748 2839 /*
2749 2840 * If this vnode is a mounted-on vnode,
2750 2841 * but the mounted-on file system is not
2751 2842 * exported, send back the filehandle for
2752 2843 * the mounted-on vnode, not the root of
2753 2844 * the mounted-on file system.
2754 2845 */
2755 2846 VN_RELE(vp);
2756 2847 vp = pre_tvp;
2757 2848 exi = pre_exi;
2758 2849 } else {
2759 2850 VN_RELE(vp);
2760 2851 return (puterrno4(EACCES));
2761 2852 }
2762 2853 } else if (pre_tvp) {
2763 2854 /* we're done with pre_tvp now. release extra hold */
2764 2855 VN_RELE(pre_tvp);
2765 2856 }
2766 2857
2767 2858 cs->exi = exi;
2768 2859
2769 2860 /*
2770 2861 * Now we do a checkauth4. The reason is that
2771 2862 * this client/user may not have access to the new
2772 2863 * exported file system, and if they do,
2773 2864 * the client/user may be mapped to a different uid.
2774 2865 *
2775 2866 * We start with a new cr, because the checkauth4 done
2776 2867 * in the PUT*FH operation over wrote the cred's uid,
2777 2868 * gid, etc, and we want the real thing before calling
2778 2869 * checkauth4()
2779 2870 */
2780 2871 crfree(cs->cr);
2781 2872 cs->cr = crdup(cs->basecr);
2782 2873
2783 2874 oldvp = cs->vp;
2784 2875 cs->vp = vp;
2785 2876 is_newvp = TRUE;
2786 2877
2787 2878 stat = call_checkauth4(cs, req);
2788 2879 if (stat != NFS4_OK) {
2789 2880 VN_RELE(cs->vp);
2790 2881 cs->vp = oldvp;
2791 2882 return (stat);
2792 2883 }
2793 2884 }
2794 2885
2795 2886 /*
2796 2887 * After various NFS checks, do a label check on the path
2797 2888 * component. The label on this path should either be the
2798 2889 * global zone's label or a zone's label. We are only
2799 2890 * interested in the zone's label because exported files
2800 2891 * in global zone is accessible (though read-only) to
2801 2892 * clients. The exportability/visibility check is already
2802 2893 * done before reaching this code.
2803 2894 */
2804 2895 if (is_system_labeled()) {
2805 2896 bslabel_t *clabel;
2806 2897
2807 2898 ASSERT(req->rq_label != NULL);
2808 2899 clabel = req->rq_label;
2809 2900 DTRACE_PROBE2(tx__rfs4__log__info__oplookup__clabel, char *,
2810 2901 "got client label from request(1)", struct svc_req *, req);
2811 2902
2812 2903 if (!blequal(&l_admin_low->tsl_label, clabel)) {
2813 2904 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
2814 2905 cs->exi)) {
2815 2906 error = EACCES;
2816 2907 goto err_out;
2817 2908 }
2818 2909 } else {
2819 2910 /*
2820 2911 * We grant access to admin_low label clients
2821 2912 * only if the client is trusted, i.e. also
2822 2913 * running Solaris Trusted Extension.
2823 2914 */
2824 2915 struct sockaddr *ca;
2825 2916 int addr_type;
2826 2917 void *ipaddr;
2827 2918 tsol_tpc_t *tp;
2828 2919
2829 2920 ca = (struct sockaddr *)svc_getrpccaller(
2830 2921 req->rq_xprt)->buf;
2831 2922 if (ca->sa_family == AF_INET) {
2832 2923 addr_type = IPV4_VERSION;
2833 2924 ipaddr = &((struct sockaddr_in *)ca)->sin_addr;
2834 2925 } else if (ca->sa_family == AF_INET6) {
2835 2926 addr_type = IPV6_VERSION;
2836 2927 ipaddr = &((struct sockaddr_in6 *)
2837 2928 ca)->sin6_addr;
2838 2929 }
2839 2930 tp = find_tpc(ipaddr, addr_type, B_FALSE);
2840 2931 if (tp == NULL || tp->tpc_tp.tp_doi !=
2841 2932 l_admin_low->tsl_doi || tp->tpc_tp.host_type !=
2842 2933 SUN_CIPSO) {
2843 2934 if (tp != NULL)
2844 2935 TPC_RELE(tp);
2845 2936 error = EACCES;
2846 2937 goto err_out;
2847 2938 }
2848 2939 TPC_RELE(tp);
2849 2940 }
2850 2941 }
2851 2942
2852 2943 error = makefh4(&cs->fh, vp, cs->exi);
2853 2944
2854 2945 err_out:
2855 2946 if (error) {
2856 2947 if (is_newvp) {
2857 2948 VN_RELE(cs->vp);
2858 2949 cs->vp = oldvp;
2859 2950 } else
2860 2951 VN_RELE(vp);
2861 2952 return (puterrno4(error));
2862 2953 }
2863 2954
2864 2955 if (!is_newvp) {
2865 2956 if (cs->vp)
2866 2957 VN_RELE(cs->vp);
2867 2958 cs->vp = vp;
2868 2959 } else if (oldvp)
2869 2960 VN_RELE(oldvp);
2870 2961
2871 2962 /*
2872 2963 * if did lookup on attrdir and didn't lookup .., set named
2873 2964 * attr fh flag
2874 2965 */
2875 2966 if (attrdir && ! dotdot)
2876 2967 set_fh4_flag(&cs->fh, FH4_NAMEDATTR);
2877 2968
2878 2969 /* Assume false for now, open proc will set this */
2879 2970 cs->mandlock = FALSE;
2880 2971
2881 2972 return (NFS4_OK);
2882 2973 }
2883 2974
2884 2975 /* ARGSUSED */
2885 2976 static void
2886 2977 rfs4_op_lookup(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
2887 2978 struct compound_state *cs)
2888 2979 {
2889 2980 LOOKUP4args *args = &argop->nfs_argop4_u.oplookup;
2890 2981 LOOKUP4res *resp = &resop->nfs_resop4_u.oplookup;
2891 2982 char *nm;
2892 2983 uint_t len;
2893 2984 struct sockaddr *ca;
2894 2985 char *name = NULL;
2895 2986 nfsstat4 status;
2896 2987
2897 2988 DTRACE_NFSV4_2(op__lookup__start, struct compound_state *, cs,
2898 2989 LOOKUP4args *, args);
2899 2990
2900 2991 if (cs->vp == NULL) {
2901 2992 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
2902 2993 goto out;
2903 2994 }
2904 2995
2905 2996 if (cs->vp->v_type == VLNK) {
2906 2997 *cs->statusp = resp->status = NFS4ERR_SYMLINK;
2907 2998 goto out;
2908 2999 }
2909 3000
2910 3001 if (cs->vp->v_type != VDIR) {
2911 3002 *cs->statusp = resp->status = NFS4ERR_NOTDIR;
2912 3003 goto out;
2913 3004 }
2914 3005
2915 3006 status = utf8_dir_verify(&args->objname);
2916 3007 if (status != NFS4_OK) {
2917 3008 *cs->statusp = resp->status = status;
2918 3009 goto out;
2919 3010 }
2920 3011
2921 3012 nm = utf8_to_str(&args->objname, &len, NULL);
2922 3013 if (nm == NULL) {
2923 3014 *cs->statusp = resp->status = NFS4ERR_INVAL;
2924 3015 goto out;
2925 3016 }
2926 3017
2927 3018 if (len > MAXNAMELEN) {
2928 3019 *cs->statusp = resp->status = NFS4ERR_NAMETOOLONG;
2929 3020 kmem_free(nm, len);
2930 3021 goto out;
2931 3022 }
2932 3023
2933 3024 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
2934 3025 name = nfscmd_convname(ca, cs->exi, nm, NFSCMD_CONV_INBOUND,
2935 3026 MAXPATHLEN + 1);
2936 3027
2937 3028 if (name == NULL) {
2938 3029 *cs->statusp = resp->status = NFS4ERR_INVAL;
2939 3030 kmem_free(nm, len);
2940 3031 goto out;
2941 3032 }
2942 3033
2943 3034 *cs->statusp = resp->status = do_rfs4_op_lookup(name, req, cs);
2944 3035
2945 3036 if (name != nm)
2946 3037 kmem_free(name, MAXPATHLEN + 1);
2947 3038 kmem_free(nm, len);
2948 3039
2949 3040 out:
2950 3041 DTRACE_NFSV4_2(op__lookup__done, struct compound_state *, cs,
2951 3042 LOOKUP4res *, resp);
2952 3043 }
2953 3044
2954 3045 /* ARGSUSED */
2955 3046 static void
2956 3047 rfs4_op_lookupp(nfs_argop4 *args, nfs_resop4 *resop, struct svc_req *req,
2957 3048 struct compound_state *cs)
2958 3049 {
2959 3050 LOOKUPP4res *resp = &resop->nfs_resop4_u.oplookupp;
2960 3051
2961 3052 DTRACE_NFSV4_1(op__lookupp__start, struct compound_state *, cs);
2962 3053
2963 3054 if (cs->vp == NULL) {
2964 3055 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
2965 3056 goto out;
2966 3057 }
2967 3058
2968 3059 if (cs->vp->v_type != VDIR) {
2969 3060 *cs->statusp = resp->status = NFS4ERR_NOTDIR;
2970 3061 goto out;
2971 3062 }
2972 3063
2973 3064 *cs->statusp = resp->status = do_rfs4_op_lookup("..", req, cs);
2974 3065
2975 3066 /*
2976 3067 * From NFSV4 Specification, LOOKUPP should not check for
2977 3068 * NFS4ERR_WRONGSEC. Retrun NFS4_OK instead.
2978 3069 */
2979 3070 if (resp->status == NFS4ERR_WRONGSEC) {
2980 3071 *cs->statusp = resp->status = NFS4_OK;
2981 3072 }
2982 3073
2983 3074 out:
2984 3075 DTRACE_NFSV4_2(op__lookupp__done, struct compound_state *, cs,
2985 3076 LOOKUPP4res *, resp);
2986 3077 }
2987 3078
2988 3079
2989 3080 /*ARGSUSED2*/
2990 3081 static void
2991 3082 rfs4_op_openattr(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
2992 3083 struct compound_state *cs)
2993 3084 {
2994 3085 OPENATTR4args *args = &argop->nfs_argop4_u.opopenattr;
2995 3086 OPENATTR4res *resp = &resop->nfs_resop4_u.opopenattr;
2996 3087 vnode_t *avp = NULL;
2997 3088 int lookup_flags = LOOKUP_XATTR, error;
2998 3089 int exp_ro = 0;
2999 3090
3000 3091 DTRACE_NFSV4_2(op__openattr__start, struct compound_state *, cs,
3001 3092 OPENATTR4args *, args);
3002 3093
3003 3094 if (cs->vp == NULL) {
3004 3095 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
3005 3096 goto out;
3006 3097 }
3007 3098
3008 3099 if ((cs->vp->v_vfsp->vfs_flag & VFS_XATTR) == 0 &&
3009 3100 !vfs_has_feature(cs->vp->v_vfsp, VFSFT_SYSATTR_VIEWS)) {
3010 3101 *cs->statusp = resp->status = puterrno4(ENOTSUP);
3011 3102 goto out;
3012 3103 }
3013 3104
3014 3105 /*
3015 3106 * If file system supports passing ACE mask to VOP_ACCESS then
3016 3107 * check for ACE_READ_NAMED_ATTRS, otherwise do legacy checks
3017 3108 */
3018 3109
3019 3110 if (vfs_has_feature(cs->vp->v_vfsp, VFSFT_ACEMASKONACCESS))
3020 3111 error = VOP_ACCESS(cs->vp, ACE_READ_NAMED_ATTRS,
3021 3112 V_ACE_MASK, cs->cr, NULL);
3022 3113 else
3023 3114 error = ((VOP_ACCESS(cs->vp, VREAD, 0, cs->cr, NULL) != 0) &&
3024 3115 (VOP_ACCESS(cs->vp, VWRITE, 0, cs->cr, NULL) != 0) &&
3025 3116 (VOP_ACCESS(cs->vp, VEXEC, 0, cs->cr, NULL) != 0));
3026 3117
3027 3118 if (error) {
3028 3119 *cs->statusp = resp->status = puterrno4(EACCES);
3029 3120 goto out;
3030 3121 }
3031 3122
3032 3123 /*
3033 3124 * The CREATE_XATTR_DIR VOP flag cannot be specified if
3034 3125 * the file system is exported read-only -- regardless of
3035 3126 * createdir flag. Otherwise the attrdir would be created
3036 3127 * (assuming server fs isn't mounted readonly locally). If
3037 3128 * VOP_LOOKUP returns ENOENT in this case, the error will
3038 3129 * be translated into EROFS. ENOSYS is mapped to ENOTSUP
3039 3130 * because specfs has no VOP_LOOKUP op, so the macro would
3040 3131 * return ENOSYS. EINVAL is returned by all (current)
3041 3132 * Solaris file system implementations when any of their
3042 3133 * restrictions are violated (xattr(dir) can't have xattrdir).
3043 3134 * Returning NOTSUPP is more appropriate in this case
3044 3135 * because the object will never be able to have an attrdir.
3045 3136 */
3046 3137 if (args->createdir && ! (exp_ro = rdonly4(req, cs)))
3047 3138 lookup_flags |= CREATE_XATTR_DIR;
3048 3139
3049 3140 error = VOP_LOOKUP(cs->vp, "", &avp, NULL, lookup_flags, NULL, cs->cr,
3050 3141 NULL, NULL, NULL);
3051 3142
3052 3143 if (error) {
3053 3144 if (error == ENOENT && args->createdir && exp_ro)
3054 3145 *cs->statusp = resp->status = puterrno4(EROFS);
3055 3146 else if (error == EINVAL || error == ENOSYS)
3056 3147 *cs->statusp = resp->status = puterrno4(ENOTSUP);
3057 3148 else
3058 3149 *cs->statusp = resp->status = puterrno4(error);
3059 3150 goto out;
3060 3151 }
3061 3152
3062 3153 ASSERT(avp->v_flag & V_XATTRDIR);
3063 3154
3064 3155 error = makefh4(&cs->fh, avp, cs->exi);
3065 3156
3066 3157 if (error) {
3067 3158 VN_RELE(avp);
3068 3159 *cs->statusp = resp->status = puterrno4(error);
3069 3160 goto out;
3070 3161 }
3071 3162
3072 3163 VN_RELE(cs->vp);
3073 3164 cs->vp = avp;
3074 3165
3075 3166 /*
3076 3167 * There is no requirement for an attrdir fh flag
3077 3168 * because the attrdir has a vnode flag to distinguish
3078 3169 * it from regular (non-xattr) directories. The
3079 3170 * FH4_ATTRDIR flag is set for future sanity checks.
3080 3171 */
3081 3172 set_fh4_flag(&cs->fh, FH4_ATTRDIR);
3082 3173 *cs->statusp = resp->status = NFS4_OK;
3083 3174
3084 3175 out:
3085 3176 DTRACE_NFSV4_2(op__openattr__done, struct compound_state *, cs,
3086 3177 OPENATTR4res *, resp);
3087 3178 }
3088 3179
3089 3180 static int
3090 3181 do_io(int direction, vnode_t *vp, struct uio *uio, int ioflag, cred_t *cred,
3091 3182 caller_context_t *ct)
3092 3183 {
3093 3184 int error;
3094 3185 int i;
3095 3186 clock_t delaytime;
3096 3187
3097 3188 delaytime = MSEC_TO_TICK_ROUNDUP(rfs4_lock_delay);
3098 3189
3099 3190 /*
3100 3191 * Don't block on mandatory locks. If this routine returns
3101 3192 * EAGAIN, the caller should return NFS4ERR_LOCKED.
3102 3193 */
3103 3194 uio->uio_fmode = FNONBLOCK;
3104 3195
3105 3196 for (i = 0; i < rfs4_maxlock_tries; i++) {
3106 3197
3107 3198
3108 3199 if (direction == FREAD) {
3109 3200 (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, ct);
3110 3201 error = VOP_READ(vp, uio, ioflag, cred, ct);
3111 3202 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, ct);
3112 3203 } else {
3113 3204 (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, ct);
3114 3205 error = VOP_WRITE(vp, uio, ioflag, cred, ct);
3115 3206 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, ct);
3116 3207 }
3117 3208
3118 3209 if (error != EAGAIN)
3119 3210 break;
3120 3211
3121 3212 if (i < rfs4_maxlock_tries - 1) {
3122 3213 delay(delaytime);
3123 3214 delaytime *= 2;
3124 3215 }
3125 3216 }
3126 3217
3127 3218 return (error);
3128 3219 }
3129 3220
3130 3221 /* ARGSUSED */
3131 3222 static void
3132 3223 rfs4_op_read(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
3133 3224 struct compound_state *cs)
3134 3225 {
3135 3226 READ4args *args = &argop->nfs_argop4_u.opread;
3136 3227 READ4res *resp = &resop->nfs_resop4_u.opread;
3137 3228 int error;
3138 3229 int verror;
3139 3230 vnode_t *vp;
3140 3231 struct vattr va;
3141 3232 struct iovec iov, *iovp = NULL;
3142 3233 int iovcnt;
3143 3234 struct uio uio;
3144 3235 u_offset_t offset;
3145 3236 bool_t *deleg = &cs->deleg;
3146 3237 nfsstat4 stat;
3147 3238 int in_crit = 0;
3148 3239 mblk_t *mp = NULL;
3149 3240 int alloc_err = 0;
3150 3241 int rdma_used = 0;
3151 3242 int loaned_buffers;
3152 3243 caller_context_t ct;
3153 3244 struct uio *uiop;
3154 3245
3155 3246 DTRACE_NFSV4_2(op__read__start, struct compound_state *, cs,
3156 3247 READ4args, args);
3157 3248
3158 3249 vp = cs->vp;
3159 3250 if (vp == NULL) {
3160 3251 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
3161 3252 goto out;
3162 3253 }
3163 3254 if (cs->access == CS_ACCESS_DENIED) {
3164 3255 *cs->statusp = resp->status = NFS4ERR_ACCESS;
3165 3256 goto out;
3166 3257 }
3167 3258
3168 3259 if ((stat = rfs4_check_stateid(FREAD, vp, &args->stateid, FALSE,
3169 3260 deleg, TRUE, &ct)) != NFS4_OK) {
3170 3261 *cs->statusp = resp->status = stat;
3171 3262 goto out;
3172 3263 }
3173 3264
3174 3265 /*
3175 3266 * Enter the critical region before calling VOP_RWLOCK
3176 3267 * to avoid a deadlock with write requests.
3177 3268 */
3178 3269 if (nbl_need_check(vp)) {
3179 3270 nbl_start_crit(vp, RW_READER);
3180 3271 in_crit = 1;
3181 3272 if (nbl_conflict(vp, NBL_READ, args->offset, args->count, 0,
3182 3273 &ct)) {
3183 3274 *cs->statusp = resp->status = NFS4ERR_LOCKED;
3184 3275 goto out;
3185 3276 }
3186 3277 }
3187 3278
3188 3279 if (args->wlist) {
3189 3280 if (args->count > clist_len(args->wlist)) {
3190 3281 *cs->statusp = resp->status = NFS4ERR_INVAL;
3191 3282 goto out;
3192 3283 }
3193 3284 rdma_used = 1;
3194 3285 }
3195 3286
3196 3287 /* use loaned buffers for TCP */
3197 3288 loaned_buffers = (nfs_loaned_buffers && !rdma_used) ? 1 : 0;
3198 3289
3199 3290 va.va_mask = AT_MODE|AT_SIZE|AT_UID;
3200 3291 verror = VOP_GETATTR(vp, &va, 0, cs->cr, &ct);
3201 3292
3202 3293 /*
3203 3294 * If we can't get the attributes, then we can't do the
3204 3295 * right access checking. So, we'll fail the request.
3205 3296 */
3206 3297 if (verror) {
3207 3298 *cs->statusp = resp->status = puterrno4(verror);
3208 3299 goto out;
3209 3300 }
3210 3301
3211 3302 if (vp->v_type != VREG) {
3212 3303 *cs->statusp = resp->status =
3213 3304 ((vp->v_type == VDIR) ? NFS4ERR_ISDIR : NFS4ERR_INVAL);
3214 3305 goto out;
3215 3306 }
3216 3307
3217 3308 if (crgetuid(cs->cr) != va.va_uid &&
3218 3309 (error = VOP_ACCESS(vp, VREAD, 0, cs->cr, &ct)) &&
3219 3310 (error = VOP_ACCESS(vp, VEXEC, 0, cs->cr, &ct))) {
3220 3311 *cs->statusp = resp->status = puterrno4(error);
3221 3312 goto out;
3222 3313 }
3223 3314
3224 3315 if (MANDLOCK(vp, va.va_mode)) { /* XXX - V4 supports mand locking */
3225 3316 *cs->statusp = resp->status = NFS4ERR_ACCESS;
3226 3317 goto out;
3227 3318 }
3228 3319
3229 3320 offset = args->offset;
3230 3321 if (offset >= va.va_size) {
3231 3322 *cs->statusp = resp->status = NFS4_OK;
3232 3323 resp->eof = TRUE;
3233 3324 resp->data_len = 0;
3234 3325 resp->data_val = NULL;
3235 3326 resp->mblk = NULL;
3236 3327 /* RDMA */
3237 3328 resp->wlist = args->wlist;
3238 3329 resp->wlist_len = resp->data_len;
3239 3330 *cs->statusp = resp->status = NFS4_OK;
3240 3331 if (resp->wlist)
3241 3332 clist_zero_len(resp->wlist);
3242 3333 goto out;
3243 3334 }
3244 3335
3245 3336 if (args->count == 0) {
3246 3337 *cs->statusp = resp->status = NFS4_OK;
3247 3338 resp->eof = FALSE;
3248 3339 resp->data_len = 0;
3249 3340 resp->data_val = NULL;
3250 3341 resp->mblk = NULL;
3251 3342 /* RDMA */
3252 3343 resp->wlist = args->wlist;
3253 3344 resp->wlist_len = resp->data_len;
3254 3345 if (resp->wlist)
3255 3346 clist_zero_len(resp->wlist);
3256 3347 goto out;
3257 3348 }
3258 3349
3259 3350 /*
3260 3351 * Do not allocate memory more than maximum allowed
3261 3352 * transfer size
3262 3353 */
3263 3354 if (args->count > rfs4_tsize(req))
3264 3355 args->count = rfs4_tsize(req);
3265 3356
3266 3357 if (loaned_buffers) {
3267 3358 uiop = (uio_t *)rfs_setup_xuio(vp);
3268 3359 ASSERT(uiop != NULL);
3269 3360 uiop->uio_segflg = UIO_SYSSPACE;
3270 3361 uiop->uio_loffset = args->offset;
3271 3362 uiop->uio_resid = args->count;
3272 3363
3273 3364 /* Jump to do the read if successful */
3274 3365 if (!VOP_REQZCBUF(vp, UIO_READ, (xuio_t *)uiop, cs->cr, &ct)) {
3275 3366 /*
3276 3367 * Need to hold the vnode until after VOP_RETZCBUF()
3277 3368 * is called.
3278 3369 */
3279 3370 VN_HOLD(vp);
3280 3371 goto doio_read;
3281 3372 }
3282 3373
3283 3374 DTRACE_PROBE2(nfss__i__reqzcbuf_failed, int,
3284 3375 uiop->uio_loffset, int, uiop->uio_resid);
3285 3376
3286 3377 uiop->uio_extflg = 0;
3287 3378
3288 3379 /* failure to setup for zero copy */
3289 3380 rfs_free_xuio((void *)uiop);
3290 3381 loaned_buffers = 0;
3291 3382 }
3292 3383
3293 3384 /*
3294 3385 * If returning data via RDMA Write, then grab the chunk list. If we
3295 3386 * aren't returning READ data w/RDMA_WRITE, then grab a mblk.
3296 3387 */
3297 3388 if (rdma_used) {
3298 3389 mp = NULL;
3299 3390 (void) rdma_get_wchunk(req, &iov, args->wlist);
3300 3391 uio.uio_iov = &iov;
3301 3392 uio.uio_iovcnt = 1;
3302 3393 } else {
3303 3394 /*
3304 3395 * mp will contain the data to be sent out in the read reply.
3305 3396 * It will be freed after the reply has been sent.
3306 3397 */
3307 3398 mp = rfs_read_alloc(args->count, &iovp, &iovcnt);
3308 3399 ASSERT(mp != NULL);
3309 3400 ASSERT(alloc_err == 0);
3310 3401 uio.uio_iov = iovp;
3311 3402 uio.uio_iovcnt = iovcnt;
3312 3403 }
3313 3404
3314 3405 uio.uio_segflg = UIO_SYSSPACE;
3315 3406 uio.uio_extflg = UIO_COPY_CACHED;
3316 3407 uio.uio_loffset = args->offset;
3317 3408 uio.uio_resid = args->count;
3318 3409 uiop = &uio;
3319 3410
3320 3411 doio_read:
3321 3412 error = do_io(FREAD, vp, uiop, 0, cs->cr, &ct);
3322 3413
3323 3414 va.va_mask = AT_SIZE;
3324 3415 verror = VOP_GETATTR(vp, &va, 0, cs->cr, &ct);
3325 3416
3326 3417 if (error) {
3327 3418 if (mp)
3328 3419 freemsg(mp);
3329 3420 *cs->statusp = resp->status = puterrno4(error);
3330 3421 goto out;
3331 3422 }
3332 3423
3333 3424 /* make mblk using zc buffers */
3334 3425 if (loaned_buffers) {
3335 3426 mp = uio_to_mblk(uiop);
3336 3427 ASSERT(mp != NULL);
3337 3428 }
3338 3429
3339 3430 *cs->statusp = resp->status = NFS4_OK;
3340 3431
3341 3432 ASSERT(uiop->uio_resid >= 0);
3342 3433 resp->data_len = args->count - uiop->uio_resid;
3343 3434 if (mp) {
3344 3435 resp->data_val = (char *)mp->b_datap->db_base;
3345 3436 rfs_rndup_mblks(mp, resp->data_len, loaned_buffers);
3346 3437 } else {
3347 3438 resp->data_val = (caddr_t)iov.iov_base;
3348 3439 }
3349 3440
3350 3441 resp->mblk = mp;
3351 3442
3352 3443 if (!verror && offset + resp->data_len == va.va_size)
3353 3444 resp->eof = TRUE;
3354 3445 else
3355 3446 resp->eof = FALSE;
3356 3447
3357 3448 if (rdma_used) {
3358 3449 if (!rdma_setup_read_data4(args, resp)) {
3359 3450 *cs->statusp = resp->status = NFS4ERR_INVAL;
3360 3451 }
3361 3452 } else {
3362 3453 resp->wlist = NULL;
3363 3454 }
3364 3455
3365 3456 out:
3366 3457 if (in_crit)
3367 3458 nbl_end_crit(vp);
3368 3459
3369 3460 if (iovp != NULL)
3370 3461 kmem_free(iovp, iovcnt * sizeof (struct iovec));
3371 3462
3372 3463 DTRACE_NFSV4_2(op__read__done, struct compound_state *, cs,
3373 3464 READ4res *, resp);
3374 3465 }
3375 3466
3376 3467 static void
3377 3468 rfs4_op_read_free(nfs_resop4 *resop)
3378 3469 {
3379 3470 READ4res *resp = &resop->nfs_resop4_u.opread;
3380 3471
3381 3472 if (resp->status == NFS4_OK && resp->mblk != NULL) {
3382 3473 freemsg(resp->mblk);
3383 3474 resp->mblk = NULL;
3384 3475 resp->data_val = NULL;
3385 3476 resp->data_len = 0;
3386 3477 }
3387 3478 }
3388 3479
3389 3480 static void
3390 3481 rfs4_op_readdir_free(nfs_resop4 * resop)
3391 3482 {
3392 3483 READDIR4res *resp = &resop->nfs_resop4_u.opreaddir;
3393 3484
3394 3485 if (resp->status == NFS4_OK && resp->mblk != NULL) {
3395 3486 freeb(resp->mblk);
3396 3487 resp->mblk = NULL;
3397 3488 resp->data_len = 0;
3398 3489 }
3399 3490 }
3400 3491
3401 3492
|
↓ open down ↓ |
743 lines elided |
↑ open up ↑ |
3402 3493 /* ARGSUSED */
3403 3494 static void
3404 3495 rfs4_op_putpubfh(nfs_argop4 *args, nfs_resop4 *resop, struct svc_req *req,
3405 3496 struct compound_state *cs)
3406 3497 {
3407 3498 PUTPUBFH4res *resp = &resop->nfs_resop4_u.opputpubfh;
3408 3499 int error;
3409 3500 vnode_t *vp;
3410 3501 struct exportinfo *exi, *sav_exi;
3411 3502 nfs_fh4_fmt_t *fh_fmtp;
3503 + nfs_export_t *ne = nfs_get_export();
3412 3504
3413 3505 DTRACE_NFSV4_1(op__putpubfh__start, struct compound_state *, cs);
3414 3506
3415 3507 if (cs->vp) {
3416 3508 VN_RELE(cs->vp);
3417 3509 cs->vp = NULL;
3418 3510 }
3419 3511
3420 3512 if (cs->cr)
3421 3513 crfree(cs->cr);
3422 3514
3423 3515 cs->cr = crdup(cs->basecr);
3424 3516
3425 - vp = exi_public->exi_vp;
3517 + vp = ne->exi_public->exi_vp;
3426 3518 if (vp == NULL) {
3427 3519 *cs->statusp = resp->status = NFS4ERR_SERVERFAULT;
3428 3520 goto out;
3429 3521 }
3430 3522
3431 - error = makefh4(&cs->fh, vp, exi_public);
3523 + error = makefh4(&cs->fh, vp, ne->exi_public);
3432 3524 if (error != 0) {
3433 3525 *cs->statusp = resp->status = puterrno4(error);
3434 3526 goto out;
3435 3527 }
3436 3528 sav_exi = cs->exi;
3437 - if (exi_public == exi_root) {
3529 + if (ne->exi_public == ne->exi_root) {
3438 3530 /*
3439 3531 * No filesystem is actually shared public, so we default
3440 3532 * to exi_root. In this case, we must check whether root
3441 3533 * is exported.
3442 3534 */
3443 3535 fh_fmtp = (nfs_fh4_fmt_t *)cs->fh.nfs_fh4_val;
3444 3536
3445 3537 /*
3446 3538 * if root filesystem is exported, the exportinfo struct that we
3447 3539 * should use is what checkexport4 returns, because root_exi is
3448 3540 * actually a mostly empty struct.
3449 3541 */
3450 3542 exi = checkexport4(&fh_fmtp->fh4_fsid,
3451 3543 (fid_t *)&fh_fmtp->fh4_xlen, NULL);
3452 - cs->exi = ((exi != NULL) ? exi : exi_public);
3544 + cs->exi = ((exi != NULL) ? exi : ne->exi_public);
3453 3545 } else {
3454 3546 /*
3455 3547 * it's a properly shared filesystem
3456 3548 */
3457 - cs->exi = exi_public;
3549 + cs->exi = ne->exi_public;
3458 3550 }
3459 3551
3460 3552 if (is_system_labeled()) {
3461 3553 bslabel_t *clabel;
3462 3554
3463 3555 ASSERT(req->rq_label != NULL);
3464 3556 clabel = req->rq_label;
3465 3557 DTRACE_PROBE2(tx__rfs4__log__info__opputpubfh__clabel, char *,
3466 3558 "got client label from request(1)",
3467 3559 struct svc_req *, req);
3468 3560 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3469 3561 if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3470 3562 cs->exi)) {
3471 3563 *cs->statusp = resp->status =
3472 3564 NFS4ERR_SERVERFAULT;
3473 3565 goto out;
3474 3566 }
3475 3567 }
3476 3568 }
3477 3569
3478 3570 VN_HOLD(vp);
3479 3571 cs->vp = vp;
3480 3572
3481 3573 if ((resp->status = call_checkauth4(cs, req)) != NFS4_OK) {
3482 3574 VN_RELE(cs->vp);
3483 3575 cs->vp = NULL;
3484 3576 cs->exi = sav_exi;
3485 3577 goto out;
3486 3578 }
3487 3579
3488 3580 *cs->statusp = resp->status = NFS4_OK;
3489 3581 out:
3490 3582 DTRACE_NFSV4_2(op__putpubfh__done, struct compound_state *, cs,
3491 3583 PUTPUBFH4res *, resp);
3492 3584 }
3493 3585
3494 3586 /*
3495 3587 * XXX - issue with put*fh operations. Suppose /export/home is exported.
3496 3588 * Suppose an NFS client goes to mount /export/home/joe. If /export, home,
3497 3589 * or joe have restrictive search permissions, then we shouldn't let
3498 3590 * the client get a file handle. This is easy to enforce. However, we
3499 3591 * don't know what security flavor should be used until we resolve the
3500 3592 * path name. Another complication is uid mapping. If root is
3501 3593 * the user, then it will be mapped to the anonymous user by default,
3502 3594 * but we won't know that till we've resolved the path name. And we won't
3503 3595 * know what the anonymous user is.
3504 3596 * Luckily, SECINFO is specified to take a full filename.
3505 3597 * So what we will have to in rfs4_op_lookup is check that flavor of
3506 3598 * the target object matches that of the request, and if root was the
3507 3599 * caller, check for the root= and anon= options, and if necessary,
3508 3600 * repeat the lookup using the right cred_t. But that's not done yet.
3509 3601 */
3510 3602 /* ARGSUSED */
3511 3603 static void
3512 3604 rfs4_op_putfh(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
3513 3605 struct compound_state *cs)
3514 3606 {
3515 3607 PUTFH4args *args = &argop->nfs_argop4_u.opputfh;
3516 3608 PUTFH4res *resp = &resop->nfs_resop4_u.opputfh;
3517 3609 nfs_fh4_fmt_t *fh_fmtp;
3518 3610
3519 3611 DTRACE_NFSV4_2(op__putfh__start, struct compound_state *, cs,
3520 3612 PUTFH4args *, args);
3521 3613
|
↓ open down ↓ |
54 lines elided |
↑ open up ↑ |
3522 3614 if (cs->vp) {
3523 3615 VN_RELE(cs->vp);
3524 3616 cs->vp = NULL;
3525 3617 }
3526 3618
3527 3619 if (cs->cr) {
3528 3620 crfree(cs->cr);
3529 3621 cs->cr = NULL;
3530 3622 }
3531 3623
3532 -
3533 3624 if (args->object.nfs_fh4_len < NFS_FH4_LEN) {
3534 3625 *cs->statusp = resp->status = NFS4ERR_BADHANDLE;
3535 3626 goto out;
3536 3627 }
3537 3628
3538 3629 fh_fmtp = (nfs_fh4_fmt_t *)args->object.nfs_fh4_val;
3539 3630 cs->exi = checkexport4(&fh_fmtp->fh4_fsid, (fid_t *)&fh_fmtp->fh4_xlen,
3540 3631 NULL);
3541 3632
3542 3633 if (cs->exi == NULL) {
3543 3634 *cs->statusp = resp->status = NFS4ERR_STALE;
3544 3635 goto out;
3545 3636 }
3546 3637
3547 3638 cs->cr = crdup(cs->basecr);
3548 3639
3549 3640 ASSERT(cs->cr != NULL);
3550 3641
3551 3642 if (! (cs->vp = nfs4_fhtovp(&args->object, cs->exi, &resp->status))) {
3552 3643 *cs->statusp = resp->status;
3553 3644 goto out;
3554 3645 }
3555 3646
3556 3647 if ((resp->status = call_checkauth4(cs, req)) != NFS4_OK) {
3557 3648 VN_RELE(cs->vp);
3558 3649 cs->vp = NULL;
3559 3650 goto out;
3560 3651 }
3561 3652
3562 3653 nfs_fh4_copy(&args->object, &cs->fh);
3563 3654 *cs->statusp = resp->status = NFS4_OK;
3564 3655 cs->deleg = FALSE;
3565 3656
3566 3657 out:
3567 3658 DTRACE_NFSV4_2(op__putfh__done, struct compound_state *, cs,
3568 3659 PUTFH4res *, resp);
3569 3660 }
3570 3661
3571 3662 /* ARGSUSED */
3572 3663 static void
3573 3664 rfs4_op_putrootfh(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
3574 3665 struct compound_state *cs)
3575 3666 {
3576 3667 PUTROOTFH4res *resp = &resop->nfs_resop4_u.opputrootfh;
3577 3668 int error;
3578 3669 fid_t fid;
3579 3670 struct exportinfo *exi, *sav_exi;
3580 3671
3581 3672 DTRACE_NFSV4_1(op__putrootfh__start, struct compound_state *, cs);
3582 3673
3583 3674 if (cs->vp) {
3584 3675 VN_RELE(cs->vp);
3585 3676 cs->vp = NULL;
3586 3677 }
3587 3678
3588 3679 if (cs->cr)
|
↓ open down ↓ |
46 lines elided |
↑ open up ↑ |
3589 3680 crfree(cs->cr);
3590 3681
3591 3682 cs->cr = crdup(cs->basecr);
3592 3683
3593 3684 /*
3594 3685 * Using rootdir, the system root vnode,
3595 3686 * get its fid.
3596 3687 */
3597 3688 bzero(&fid, sizeof (fid));
3598 3689 fid.fid_len = MAXFIDSZ;
3599 - error = vop_fid_pseudo(rootdir, &fid);
3690 + error = vop_fid_pseudo(ZONE_ROOTVP(), &fid);
3600 3691 if (error != 0) {
3601 3692 *cs->statusp = resp->status = puterrno4(error);
3602 3693 goto out;
3603 3694 }
3604 3695
3605 3696 /*
3606 3697 * Then use the root fsid & fid it to find out if it's exported
3607 3698 *
3608 3699 * If the server root isn't exported directly, then
3609 3700 * it should at least be a pseudo export based on
3610 3701 * one or more exports further down in the server's
3611 3702 * file tree.
3612 3703 */
3613 - exi = checkexport4(&rootdir->v_vfsp->vfs_fsid, &fid, NULL);
3704 + exi = checkexport4(&ZONE_ROOTVP()->v_vfsp->vfs_fsid, &fid, NULL);
3614 3705 if (exi == NULL || exi->exi_export.ex_flags & EX_PUBLIC) {
3615 3706 NFS4_DEBUG(rfs4_debug,
3616 3707 (CE_WARN, "rfs4_op_putrootfh: export check failure"));
3617 3708 *cs->statusp = resp->status = NFS4ERR_SERVERFAULT;
3618 3709 goto out;
3619 3710 }
3620 3711
3621 3712 /*
3622 3713 * Now make a filehandle based on the root
3623 3714 * export and root vnode.
3624 3715 */
3625 - error = makefh4(&cs->fh, rootdir, exi);
3716 + error = makefh4(&cs->fh, ZONE_ROOTVP(), exi);
3626 3717 if (error != 0) {
3627 3718 *cs->statusp = resp->status = puterrno4(error);
3628 3719 goto out;
3629 3720 }
3630 3721
3631 3722 sav_exi = cs->exi;
3632 3723 cs->exi = exi;
3633 3724
3634 - VN_HOLD(rootdir);
3635 - cs->vp = rootdir;
3725 + VN_HOLD(ZONE_ROOTVP());
3726 + cs->vp = ZONE_ROOTVP();
3636 3727
3637 3728 if ((resp->status = call_checkauth4(cs, req)) != NFS4_OK) {
3638 - VN_RELE(rootdir);
3729 + VN_RELE(cs->vp);
3639 3730 cs->vp = NULL;
3640 3731 cs->exi = sav_exi;
3641 3732 goto out;
3642 3733 }
3643 3734
3644 3735 *cs->statusp = resp->status = NFS4_OK;
3645 3736 cs->deleg = FALSE;
3646 3737 out:
3647 3738 DTRACE_NFSV4_2(op__putrootfh__done, struct compound_state *, cs,
3648 3739 PUTROOTFH4res *, resp);
3649 3740 }
3650 3741
3651 3742 /*
3652 3743 * set_rdattr_params sets up the variables used to manage what information
3653 3744 * to get for each directory entry.
3654 3745 */
3655 3746 static nfsstat4
3656 3747 set_rdattr_params(struct nfs4_svgetit_arg *sargp,
3657 3748 bitmap4 attrs, bool_t *need_to_lookup)
3658 3749 {
3659 3750 uint_t va_mask;
3660 3751 nfsstat4 status;
3661 3752 bitmap4 objbits;
3662 3753
3663 3754 status = bitmap4_to_attrmask(attrs, sargp);
3664 3755 if (status != NFS4_OK) {
3665 3756 /*
3666 3757 * could not even figure attr mask
3667 3758 */
3668 3759 return (status);
3669 3760 }
3670 3761 va_mask = sargp->vap->va_mask;
3671 3762
3672 3763 /*
3673 3764 * dirent's d_ino is always correct value for mounted_on_fileid.
3674 3765 * mntdfid_set is set once here, but mounted_on_fileid is
3675 3766 * set in main dirent processing loop for each dirent.
3676 3767 * The mntdfid_set is a simple optimization that lets the
3677 3768 * server attr code avoid work when caller is readdir.
3678 3769 */
3679 3770 sargp->mntdfid_set = TRUE;
3680 3771
3681 3772 /*
3682 3773 * Lookup entry only if client asked for any of the following:
3683 3774 * a) vattr attrs
3684 3775 * b) vfs attrs
3685 3776 * c) attrs w/per-object scope requested (change, filehandle, etc)
3686 3777 * other than mounted_on_fileid (which we can take from dirent)
3687 3778 */
3688 3779 objbits = attrs ? attrs & NFS4_VP_ATTR_MASK : 0;
3689 3780
3690 3781 if (va_mask || sargp->sbp || (objbits & ~FATTR4_MOUNTED_ON_FILEID_MASK))
3691 3782 *need_to_lookup = TRUE;
3692 3783 else
3693 3784 *need_to_lookup = FALSE;
3694 3785
3695 3786 if (sargp->sbp == NULL)
3696 3787 return (NFS4_OK);
3697 3788
3698 3789 /*
3699 3790 * If filesystem attrs are requested, get them now from the
3700 3791 * directory vp, as most entries will have same filesystem. The only
3701 3792 * exception are mounted over entries but we handle
3702 3793 * those as we go (XXX mounted over detection not yet implemented).
3703 3794 */
3704 3795 sargp->vap->va_mask = 0; /* to avoid VOP_GETATTR */
3705 3796 status = bitmap4_get_sysattrs(sargp);
3706 3797 sargp->vap->va_mask = va_mask;
3707 3798
3708 3799 if ((status != NFS4_OK) && sargp->rdattr_error_req) {
3709 3800 /*
3710 3801 * Failed to get filesystem attributes.
3711 3802 * Return a rdattr_error for each entry, but don't fail.
3712 3803 * However, don't get any obj-dependent attrs.
3713 3804 */
3714 3805 sargp->rdattr_error = status; /* for rdattr_error */
3715 3806 *need_to_lookup = FALSE;
3716 3807 /*
3717 3808 * At least get fileid for regular readdir output
3718 3809 */
3719 3810 sargp->vap->va_mask &= AT_NODEID;
3720 3811 status = NFS4_OK;
3721 3812 }
3722 3813
3723 3814 return (status);
3724 3815 }
3725 3816
3726 3817 /*
3727 3818 * readlink: args: CURRENT_FH.
3728 3819 * res: status. If success - CURRENT_FH unchanged, return linktext.
3729 3820 */
3730 3821
3731 3822 /* ARGSUSED */
3732 3823 static void
3733 3824 rfs4_op_readlink(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
3734 3825 struct compound_state *cs)
3735 3826 {
3736 3827 READLINK4res *resp = &resop->nfs_resop4_u.opreadlink;
3737 3828 int error;
3738 3829 vnode_t *vp;
3739 3830 struct iovec iov;
3740 3831 struct vattr va;
3741 3832 struct uio uio;
3742 3833 char *data;
3743 3834 struct sockaddr *ca;
3744 3835 char *name = NULL;
3745 3836 int is_referral;
3746 3837
3747 3838 DTRACE_NFSV4_1(op__readlink__start, struct compound_state *, cs);
3748 3839
3749 3840 /* CURRENT_FH: directory */
3750 3841 vp = cs->vp;
3751 3842 if (vp == NULL) {
3752 3843 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
3753 3844 goto out;
3754 3845 }
3755 3846
3756 3847 if (cs->access == CS_ACCESS_DENIED) {
3757 3848 *cs->statusp = resp->status = NFS4ERR_ACCESS;
3758 3849 goto out;
3759 3850 }
3760 3851
3761 3852 /* Is it a referral? */
3762 3853 if (vn_is_nfs_reparse(vp, cs->cr) && client_is_downrev(req)) {
3763 3854
3764 3855 is_referral = 1;
3765 3856
3766 3857 } else {
3767 3858
3768 3859 is_referral = 0;
3769 3860
3770 3861 if (vp->v_type == VDIR) {
3771 3862 *cs->statusp = resp->status = NFS4ERR_ISDIR;
3772 3863 goto out;
3773 3864 }
3774 3865
3775 3866 if (vp->v_type != VLNK) {
3776 3867 *cs->statusp = resp->status = NFS4ERR_INVAL;
3777 3868 goto out;
3778 3869 }
3779 3870
3780 3871 }
3781 3872
3782 3873 va.va_mask = AT_MODE;
3783 3874 error = VOP_GETATTR(vp, &va, 0, cs->cr, NULL);
3784 3875 if (error) {
3785 3876 *cs->statusp = resp->status = puterrno4(error);
3786 3877 goto out;
3787 3878 }
3788 3879
3789 3880 if (MANDLOCK(vp, va.va_mode)) {
3790 3881 *cs->statusp = resp->status = NFS4ERR_ACCESS;
3791 3882 goto out;
3792 3883 }
3793 3884
3794 3885 data = kmem_alloc(MAXPATHLEN + 1, KM_SLEEP);
3795 3886
3796 3887 if (is_referral) {
3797 3888 char *s;
3798 3889 size_t strsz;
3799 3890
3800 3891 /* Get an artificial symlink based on a referral */
3801 3892 s = build_symlink(vp, cs->cr, &strsz);
3802 3893 global_svstat_ptr[4][NFS_REFERLINKS].value.ui64++;
3803 3894 DTRACE_PROBE2(nfs4serv__func__referral__reflink,
3804 3895 vnode_t *, vp, char *, s);
3805 3896 if (s == NULL)
3806 3897 error = EINVAL;
3807 3898 else {
3808 3899 error = 0;
3809 3900 (void) strlcpy(data, s, MAXPATHLEN + 1);
3810 3901 kmem_free(s, strsz);
3811 3902 }
3812 3903
3813 3904 } else {
3814 3905
3815 3906 iov.iov_base = data;
3816 3907 iov.iov_len = MAXPATHLEN;
3817 3908 uio.uio_iov = &iov;
3818 3909 uio.uio_iovcnt = 1;
3819 3910 uio.uio_segflg = UIO_SYSSPACE;
3820 3911 uio.uio_extflg = UIO_COPY_CACHED;
3821 3912 uio.uio_loffset = 0;
3822 3913 uio.uio_resid = MAXPATHLEN;
3823 3914
3824 3915 error = VOP_READLINK(vp, &uio, cs->cr, NULL);
3825 3916
3826 3917 if (!error)
3827 3918 *(data + MAXPATHLEN - uio.uio_resid) = '\0';
3828 3919 }
3829 3920
3830 3921 if (error) {
3831 3922 kmem_free((caddr_t)data, (uint_t)MAXPATHLEN + 1);
3832 3923 *cs->statusp = resp->status = puterrno4(error);
3833 3924 goto out;
3834 3925 }
3835 3926
3836 3927 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
3837 3928 name = nfscmd_convname(ca, cs->exi, data, NFSCMD_CONV_OUTBOUND,
3838 3929 MAXPATHLEN + 1);
3839 3930
3840 3931 if (name == NULL) {
3841 3932 /*
3842 3933 * Even though the conversion failed, we return
3843 3934 * something. We just don't translate it.
3844 3935 */
3845 3936 name = data;
3846 3937 }
3847 3938
3848 3939 /*
3849 3940 * treat link name as data
3850 3941 */
3851 3942 (void) str_to_utf8(name, (utf8string *)&resp->link);
3852 3943
3853 3944 if (name != data)
3854 3945 kmem_free(name, MAXPATHLEN + 1);
3855 3946 kmem_free((caddr_t)data, (uint_t)MAXPATHLEN + 1);
3856 3947 *cs->statusp = resp->status = NFS4_OK;
3857 3948
3858 3949 out:
3859 3950 DTRACE_NFSV4_2(op__readlink__done, struct compound_state *, cs,
3860 3951 READLINK4res *, resp);
3861 3952 }
3862 3953
3863 3954 static void
3864 3955 rfs4_op_readlink_free(nfs_resop4 *resop)
3865 3956 {
3866 3957 READLINK4res *resp = &resop->nfs_resop4_u.opreadlink;
3867 3958 utf8string *symlink = (utf8string *)&resp->link;
3868 3959
3869 3960 if (symlink->utf8string_val) {
3870 3961 UTF8STRING_FREE(*symlink)
3871 3962 }
3872 3963 }
3873 3964
3874 3965 /*
3875 3966 * release_lockowner:
3876 3967 * Release any state associated with the supplied
3877 3968 * lockowner. Note if any lo_state is holding locks we will not
3878 3969 * rele that lo_state and thus the lockowner will not be destroyed.
3879 3970 * A client using lock after the lock owner stateid has been released
3880 3971 * will suffer the consequence of NFS4ERR_BAD_STATEID and would have
3881 3972 * to reissue the lock with new_lock_owner set to TRUE.
3882 3973 * args: lock_owner
3883 3974 * res: status
3884 3975 */
3885 3976 /* ARGSUSED */
3886 3977 static void
3887 3978 rfs4_op_release_lockowner(nfs_argop4 *argop, nfs_resop4 *resop,
3888 3979 struct svc_req *req, struct compound_state *cs)
3889 3980 {
3890 3981 RELEASE_LOCKOWNER4args *ap = &argop->nfs_argop4_u.oprelease_lockowner;
3891 3982 RELEASE_LOCKOWNER4res *resp = &resop->nfs_resop4_u.oprelease_lockowner;
3892 3983 rfs4_lockowner_t *lo;
3893 3984 rfs4_openowner_t *oo;
3894 3985 rfs4_state_t *sp;
3895 3986 rfs4_lo_state_t *lsp;
3896 3987 rfs4_client_t *cp;
3897 3988 bool_t create = FALSE;
3898 3989 locklist_t *llist;
3899 3990 sysid_t sysid;
3900 3991
3901 3992 DTRACE_NFSV4_2(op__release__lockowner__start, struct compound_state *,
3902 3993 cs, RELEASE_LOCKOWNER4args *, ap);
3903 3994
3904 3995 /* Make sure there is a clientid around for this request */
3905 3996 cp = rfs4_findclient_by_id(ap->lock_owner.clientid, FALSE);
3906 3997
3907 3998 if (cp == NULL) {
3908 3999 *cs->statusp = resp->status =
3909 4000 rfs4_check_clientid(&ap->lock_owner.clientid, 0);
3910 4001 goto out;
3911 4002 }
3912 4003 rfs4_client_rele(cp);
3913 4004
3914 4005 lo = rfs4_findlockowner(&ap->lock_owner, &create);
3915 4006 if (lo == NULL) {
3916 4007 *cs->statusp = resp->status = NFS4_OK;
3917 4008 goto out;
3918 4009 }
3919 4010 ASSERT(lo->rl_client != NULL);
3920 4011
3921 4012 /*
3922 4013 * Check for EXPIRED client. If so will reap state with in a lease
3923 4014 * period or on next set_clientid_confirm step
3924 4015 */
3925 4016 if (rfs4_lease_expired(lo->rl_client)) {
3926 4017 rfs4_lockowner_rele(lo);
3927 4018 *cs->statusp = resp->status = NFS4ERR_EXPIRED;
3928 4019 goto out;
3929 4020 }
3930 4021
3931 4022 /*
3932 4023 * If no sysid has been assigned, then no locks exist; just return.
3933 4024 */
3934 4025 rfs4_dbe_lock(lo->rl_client->rc_dbe);
3935 4026 if (lo->rl_client->rc_sysidt == LM_NOSYSID) {
3936 4027 rfs4_lockowner_rele(lo);
3937 4028 rfs4_dbe_unlock(lo->rl_client->rc_dbe);
3938 4029 goto out;
3939 4030 }
3940 4031
3941 4032 sysid = lo->rl_client->rc_sysidt;
3942 4033 rfs4_dbe_unlock(lo->rl_client->rc_dbe);
3943 4034
3944 4035 /*
3945 4036 * Mark the lockowner invalid.
3946 4037 */
3947 4038 rfs4_dbe_hide(lo->rl_dbe);
3948 4039
3949 4040 /*
3950 4041 * sysid-pid pair should now not be used since the lockowner is
3951 4042 * invalid. If the client were to instantiate the lockowner again
3952 4043 * it would be assigned a new pid. Thus we can get the list of
3953 4044 * current locks.
3954 4045 */
3955 4046
3956 4047 llist = flk_get_active_locks(sysid, lo->rl_pid);
3957 4048 /* If we are still holding locks fail */
3958 4049 if (llist != NULL) {
3959 4050
3960 4051 *cs->statusp = resp->status = NFS4ERR_LOCKS_HELD;
3961 4052
3962 4053 flk_free_locklist(llist);
3963 4054 /*
3964 4055 * We need to unhide the lockowner so the client can
3965 4056 * try it again. The bad thing here is if the client
3966 4057 * has a logic error that took it here in the first place
3967 4058 * they probably have lost accounting of the locks that it
3968 4059 * is holding. So we may have dangling state until the
3969 4060 * open owner state is reaped via close. One scenario
3970 4061 * that could possibly occur is that the client has
3971 4062 * sent the unlock request(s) in separate threads
3972 4063 * and has not waited for the replies before sending the
3973 4064 * RELEASE_LOCKOWNER request. Presumably, it would expect
3974 4065 * and deal appropriately with NFS4ERR_LOCKS_HELD, by
3975 4066 * reissuing the request.
3976 4067 */
3977 4068 rfs4_dbe_unhide(lo->rl_dbe);
3978 4069 rfs4_lockowner_rele(lo);
3979 4070 goto out;
3980 4071 }
3981 4072
3982 4073 /*
3983 4074 * For the corresponding client we need to check each open
3984 4075 * owner for any opens that have lockowner state associated
3985 4076 * with this lockowner.
3986 4077 */
3987 4078
3988 4079 rfs4_dbe_lock(lo->rl_client->rc_dbe);
3989 4080 for (oo = list_head(&lo->rl_client->rc_openownerlist); oo != NULL;
3990 4081 oo = list_next(&lo->rl_client->rc_openownerlist, oo)) {
3991 4082
3992 4083 rfs4_dbe_lock(oo->ro_dbe);
3993 4084 for (sp = list_head(&oo->ro_statelist); sp != NULL;
3994 4085 sp = list_next(&oo->ro_statelist, sp)) {
3995 4086
3996 4087 rfs4_dbe_lock(sp->rs_dbe);
3997 4088 for (lsp = list_head(&sp->rs_lostatelist);
3998 4089 lsp != NULL;
3999 4090 lsp = list_next(&sp->rs_lostatelist, lsp)) {
4000 4091 if (lsp->rls_locker == lo) {
4001 4092 rfs4_dbe_lock(lsp->rls_dbe);
4002 4093 rfs4_dbe_invalidate(lsp->rls_dbe);
4003 4094 rfs4_dbe_unlock(lsp->rls_dbe);
4004 4095 }
4005 4096 }
4006 4097 rfs4_dbe_unlock(sp->rs_dbe);
4007 4098 }
4008 4099 rfs4_dbe_unlock(oo->ro_dbe);
4009 4100 }
4010 4101 rfs4_dbe_unlock(lo->rl_client->rc_dbe);
4011 4102
4012 4103 rfs4_lockowner_rele(lo);
4013 4104
4014 4105 *cs->statusp = resp->status = NFS4_OK;
4015 4106
4016 4107 out:
4017 4108 DTRACE_NFSV4_2(op__release__lockowner__done, struct compound_state *,
4018 4109 cs, RELEASE_LOCKOWNER4res *, resp);
4019 4110 }
4020 4111
4021 4112 /*
4022 4113 * short utility function to lookup a file and recall the delegation
4023 4114 */
4024 4115 static rfs4_file_t *
4025 4116 rfs4_lookup_and_findfile(vnode_t *dvp, char *nm, vnode_t **vpp,
4026 4117 int *lkup_error, cred_t *cr)
4027 4118 {
4028 4119 vnode_t *vp;
4029 4120 rfs4_file_t *fp = NULL;
4030 4121 bool_t fcreate = FALSE;
4031 4122 int error;
4032 4123
4033 4124 if (vpp)
4034 4125 *vpp = NULL;
4035 4126
4036 4127 if ((error = VOP_LOOKUP(dvp, nm, &vp, NULL, 0, NULL, cr, NULL, NULL,
4037 4128 NULL)) == 0) {
4038 4129 if (vp->v_type == VREG)
4039 4130 fp = rfs4_findfile(vp, NULL, &fcreate);
4040 4131 if (vpp)
4041 4132 *vpp = vp;
4042 4133 else
4043 4134 VN_RELE(vp);
4044 4135 }
4045 4136
4046 4137 if (lkup_error)
4047 4138 *lkup_error = error;
4048 4139
4049 4140 return (fp);
4050 4141 }
4051 4142
4052 4143 /*
4053 4144 * remove: args: CURRENT_FH: directory; name.
4054 4145 * res: status. If success - CURRENT_FH unchanged, return change_info
4055 4146 * for directory.
4056 4147 */
4057 4148 /* ARGSUSED */
4058 4149 static void
4059 4150 rfs4_op_remove(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
4060 4151 struct compound_state *cs)
4061 4152 {
4062 4153 REMOVE4args *args = &argop->nfs_argop4_u.opremove;
4063 4154 REMOVE4res *resp = &resop->nfs_resop4_u.opremove;
4064 4155 int error;
4065 4156 vnode_t *dvp, *vp;
4066 4157 struct vattr bdva, idva, adva;
4067 4158 char *nm;
4068 4159 uint_t len;
4069 4160 rfs4_file_t *fp;
4070 4161 int in_crit = 0;
4071 4162 bslabel_t *clabel;
4072 4163 struct sockaddr *ca;
4073 4164 char *name = NULL;
4074 4165 nfsstat4 status;
4075 4166
4076 4167 DTRACE_NFSV4_2(op__remove__start, struct compound_state *, cs,
4077 4168 REMOVE4args *, args);
4078 4169
4079 4170 /* CURRENT_FH: directory */
4080 4171 dvp = cs->vp;
4081 4172 if (dvp == NULL) {
4082 4173 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
4083 4174 goto out;
4084 4175 }
4085 4176
4086 4177 if (cs->access == CS_ACCESS_DENIED) {
4087 4178 *cs->statusp = resp->status = NFS4ERR_ACCESS;
4088 4179 goto out;
4089 4180 }
4090 4181
4091 4182 /*
4092 4183 * If there is an unshared filesystem mounted on this vnode,
4093 4184 * Do not allow to remove anything in this directory.
4094 4185 */
4095 4186 if (vn_ismntpt(dvp)) {
4096 4187 *cs->statusp = resp->status = NFS4ERR_ACCESS;
4097 4188 goto out;
4098 4189 }
4099 4190
4100 4191 if (dvp->v_type != VDIR) {
4101 4192 *cs->statusp = resp->status = NFS4ERR_NOTDIR;
4102 4193 goto out;
4103 4194 }
4104 4195
4105 4196 status = utf8_dir_verify(&args->target);
4106 4197 if (status != NFS4_OK) {
4107 4198 *cs->statusp = resp->status = status;
4108 4199 goto out;
4109 4200 }
4110 4201
4111 4202 /*
4112 4203 * Lookup the file so that we can check if it's a directory
4113 4204 */
4114 4205 nm = utf8_to_fn(&args->target, &len, NULL);
4115 4206 if (nm == NULL) {
4116 4207 *cs->statusp = resp->status = NFS4ERR_INVAL;
4117 4208 goto out;
4118 4209 }
4119 4210
4120 4211 if (len > MAXNAMELEN) {
4121 4212 *cs->statusp = resp->status = NFS4ERR_NAMETOOLONG;
4122 4213 kmem_free(nm, len);
4123 4214 goto out;
4124 4215 }
4125 4216
4126 4217 if (rdonly4(req, cs)) {
4127 4218 *cs->statusp = resp->status = NFS4ERR_ROFS;
4128 4219 kmem_free(nm, len);
4129 4220 goto out;
4130 4221 }
4131 4222
4132 4223 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
4133 4224 name = nfscmd_convname(ca, cs->exi, nm, NFSCMD_CONV_INBOUND,
4134 4225 MAXPATHLEN + 1);
4135 4226
4136 4227 if (name == NULL) {
4137 4228 *cs->statusp = resp->status = NFS4ERR_INVAL;
4138 4229 kmem_free(nm, len);
4139 4230 goto out;
4140 4231 }
4141 4232
4142 4233 /*
4143 4234 * Lookup the file to determine type and while we are see if
4144 4235 * there is a file struct around and check for delegation.
4145 4236 * We don't need to acquire va_seq before this lookup, if
4146 4237 * it causes an update, cinfo.before will not match, which will
4147 4238 * trigger a cache flush even if atomic is TRUE.
4148 4239 */
4149 4240 if (fp = rfs4_lookup_and_findfile(dvp, name, &vp, &error, cs->cr)) {
4150 4241 if (rfs4_check_delegated_byfp(FWRITE, fp, TRUE, TRUE, TRUE,
4151 4242 NULL)) {
4152 4243 VN_RELE(vp);
4153 4244 rfs4_file_rele(fp);
4154 4245 *cs->statusp = resp->status = NFS4ERR_DELAY;
4155 4246 if (nm != name)
4156 4247 kmem_free(name, MAXPATHLEN + 1);
4157 4248 kmem_free(nm, len);
4158 4249 goto out;
4159 4250 }
4160 4251 }
4161 4252
4162 4253 /* Didn't find anything to remove */
4163 4254 if (vp == NULL) {
4164 4255 *cs->statusp = resp->status = error;
4165 4256 if (nm != name)
4166 4257 kmem_free(name, MAXPATHLEN + 1);
4167 4258 kmem_free(nm, len);
4168 4259 goto out;
4169 4260 }
4170 4261
4171 4262 if (nbl_need_check(vp)) {
4172 4263 nbl_start_crit(vp, RW_READER);
4173 4264 in_crit = 1;
4174 4265 if (nbl_conflict(vp, NBL_REMOVE, 0, 0, 0, NULL)) {
4175 4266 *cs->statusp = resp->status = NFS4ERR_FILE_OPEN;
4176 4267 if (nm != name)
4177 4268 kmem_free(name, MAXPATHLEN + 1);
4178 4269 kmem_free(nm, len);
4179 4270 nbl_end_crit(vp);
4180 4271 VN_RELE(vp);
4181 4272 if (fp) {
4182 4273 rfs4_clear_dont_grant(fp);
4183 4274 rfs4_file_rele(fp);
4184 4275 }
4185 4276 goto out;
4186 4277 }
4187 4278 }
4188 4279
4189 4280 /* check label before allowing removal */
4190 4281 if (is_system_labeled()) {
4191 4282 ASSERT(req->rq_label != NULL);
4192 4283 clabel = req->rq_label;
4193 4284 DTRACE_PROBE2(tx__rfs4__log__info__opremove__clabel, char *,
4194 4285 "got client label from request(1)",
4195 4286 struct svc_req *, req);
4196 4287 if (!blequal(&l_admin_low->tsl_label, clabel)) {
4197 4288 if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
4198 4289 cs->exi)) {
4199 4290 *cs->statusp = resp->status = NFS4ERR_ACCESS;
4200 4291 if (name != nm)
4201 4292 kmem_free(name, MAXPATHLEN + 1);
4202 4293 kmem_free(nm, len);
4203 4294 if (in_crit)
4204 4295 nbl_end_crit(vp);
4205 4296 VN_RELE(vp);
4206 4297 if (fp) {
4207 4298 rfs4_clear_dont_grant(fp);
4208 4299 rfs4_file_rele(fp);
4209 4300 }
4210 4301 goto out;
4211 4302 }
4212 4303 }
4213 4304 }
4214 4305
4215 4306 /* Get dir "before" change value */
4216 4307 bdva.va_mask = AT_CTIME|AT_SEQ;
4217 4308 error = VOP_GETATTR(dvp, &bdva, 0, cs->cr, NULL);
4218 4309 if (error) {
4219 4310 *cs->statusp = resp->status = puterrno4(error);
4220 4311 if (nm != name)
4221 4312 kmem_free(name, MAXPATHLEN + 1);
4222 4313 kmem_free(nm, len);
4223 4314 if (in_crit)
4224 4315 nbl_end_crit(vp);
4225 4316 VN_RELE(vp);
4226 4317 if (fp) {
4227 4318 rfs4_clear_dont_grant(fp);
4228 4319 rfs4_file_rele(fp);
4229 4320 }
4230 4321 goto out;
4231 4322 }
4232 4323 NFS4_SET_FATTR4_CHANGE(resp->cinfo.before, bdva.va_ctime)
4233 4324
4234 4325 /* Actually do the REMOVE operation */
4235 4326 if (vp->v_type == VDIR) {
4236 4327 /*
4237 4328 * Can't remove a directory that has a mounted-on filesystem.
4238 4329 */
|
↓ open down ↓ |
590 lines elided |
↑ open up ↑ |
4239 4330 if (vn_ismntpt(vp)) {
4240 4331 error = EACCES;
4241 4332 } else {
4242 4333 /*
4243 4334 * System V defines rmdir to return EEXIST,
4244 4335 * not ENOTEMPTY, if the directory is not
4245 4336 * empty. A System V NFS server needs to map
4246 4337 * NFS4ERR_EXIST to NFS4ERR_NOTEMPTY to
4247 4338 * transmit over the wire.
4248 4339 */
4249 - if ((error = VOP_RMDIR(dvp, name, rootdir, cs->cr,
4340 + if ((error = VOP_RMDIR(dvp, name, ZONE_ROOTVP(), cs->cr,
4250 4341 NULL, 0)) == EEXIST)
4251 4342 error = ENOTEMPTY;
4252 4343 }
4253 4344 } else {
4254 4345 if ((error = VOP_REMOVE(dvp, name, cs->cr, NULL, 0)) == 0 &&
4255 4346 fp != NULL) {
4256 4347 struct vattr va;
4257 4348 vnode_t *tvp;
4258 4349
4259 4350 rfs4_dbe_lock(fp->rf_dbe);
4260 4351 tvp = fp->rf_vp;
4261 4352 if (tvp)
4262 4353 VN_HOLD(tvp);
4263 4354 rfs4_dbe_unlock(fp->rf_dbe);
4264 4355
4265 4356 if (tvp) {
4266 4357 /*
4267 4358 * This is va_seq safe because we are not
4268 4359 * manipulating dvp.
4269 4360 */
4270 4361 va.va_mask = AT_NLINK;
4271 4362 if (!VOP_GETATTR(tvp, &va, 0, cs->cr, NULL) &&
4272 4363 va.va_nlink == 0) {
4273 4364 /* Remove state on file remove */
4274 4365 if (in_crit) {
4275 4366 nbl_end_crit(vp);
4276 4367 in_crit = 0;
4277 4368 }
4278 4369 rfs4_close_all_state(fp);
4279 4370 }
4280 4371 VN_RELE(tvp);
4281 4372 }
4282 4373 }
4283 4374 }
4284 4375
4285 4376 if (in_crit)
4286 4377 nbl_end_crit(vp);
4287 4378 VN_RELE(vp);
4288 4379
4289 4380 if (fp) {
4290 4381 rfs4_clear_dont_grant(fp);
4291 4382 rfs4_file_rele(fp);
4292 4383 }
4293 4384 if (nm != name)
4294 4385 kmem_free(name, MAXPATHLEN + 1);
4295 4386 kmem_free(nm, len);
4296 4387
4297 4388 if (error) {
4298 4389 *cs->statusp = resp->status = puterrno4(error);
4299 4390 goto out;
4300 4391 }
4301 4392
4302 4393 /*
4303 4394 * Get the initial "after" sequence number, if it fails, set to zero
4304 4395 */
4305 4396 idva.va_mask = AT_SEQ;
4306 4397 if (VOP_GETATTR(dvp, &idva, 0, cs->cr, NULL))
4307 4398 idva.va_seq = 0;
4308 4399
4309 4400 /*
4310 4401 * Force modified data and metadata out to stable storage.
4311 4402 */
4312 4403 (void) VOP_FSYNC(dvp, 0, cs->cr, NULL);
4313 4404
4314 4405 /*
4315 4406 * Get "after" change value, if it fails, simply return the
4316 4407 * before value.
4317 4408 */
4318 4409 adva.va_mask = AT_CTIME|AT_SEQ;
4319 4410 if (VOP_GETATTR(dvp, &adva, 0, cs->cr, NULL)) {
4320 4411 adva.va_ctime = bdva.va_ctime;
4321 4412 adva.va_seq = 0;
4322 4413 }
4323 4414
4324 4415 NFS4_SET_FATTR4_CHANGE(resp->cinfo.after, adva.va_ctime)
4325 4416
4326 4417 /*
4327 4418 * The cinfo.atomic = TRUE only if we have
4328 4419 * non-zero va_seq's, and it has incremented by exactly one
4329 4420 * during the VOP_REMOVE/RMDIR and it didn't change during
4330 4421 * the VOP_FSYNC.
4331 4422 */
4332 4423 if (bdva.va_seq && idva.va_seq && adva.va_seq &&
4333 4424 idva.va_seq == (bdva.va_seq + 1) && idva.va_seq == adva.va_seq)
4334 4425 resp->cinfo.atomic = TRUE;
4335 4426 else
4336 4427 resp->cinfo.atomic = FALSE;
4337 4428
4338 4429 *cs->statusp = resp->status = NFS4_OK;
4339 4430
4340 4431 out:
4341 4432 DTRACE_NFSV4_2(op__remove__done, struct compound_state *, cs,
4342 4433 REMOVE4res *, resp);
4343 4434 }
4344 4435
4345 4436 /*
4346 4437 * rename: args: SAVED_FH: from directory, CURRENT_FH: target directory,
4347 4438 * oldname and newname.
4348 4439 * res: status. If success - CURRENT_FH unchanged, return change_info
4349 4440 * for both from and target directories.
4350 4441 */
|
↓ open down ↓ |
91 lines elided |
↑ open up ↑ |
4351 4442 /* ARGSUSED */
4352 4443 static void
4353 4444 rfs4_op_rename(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
4354 4445 struct compound_state *cs)
4355 4446 {
4356 4447 RENAME4args *args = &argop->nfs_argop4_u.oprename;
4357 4448 RENAME4res *resp = &resop->nfs_resop4_u.oprename;
4358 4449 int error;
4359 4450 vnode_t *odvp;
4360 4451 vnode_t *ndvp;
4361 - vnode_t *srcvp, *targvp;
4452 + vnode_t *srcvp, *targvp, *tvp;
4362 4453 struct vattr obdva, oidva, oadva;
4363 4454 struct vattr nbdva, nidva, nadva;
4364 4455 char *onm, *nnm;
4365 4456 uint_t olen, nlen;
4366 4457 rfs4_file_t *fp, *sfp;
4367 4458 int in_crit_src, in_crit_targ;
4368 4459 int fp_rele_grant_hold, sfp_rele_grant_hold;
4460 + int unlinked;
4369 4461 bslabel_t *clabel;
4370 4462 struct sockaddr *ca;
4371 4463 char *converted_onm = NULL;
4372 4464 char *converted_nnm = NULL;
4373 4465 nfsstat4 status;
4374 4466
4375 4467 DTRACE_NFSV4_2(op__rename__start, struct compound_state *, cs,
4376 4468 RENAME4args *, args);
4377 4469
4378 4470 fp = sfp = NULL;
4379 - srcvp = targvp = NULL;
4471 + srcvp = targvp = tvp = NULL;
4380 4472 in_crit_src = in_crit_targ = 0;
4381 4473 fp_rele_grant_hold = sfp_rele_grant_hold = 0;
4474 + unlinked = 0;
4382 4475
4383 4476 /* CURRENT_FH: target directory */
4384 4477 ndvp = cs->vp;
4385 4478 if (ndvp == NULL) {
4386 4479 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
4387 4480 goto out;
4388 4481 }
4389 4482
4390 4483 /* SAVED_FH: from directory */
4391 4484 odvp = cs->saved_vp;
4392 4485 if (odvp == NULL) {
4393 4486 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
4394 4487 goto out;
4395 4488 }
4396 4489
4397 4490 if (cs->access == CS_ACCESS_DENIED) {
4398 4491 *cs->statusp = resp->status = NFS4ERR_ACCESS;
4399 4492 goto out;
4400 4493 }
4401 4494
4402 4495 /*
4403 4496 * If there is an unshared filesystem mounted on this vnode,
4404 4497 * do not allow to rename objects in this directory.
4405 4498 */
4406 4499 if (vn_ismntpt(odvp)) {
4407 4500 *cs->statusp = resp->status = NFS4ERR_ACCESS;
4408 4501 goto out;
4409 4502 }
4410 4503
4411 4504 /*
4412 4505 * If there is an unshared filesystem mounted on this vnode,
4413 4506 * do not allow to rename to this directory.
4414 4507 */
4415 4508 if (vn_ismntpt(ndvp)) {
4416 4509 *cs->statusp = resp->status = NFS4ERR_ACCESS;
4417 4510 goto out;
4418 4511 }
4419 4512
4420 4513 if (odvp->v_type != VDIR || ndvp->v_type != VDIR) {
4421 4514 *cs->statusp = resp->status = NFS4ERR_NOTDIR;
4422 4515 goto out;
4423 4516 }
4424 4517
4425 4518 if (cs->saved_exi != cs->exi) {
4426 4519 *cs->statusp = resp->status = NFS4ERR_XDEV;
4427 4520 goto out;
4428 4521 }
4429 4522
4430 4523 status = utf8_dir_verify(&args->oldname);
4431 4524 if (status != NFS4_OK) {
4432 4525 *cs->statusp = resp->status = status;
4433 4526 goto out;
4434 4527 }
4435 4528
4436 4529 status = utf8_dir_verify(&args->newname);
4437 4530 if (status != NFS4_OK) {
4438 4531 *cs->statusp = resp->status = status;
4439 4532 goto out;
4440 4533 }
4441 4534
4442 4535 onm = utf8_to_fn(&args->oldname, &olen, NULL);
4443 4536 if (onm == NULL) {
4444 4537 *cs->statusp = resp->status = NFS4ERR_INVAL;
4445 4538 goto out;
4446 4539 }
4447 4540 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
4448 4541 nlen = MAXPATHLEN + 1;
4449 4542 converted_onm = nfscmd_convname(ca, cs->exi, onm, NFSCMD_CONV_INBOUND,
4450 4543 nlen);
4451 4544
4452 4545 if (converted_onm == NULL) {
4453 4546 *cs->statusp = resp->status = NFS4ERR_INVAL;
4454 4547 kmem_free(onm, olen);
4455 4548 goto out;
4456 4549 }
4457 4550
4458 4551 nnm = utf8_to_fn(&args->newname, &nlen, NULL);
4459 4552 if (nnm == NULL) {
4460 4553 *cs->statusp = resp->status = NFS4ERR_INVAL;
4461 4554 if (onm != converted_onm)
4462 4555 kmem_free(converted_onm, MAXPATHLEN + 1);
4463 4556 kmem_free(onm, olen);
4464 4557 goto out;
4465 4558 }
4466 4559 converted_nnm = nfscmd_convname(ca, cs->exi, nnm, NFSCMD_CONV_INBOUND,
4467 4560 MAXPATHLEN + 1);
4468 4561
4469 4562 if (converted_nnm == NULL) {
4470 4563 *cs->statusp = resp->status = NFS4ERR_INVAL;
4471 4564 kmem_free(nnm, nlen);
4472 4565 nnm = NULL;
4473 4566 if (onm != converted_onm)
4474 4567 kmem_free(converted_onm, MAXPATHLEN + 1);
4475 4568 kmem_free(onm, olen);
4476 4569 goto out;
4477 4570 }
4478 4571
4479 4572
4480 4573 if (olen > MAXNAMELEN || nlen > MAXNAMELEN) {
4481 4574 *cs->statusp = resp->status = NFS4ERR_NAMETOOLONG;
4482 4575 kmem_free(onm, olen);
4483 4576 kmem_free(nnm, nlen);
4484 4577 goto out;
4485 4578 }
4486 4579
4487 4580
4488 4581 if (rdonly4(req, cs)) {
4489 4582 *cs->statusp = resp->status = NFS4ERR_ROFS;
4490 4583 if (onm != converted_onm)
4491 4584 kmem_free(converted_onm, MAXPATHLEN + 1);
4492 4585 kmem_free(onm, olen);
4493 4586 if (nnm != converted_nnm)
4494 4587 kmem_free(converted_nnm, MAXPATHLEN + 1);
4495 4588 kmem_free(nnm, nlen);
4496 4589 goto out;
4497 4590 }
4498 4591
4499 4592 /* check label of the target dir */
4500 4593 if (is_system_labeled()) {
4501 4594 ASSERT(req->rq_label != NULL);
4502 4595 clabel = req->rq_label;
4503 4596 DTRACE_PROBE2(tx__rfs4__log__info__oprename__clabel, char *,
4504 4597 "got client label from request(1)",
4505 4598 struct svc_req *, req);
4506 4599 if (!blequal(&l_admin_low->tsl_label, clabel)) {
4507 4600 if (!do_rfs_label_check(clabel, ndvp,
4508 4601 EQUALITY_CHECK, cs->exi)) {
4509 4602 *cs->statusp = resp->status = NFS4ERR_ACCESS;
4510 4603 goto err_out;
4511 4604 }
4512 4605 }
4513 4606 }
4514 4607
4515 4608 /*
4516 4609 * Is the source a file and have a delegation?
4517 4610 * We don't need to acquire va_seq before these lookups, if
4518 4611 * it causes an update, cinfo.before will not match, which will
4519 4612 * trigger a cache flush even if atomic is TRUE.
4520 4613 */
4521 4614 if (sfp = rfs4_lookup_and_findfile(odvp, converted_onm, &srcvp,
4522 4615 &error, cs->cr)) {
4523 4616 if (rfs4_check_delegated_byfp(FWRITE, sfp, TRUE, TRUE, TRUE,
4524 4617 NULL)) {
4525 4618 *cs->statusp = resp->status = NFS4ERR_DELAY;
4526 4619 goto err_out;
4527 4620 }
4528 4621 }
4529 4622
4530 4623 if (srcvp == NULL) {
4531 4624 *cs->statusp = resp->status = puterrno4(error);
4532 4625 if (onm != converted_onm)
4533 4626 kmem_free(converted_onm, MAXPATHLEN + 1);
4534 4627 kmem_free(onm, olen);
4535 4628 if (nnm != converted_nnm)
4536 4629 kmem_free(converted_nnm, MAXPATHLEN + 1);
4537 4630 kmem_free(nnm, nlen);
4538 4631 goto out;
4539 4632 }
4540 4633
4541 4634 sfp_rele_grant_hold = 1;
4542 4635
4543 4636 /* Does the destination exist and a file and have a delegation? */
|
↓ open down ↓ |
152 lines elided |
↑ open up ↑ |
4544 4637 if (fp = rfs4_lookup_and_findfile(ndvp, converted_nnm, &targvp,
4545 4638 NULL, cs->cr)) {
4546 4639 if (rfs4_check_delegated_byfp(FWRITE, fp, TRUE, TRUE, TRUE,
4547 4640 NULL)) {
4548 4641 *cs->statusp = resp->status = NFS4ERR_DELAY;
4549 4642 goto err_out;
4550 4643 }
4551 4644 }
4552 4645 fp_rele_grant_hold = 1;
4553 4646
4554 -
4555 4647 /* Check for NBMAND lock on both source and target */
4556 4648 if (nbl_need_check(srcvp)) {
4557 4649 nbl_start_crit(srcvp, RW_READER);
4558 4650 in_crit_src = 1;
4559 4651 if (nbl_conflict(srcvp, NBL_RENAME, 0, 0, 0, NULL)) {
4560 4652 *cs->statusp = resp->status = NFS4ERR_FILE_OPEN;
4561 4653 goto err_out;
4562 4654 }
4563 4655 }
4564 4656
4565 4657 if (targvp && nbl_need_check(targvp)) {
4566 4658 nbl_start_crit(targvp, RW_READER);
4567 4659 in_crit_targ = 1;
4568 4660 if (nbl_conflict(targvp, NBL_REMOVE, 0, 0, 0, NULL)) {
4569 4661 *cs->statusp = resp->status = NFS4ERR_FILE_OPEN;
4570 4662 goto err_out;
4571 4663 }
4572 4664 }
4573 4665
4574 4666 /* Get source "before" change value */
4575 4667 obdva.va_mask = AT_CTIME|AT_SEQ;
4576 4668 error = VOP_GETATTR(odvp, &obdva, 0, cs->cr, NULL);
4577 4669 if (!error) {
4578 4670 nbdva.va_mask = AT_CTIME|AT_SEQ;
|
↓ open down ↓ |
14 lines elided |
↑ open up ↑ |
4579 4671 error = VOP_GETATTR(ndvp, &nbdva, 0, cs->cr, NULL);
4580 4672 }
4581 4673 if (error) {
4582 4674 *cs->statusp = resp->status = puterrno4(error);
4583 4675 goto err_out;
4584 4676 }
4585 4677
4586 4678 NFS4_SET_FATTR4_CHANGE(resp->source_cinfo.before, obdva.va_ctime)
4587 4679 NFS4_SET_FATTR4_CHANGE(resp->target_cinfo.before, nbdva.va_ctime)
4588 4680
4589 - if ((error = VOP_RENAME(odvp, converted_onm, ndvp, converted_nnm,
4590 - cs->cr, NULL, 0)) == 0 && fp != NULL) {
4591 - struct vattr va;
4592 - vnode_t *tvp;
4681 + error = VOP_RENAME(odvp, converted_onm, ndvp, converted_nnm, cs->cr,
4682 + NULL, 0);
4593 4683
4684 + /*
4685 + * If target existed and was unlinked by VOP_RENAME, state will need
4686 + * closed. To avoid deadlock, rfs4_close_all_state will be done after
4687 + * any necessary nbl_end_crit on srcvp and tgtvp.
4688 + */
4689 + if (error == 0 && fp != NULL) {
4594 4690 rfs4_dbe_lock(fp->rf_dbe);
4595 4691 tvp = fp->rf_vp;
4596 4692 if (tvp)
4597 4693 VN_HOLD(tvp);
4598 4694 rfs4_dbe_unlock(fp->rf_dbe);
4599 4695
4600 4696 if (tvp) {
4697 + struct vattr va;
4601 4698 va.va_mask = AT_NLINK;
4699 +
4602 4700 if (!VOP_GETATTR(tvp, &va, 0, cs->cr, NULL) &&
4603 4701 va.va_nlink == 0) {
4604 - /* The file is gone and so should the state */
4605 - if (in_crit_targ) {
4606 - nbl_end_crit(targvp);
4607 - in_crit_targ = 0;
4702 + unlinked = 1;
4703 +
4704 + /* DEBUG data */
4705 + if ((srcvp == targvp) || (tvp != targvp)) {
4706 + cmn_err(CE_WARN, "rfs4_op_rename: "
4707 + "srcvp %p, targvp: %p, tvp: %p",
4708 + (void *)srcvp, (void *)targvp,
4709 + (void *)tvp);
4608 4710 }
4609 - rfs4_close_all_state(fp);
4711 + } else {
4712 + VN_RELE(tvp);
4610 4713 }
4611 - VN_RELE(tvp);
4612 4714 }
4613 4715 }
4614 4716 if (error == 0)
4615 4717 vn_renamepath(ndvp, srcvp, nnm, nlen - 1);
4616 4718
4617 4719 if (in_crit_src)
4618 4720 nbl_end_crit(srcvp);
4619 4721 if (srcvp)
4620 4722 VN_RELE(srcvp);
4621 4723 if (in_crit_targ)
4622 4724 nbl_end_crit(targvp);
4623 4725 if (targvp)
4624 4726 VN_RELE(targvp);
4625 4727
4728 + if (unlinked) {
4729 + ASSERT(fp != NULL);
4730 + ASSERT(tvp != NULL);
4731 +
4732 + /* DEBUG data */
4733 + if (RW_READ_HELD(&tvp->v_nbllock)) {
4734 + cmn_err(CE_WARN, "rfs4_op_rename: "
4735 + "RW_READ_HELD(%p)", (void *)tvp);
4736 + }
4737 +
4738 + /* The file is gone and so should the state */
4739 + rfs4_close_all_state(fp);
4740 + VN_RELE(tvp);
4741 + }
4742 +
4626 4743 if (sfp) {
4627 4744 rfs4_clear_dont_grant(sfp);
4628 4745 rfs4_file_rele(sfp);
4629 4746 }
4630 4747 if (fp) {
4631 4748 rfs4_clear_dont_grant(fp);
4632 4749 rfs4_file_rele(fp);
4633 4750 }
4634 4751
4635 4752 if (converted_onm != onm)
4636 4753 kmem_free(converted_onm, MAXPATHLEN + 1);
4637 4754 kmem_free(onm, olen);
4638 4755 if (converted_nnm != nnm)
4639 4756 kmem_free(converted_nnm, MAXPATHLEN + 1);
4640 4757 kmem_free(nnm, nlen);
4641 4758
4642 4759 /*
4643 4760 * Get the initial "after" sequence number, if it fails, set to zero
4644 4761 */
4645 4762 oidva.va_mask = AT_SEQ;
4646 4763 if (VOP_GETATTR(odvp, &oidva, 0, cs->cr, NULL))
4647 4764 oidva.va_seq = 0;
4648 4765
4649 4766 nidva.va_mask = AT_SEQ;
4650 4767 if (VOP_GETATTR(ndvp, &nidva, 0, cs->cr, NULL))
4651 4768 nidva.va_seq = 0;
4652 4769
4653 4770 /*
4654 4771 * Force modified data and metadata out to stable storage.
4655 4772 */
4656 4773 (void) VOP_FSYNC(odvp, 0, cs->cr, NULL);
4657 4774 (void) VOP_FSYNC(ndvp, 0, cs->cr, NULL);
4658 4775
4659 4776 if (error) {
4660 4777 *cs->statusp = resp->status = puterrno4(error);
4661 4778 goto out;
4662 4779 }
4663 4780
4664 4781 /*
4665 4782 * Get "after" change values, if it fails, simply return the
4666 4783 * before value.
4667 4784 */
4668 4785 oadva.va_mask = AT_CTIME|AT_SEQ;
4669 4786 if (VOP_GETATTR(odvp, &oadva, 0, cs->cr, NULL)) {
4670 4787 oadva.va_ctime = obdva.va_ctime;
4671 4788 oadva.va_seq = 0;
4672 4789 }
4673 4790
4674 4791 nadva.va_mask = AT_CTIME|AT_SEQ;
4675 4792 if (VOP_GETATTR(odvp, &nadva, 0, cs->cr, NULL)) {
4676 4793 nadva.va_ctime = nbdva.va_ctime;
4677 4794 nadva.va_seq = 0;
4678 4795 }
4679 4796
4680 4797 NFS4_SET_FATTR4_CHANGE(resp->source_cinfo.after, oadva.va_ctime)
4681 4798 NFS4_SET_FATTR4_CHANGE(resp->target_cinfo.after, nadva.va_ctime)
4682 4799
4683 4800 /*
4684 4801 * The cinfo.atomic = TRUE only if we have
4685 4802 * non-zero va_seq's, and it has incremented by exactly one
4686 4803 * during the VOP_RENAME and it didn't change during the VOP_FSYNC.
4687 4804 */
4688 4805 if (obdva.va_seq && oidva.va_seq && oadva.va_seq &&
4689 4806 oidva.va_seq == (obdva.va_seq + 1) && oidva.va_seq == oadva.va_seq)
4690 4807 resp->source_cinfo.atomic = TRUE;
4691 4808 else
4692 4809 resp->source_cinfo.atomic = FALSE;
4693 4810
4694 4811 if (nbdva.va_seq && nidva.va_seq && nadva.va_seq &&
4695 4812 nidva.va_seq == (nbdva.va_seq + 1) && nidva.va_seq == nadva.va_seq)
4696 4813 resp->target_cinfo.atomic = TRUE;
4697 4814 else
4698 4815 resp->target_cinfo.atomic = FALSE;
4699 4816
4700 4817 #ifdef VOLATILE_FH_TEST
4701 4818 {
4702 4819 extern void add_volrnm_fh(struct exportinfo *, vnode_t *);
4703 4820
4704 4821 /*
4705 4822 * Add the renamed file handle to the volatile rename list
4706 4823 */
4707 4824 if (cs->exi->exi_export.ex_flags & EX_VOLRNM) {
4708 4825 /* file handles may expire on rename */
4709 4826 vnode_t *vp;
4710 4827
4711 4828 nnm = utf8_to_fn(&args->newname, &nlen, NULL);
4712 4829 /*
4713 4830 * Already know that nnm will be a valid string
4714 4831 */
4715 4832 error = VOP_LOOKUP(ndvp, nnm, &vp, NULL, 0, NULL, cs->cr,
4716 4833 NULL, NULL, NULL);
4717 4834 kmem_free(nnm, nlen);
4718 4835 if (!error) {
4719 4836 add_volrnm_fh(cs->exi, vp);
4720 4837 VN_RELE(vp);
4721 4838 }
4722 4839 }
4723 4840 }
4724 4841 #endif /* VOLATILE_FH_TEST */
4725 4842
4726 4843 *cs->statusp = resp->status = NFS4_OK;
4727 4844 out:
4728 4845 DTRACE_NFSV4_2(op__rename__done, struct compound_state *, cs,
4729 4846 RENAME4res *, resp);
4730 4847 return;
4731 4848
4732 4849 err_out:
4733 4850 if (onm != converted_onm)
4734 4851 kmem_free(converted_onm, MAXPATHLEN + 1);
4735 4852 if (onm != NULL)
4736 4853 kmem_free(onm, olen);
4737 4854 if (nnm != converted_nnm)
4738 4855 kmem_free(converted_nnm, MAXPATHLEN + 1);
4739 4856 if (nnm != NULL)
4740 4857 kmem_free(nnm, nlen);
4741 4858
4742 4859 if (in_crit_src) nbl_end_crit(srcvp);
4743 4860 if (in_crit_targ) nbl_end_crit(targvp);
4744 4861 if (targvp) VN_RELE(targvp);
4745 4862 if (srcvp) VN_RELE(srcvp);
4746 4863 if (sfp) {
4747 4864 if (sfp_rele_grant_hold) rfs4_clear_dont_grant(sfp);
4748 4865 rfs4_file_rele(sfp);
4749 4866 }
4750 4867 if (fp) {
4751 4868 if (fp_rele_grant_hold) rfs4_clear_dont_grant(fp);
4752 4869 rfs4_file_rele(fp);
4753 4870 }
4754 4871
4755 4872 DTRACE_NFSV4_2(op__rename__done, struct compound_state *, cs,
4756 4873 RENAME4res *, resp);
4757 4874 }
4758 4875
4759 4876 /* ARGSUSED */
4760 4877 static void
4761 4878 rfs4_op_renew(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
4762 4879 struct compound_state *cs)
4763 4880 {
4764 4881 RENEW4args *args = &argop->nfs_argop4_u.oprenew;
4765 4882 RENEW4res *resp = &resop->nfs_resop4_u.oprenew;
4766 4883 rfs4_client_t *cp;
4767 4884
4768 4885 DTRACE_NFSV4_2(op__renew__start, struct compound_state *, cs,
4769 4886 RENEW4args *, args);
4770 4887
4771 4888 if ((cp = rfs4_findclient_by_id(args->clientid, FALSE)) == NULL) {
4772 4889 *cs->statusp = resp->status =
4773 4890 rfs4_check_clientid(&args->clientid, 0);
4774 4891 goto out;
4775 4892 }
4776 4893
4777 4894 if (rfs4_lease_expired(cp)) {
4778 4895 rfs4_client_rele(cp);
4779 4896 *cs->statusp = resp->status = NFS4ERR_EXPIRED;
4780 4897 goto out;
4781 4898 }
4782 4899
4783 4900 rfs4_update_lease(cp);
4784 4901
4785 4902 mutex_enter(cp->rc_cbinfo.cb_lock);
4786 4903 if (cp->rc_cbinfo.cb_notified_of_cb_path_down == FALSE) {
4787 4904 cp->rc_cbinfo.cb_notified_of_cb_path_down = TRUE;
4788 4905 *cs->statusp = resp->status = NFS4ERR_CB_PATH_DOWN;
4789 4906 } else {
4790 4907 *cs->statusp = resp->status = NFS4_OK;
4791 4908 }
4792 4909 mutex_exit(cp->rc_cbinfo.cb_lock);
4793 4910
4794 4911 rfs4_client_rele(cp);
4795 4912
4796 4913 out:
4797 4914 DTRACE_NFSV4_2(op__renew__done, struct compound_state *, cs,
4798 4915 RENEW4res *, resp);
4799 4916 }
4800 4917
4801 4918 /* ARGSUSED */
4802 4919 static void
4803 4920 rfs4_op_restorefh(nfs_argop4 *args, nfs_resop4 *resop, struct svc_req *req,
4804 4921 struct compound_state *cs)
4805 4922 {
4806 4923 RESTOREFH4res *resp = &resop->nfs_resop4_u.oprestorefh;
4807 4924
4808 4925 DTRACE_NFSV4_1(op__restorefh__start, struct compound_state *, cs);
4809 4926
4810 4927 /* No need to check cs->access - we are not accessing any object */
4811 4928 if ((cs->saved_vp == NULL) || (cs->saved_fh.nfs_fh4_val == NULL)) {
4812 4929 *cs->statusp = resp->status = NFS4ERR_RESTOREFH;
4813 4930 goto out;
4814 4931 }
4815 4932 if (cs->vp != NULL) {
4816 4933 VN_RELE(cs->vp);
4817 4934 }
4818 4935 cs->vp = cs->saved_vp;
4819 4936 cs->saved_vp = NULL;
4820 4937 cs->exi = cs->saved_exi;
4821 4938 nfs_fh4_copy(&cs->saved_fh, &cs->fh);
4822 4939 *cs->statusp = resp->status = NFS4_OK;
4823 4940 cs->deleg = FALSE;
4824 4941
4825 4942 out:
4826 4943 DTRACE_NFSV4_2(op__restorefh__done, struct compound_state *, cs,
4827 4944 RESTOREFH4res *, resp);
4828 4945 }
4829 4946
4830 4947 /* ARGSUSED */
4831 4948 static void
4832 4949 rfs4_op_savefh(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
4833 4950 struct compound_state *cs)
4834 4951 {
4835 4952 SAVEFH4res *resp = &resop->nfs_resop4_u.opsavefh;
4836 4953
4837 4954 DTRACE_NFSV4_1(op__savefh__start, struct compound_state *, cs);
4838 4955
4839 4956 /* No need to check cs->access - we are not accessing any object */
4840 4957 if (cs->vp == NULL) {
4841 4958 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
4842 4959 goto out;
4843 4960 }
4844 4961 if (cs->saved_vp != NULL) {
4845 4962 VN_RELE(cs->saved_vp);
4846 4963 }
4847 4964 cs->saved_vp = cs->vp;
4848 4965 VN_HOLD(cs->saved_vp);
4849 4966 cs->saved_exi = cs->exi;
4850 4967 /*
4851 4968 * since SAVEFH is fairly rare, don't alloc space for its fh
4852 4969 * unless necessary.
4853 4970 */
4854 4971 if (cs->saved_fh.nfs_fh4_val == NULL) {
4855 4972 cs->saved_fh.nfs_fh4_val = kmem_alloc(NFS4_FHSIZE, KM_SLEEP);
4856 4973 }
4857 4974 nfs_fh4_copy(&cs->fh, &cs->saved_fh);
4858 4975 *cs->statusp = resp->status = NFS4_OK;
4859 4976
4860 4977 out:
4861 4978 DTRACE_NFSV4_2(op__savefh__done, struct compound_state *, cs,
4862 4979 SAVEFH4res *, resp);
4863 4980 }
4864 4981
4865 4982 /*
4866 4983 * rfs4_verify_attr is called when nfsv4 Setattr failed, but we wish to
4867 4984 * return the bitmap of attrs that were set successfully. It is also
4868 4985 * called by Verify/Nverify to test the vattr/vfsstat attrs. It should
4869 4986 * always be called only after rfs4_do_set_attrs().
4870 4987 *
4871 4988 * Verify that the attributes are same as the expected ones. sargp->vap
4872 4989 * and sargp->sbp contain the input attributes as translated from fattr4.
4873 4990 *
4874 4991 * This function verifies only the attrs that correspond to a vattr or
4875 4992 * vfsstat struct. That is because of the extra step needed to get the
4876 4993 * corresponding system structs. Other attributes have already been set or
4877 4994 * verified by do_rfs4_set_attrs.
4878 4995 *
4879 4996 * Return 0 if all attrs match, -1 if some don't, error if error processing.
4880 4997 */
4881 4998 static int
4882 4999 rfs4_verify_attr(struct nfs4_svgetit_arg *sargp,
4883 5000 bitmap4 *resp, struct nfs4_ntov_table *ntovp)
4884 5001 {
4885 5002 int error, ret_error = 0;
4886 5003 int i, k;
4887 5004 uint_t sva_mask = sargp->vap->va_mask;
4888 5005 uint_t vbit;
4889 5006 union nfs4_attr_u *na;
4890 5007 uint8_t *amap;
4891 5008 bool_t getsb = ntovp->vfsstat;
4892 5009
4893 5010 if (sva_mask != 0) {
4894 5011 /*
4895 5012 * Okay to overwrite sargp->vap because we verify based
4896 5013 * on the incoming values.
4897 5014 */
4898 5015 ret_error = VOP_GETATTR(sargp->cs->vp, sargp->vap, 0,
4899 5016 sargp->cs->cr, NULL);
4900 5017 if (ret_error) {
4901 5018 if (resp == NULL)
4902 5019 return (ret_error);
4903 5020 /*
4904 5021 * Must return bitmap of successful attrs
4905 5022 */
4906 5023 sva_mask = 0; /* to prevent checking vap later */
4907 5024 } else {
4908 5025 /*
4909 5026 * Some file systems clobber va_mask. it is probably
4910 5027 * wrong of them to do so, nonethless we practice
4911 5028 * defensive coding.
4912 5029 * See bug id 4276830.
4913 5030 */
4914 5031 sargp->vap->va_mask = sva_mask;
4915 5032 }
4916 5033 }
4917 5034
4918 5035 if (getsb) {
4919 5036 /*
4920 5037 * Now get the superblock and loop on the bitmap, as there is
4921 5038 * no simple way of translating from superblock to bitmap4.
4922 5039 */
4923 5040 ret_error = VFS_STATVFS(sargp->cs->vp->v_vfsp, sargp->sbp);
4924 5041 if (ret_error) {
4925 5042 if (resp == NULL)
4926 5043 goto errout;
4927 5044 getsb = FALSE;
4928 5045 }
4929 5046 }
4930 5047
4931 5048 /*
4932 5049 * Now loop and verify each attribute which getattr returned
4933 5050 * whether it's the same as the input.
4934 5051 */
4935 5052 if (resp == NULL && !getsb && (sva_mask == 0))
4936 5053 goto errout;
4937 5054
4938 5055 na = ntovp->na;
4939 5056 amap = ntovp->amap;
4940 5057 k = 0;
4941 5058 for (i = 0; i < ntovp->attrcnt; i++, na++, amap++) {
4942 5059 k = *amap;
4943 5060 ASSERT(nfs4_ntov_map[k].nval == k);
4944 5061 vbit = nfs4_ntov_map[k].vbit;
4945 5062
4946 5063 /*
4947 5064 * If vattr attribute but VOP_GETATTR failed, or it's
4948 5065 * superblock attribute but VFS_STATVFS failed, skip
4949 5066 */
4950 5067 if (vbit) {
4951 5068 if ((vbit & sva_mask) == 0)
4952 5069 continue;
4953 5070 } else if (!(getsb && nfs4_ntov_map[k].vfsstat)) {
4954 5071 continue;
4955 5072 }
4956 5073 error = (*nfs4_ntov_map[k].sv_getit)(NFS4ATTR_VERIT, sargp, na);
4957 5074 if (resp != NULL) {
4958 5075 if (error)
4959 5076 ret_error = -1; /* not all match */
4960 5077 else /* update response bitmap */
4961 5078 *resp |= nfs4_ntov_map[k].fbit;
4962 5079 continue;
4963 5080 }
4964 5081 if (error) {
4965 5082 ret_error = -1; /* not all match */
4966 5083 break;
4967 5084 }
4968 5085 }
4969 5086 errout:
4970 5087 return (ret_error);
4971 5088 }
4972 5089
4973 5090 /*
4974 5091 * Decode the attribute to be set/verified. If the attr requires a sys op
4975 5092 * (VOP_GETATTR, VFS_VFSSTAT), and the request is to verify, then don't
4976 5093 * call the sv_getit function for it, because the sys op hasn't yet been done.
4977 5094 * Return 0 for success, error code if failed.
4978 5095 *
4979 5096 * Note: the decoded arg is not freed here but in nfs4_ntov_table_free.
4980 5097 */
4981 5098 static int
4982 5099 decode_fattr4_attr(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sargp,
4983 5100 int k, XDR *xdrp, bitmap4 *resp_bval, union nfs4_attr_u *nap)
4984 5101 {
4985 5102 int error = 0;
4986 5103 bool_t set_later;
4987 5104
4988 5105 sargp->vap->va_mask |= nfs4_ntov_map[k].vbit;
4989 5106
4990 5107 if ((*nfs4_ntov_map[k].xfunc)(xdrp, nap)) {
4991 5108 set_later = nfs4_ntov_map[k].vbit || nfs4_ntov_map[k].vfsstat;
4992 5109 /*
4993 5110 * don't verify yet if a vattr or sb dependent attr,
4994 5111 * because we don't have their sys values yet.
4995 5112 * Will be done later.
4996 5113 */
4997 5114 if (! (set_later && (cmd == NFS4ATTR_VERIT))) {
4998 5115 /*
4999 5116 * ACLs are a special case, since setting the MODE
5000 5117 * conflicts with setting the ACL. We delay setting
5001 5118 * the ACL until all other attributes have been set.
5002 5119 * The ACL gets set in do_rfs4_op_setattr().
5003 5120 */
5004 5121 if (nfs4_ntov_map[k].fbit != FATTR4_ACL_MASK) {
5005 5122 error = (*nfs4_ntov_map[k].sv_getit)(cmd,
5006 5123 sargp, nap);
5007 5124 if (error) {
5008 5125 xdr_free(nfs4_ntov_map[k].xfunc,
5009 5126 (caddr_t)nap);
5010 5127 }
5011 5128 }
5012 5129 }
5013 5130 } else {
5014 5131 #ifdef DEBUG
5015 5132 cmn_err(CE_NOTE, "decode_fattr4_attr: error "
5016 5133 "decoding attribute %d\n", k);
5017 5134 #endif
5018 5135 error = EINVAL;
5019 5136 }
5020 5137 if (!error && resp_bval && !set_later) {
5021 5138 *resp_bval |= nfs4_ntov_map[k].fbit;
5022 5139 }
5023 5140
5024 5141 return (error);
5025 5142 }
5026 5143
5027 5144 /*
5028 5145 * Set vattr based on incoming fattr4 attrs - used by setattr.
5029 5146 * Set response mask. Ignore any values that are not writable vattr attrs.
5030 5147 */
5031 5148 static nfsstat4
5032 5149 do_rfs4_set_attrs(bitmap4 *resp, fattr4 *fattrp, struct compound_state *cs,
5033 5150 struct nfs4_svgetit_arg *sargp, struct nfs4_ntov_table *ntovp,
5034 5151 nfs4_attr_cmd_t cmd)
5035 5152 {
5036 5153 int error = 0;
5037 5154 int i;
5038 5155 char *attrs = fattrp->attrlist4;
5039 5156 uint32_t attrslen = fattrp->attrlist4_len;
5040 5157 XDR xdr;
5041 5158 nfsstat4 status = NFS4_OK;
5042 5159 vnode_t *vp = cs->vp;
5043 5160 union nfs4_attr_u *na;
5044 5161 uint8_t *amap;
5045 5162
5046 5163 #ifndef lint
5047 5164 /*
5048 5165 * Make sure that maximum attribute number can be expressed as an
5049 5166 * 8 bit quantity.
5050 5167 */
5051 5168 ASSERT(NFS4_MAXNUM_ATTRS <= (UINT8_MAX + 1));
5052 5169 #endif
5053 5170
5054 5171 if (vp == NULL) {
5055 5172 if (resp)
5056 5173 *resp = 0;
5057 5174 return (NFS4ERR_NOFILEHANDLE);
5058 5175 }
5059 5176 if (cs->access == CS_ACCESS_DENIED) {
5060 5177 if (resp)
5061 5178 *resp = 0;
5062 5179 return (NFS4ERR_ACCESS);
5063 5180 }
5064 5181
5065 5182 sargp->op = cmd;
5066 5183 sargp->cs = cs;
5067 5184 sargp->flag = 0; /* may be set later */
5068 5185 sargp->vap->va_mask = 0;
5069 5186 sargp->rdattr_error = NFS4_OK;
5070 5187 sargp->rdattr_error_req = FALSE;
5071 5188 /* sargp->sbp is set by the caller */
5072 5189
5073 5190 xdrmem_create(&xdr, attrs, attrslen, XDR_DECODE);
5074 5191
5075 5192 na = ntovp->na;
5076 5193 amap = ntovp->amap;
5077 5194
5078 5195 /*
5079 5196 * The following loop iterates on the nfs4_ntov_map checking
5080 5197 * if the fbit is set in the requested bitmap.
5081 5198 * If set then we process the arguments using the
5082 5199 * rfs4_fattr4 conversion functions to populate the setattr
5083 5200 * vattr and va_mask. Any settable attrs that are not using vattr
5084 5201 * will be set in this loop.
5085 5202 */
5086 5203 for (i = 0; i < nfs4_ntov_map_size; i++) {
5087 5204 if (!(fattrp->attrmask & nfs4_ntov_map[i].fbit)) {
5088 5205 continue;
5089 5206 }
5090 5207 /*
5091 5208 * If setattr, must be a writable attr.
5092 5209 * If verify/nverify, must be a readable attr.
5093 5210 */
5094 5211 if ((error = (*nfs4_ntov_map[i].sv_getit)(
5095 5212 NFS4ATTR_SUPPORTED, sargp, NULL)) != 0) {
5096 5213 /*
5097 5214 * Client tries to set/verify an
5098 5215 * unsupported attribute, tries to set
5099 5216 * a read only attr or verify a write
5100 5217 * only one - error!
5101 5218 */
5102 5219 break;
5103 5220 }
5104 5221 /*
5105 5222 * Decode the attribute to set/verify
5106 5223 */
5107 5224 error = decode_fattr4_attr(cmd, sargp, nfs4_ntov_map[i].nval,
5108 5225 &xdr, resp ? resp : NULL, na);
5109 5226 if (error)
5110 5227 break;
5111 5228 *amap++ = (uint8_t)nfs4_ntov_map[i].nval;
5112 5229 na++;
5113 5230 (ntovp->attrcnt)++;
5114 5231 if (nfs4_ntov_map[i].vfsstat)
5115 5232 ntovp->vfsstat = TRUE;
5116 5233 }
5117 5234
5118 5235 if (error != 0)
5119 5236 status = (error == ENOTSUP ? NFS4ERR_ATTRNOTSUPP :
5120 5237 puterrno4(error));
5121 5238 /* xdrmem_destroy(&xdrs); */ /* NO-OP */
5122 5239 return (status);
5123 5240 }
5124 5241
5125 5242 static nfsstat4
5126 5243 do_rfs4_op_setattr(bitmap4 *resp, fattr4 *fattrp, struct compound_state *cs,
5127 5244 stateid4 *stateid)
5128 5245 {
5129 5246 int error = 0;
5130 5247 struct nfs4_svgetit_arg sarg;
5131 5248 bool_t trunc;
5132 5249
5133 5250 nfsstat4 status = NFS4_OK;
5134 5251 cred_t *cr = cs->cr;
5135 5252 vnode_t *vp = cs->vp;
5136 5253 struct nfs4_ntov_table ntov;
5137 5254 struct statvfs64 sb;
5138 5255 struct vattr bva;
5139 5256 struct flock64 bf;
5140 5257 int in_crit = 0;
5141 5258 uint_t saved_mask = 0;
5142 5259 caller_context_t ct;
5143 5260
5144 5261 *resp = 0;
5145 5262 sarg.sbp = &sb;
5146 5263 sarg.is_referral = B_FALSE;
5147 5264 nfs4_ntov_table_init(&ntov);
5148 5265 status = do_rfs4_set_attrs(resp, fattrp, cs, &sarg, &ntov,
5149 5266 NFS4ATTR_SETIT);
5150 5267 if (status != NFS4_OK) {
5151 5268 /*
5152 5269 * failed set attrs
5153 5270 */
5154 5271 goto done;
5155 5272 }
5156 5273 if ((sarg.vap->va_mask == 0) &&
5157 5274 (! (fattrp->attrmask & FATTR4_ACL_MASK))) {
5158 5275 /*
5159 5276 * no further work to be done
5160 5277 */
5161 5278 goto done;
5162 5279 }
5163 5280
5164 5281 /*
5165 5282 * If we got a request to set the ACL and the MODE, only
5166 5283 * allow changing VSUID, VSGID, and VSVTX. Attempting
5167 5284 * to change any other bits, along with setting an ACL,
5168 5285 * gives NFS4ERR_INVAL.
5169 5286 */
5170 5287 if ((fattrp->attrmask & FATTR4_ACL_MASK) &&
5171 5288 (fattrp->attrmask & FATTR4_MODE_MASK)) {
5172 5289 vattr_t va;
5173 5290
5174 5291 va.va_mask = AT_MODE;
5175 5292 error = VOP_GETATTR(vp, &va, 0, cs->cr, NULL);
5176 5293 if (error) {
5177 5294 status = puterrno4(error);
5178 5295 goto done;
5179 5296 }
5180 5297 if ((sarg.vap->va_mode ^ va.va_mode) &
5181 5298 ~(VSUID | VSGID | VSVTX)) {
5182 5299 status = NFS4ERR_INVAL;
5183 5300 goto done;
5184 5301 }
5185 5302 }
5186 5303
5187 5304 /* Check stateid only if size has been set */
5188 5305 if (sarg.vap->va_mask & AT_SIZE) {
5189 5306 trunc = (sarg.vap->va_size == 0);
5190 5307 status = rfs4_check_stateid(FWRITE, cs->vp, stateid,
5191 5308 trunc, &cs->deleg, sarg.vap->va_mask & AT_SIZE, &ct);
5192 5309 if (status != NFS4_OK)
5193 5310 goto done;
5194 5311 } else {
5195 5312 ct.cc_sysid = 0;
5196 5313 ct.cc_pid = 0;
5197 5314 ct.cc_caller_id = nfs4_srv_caller_id;
5198 5315 ct.cc_flags = CC_DONTBLOCK;
5199 5316 }
5200 5317
5201 5318 /* XXX start of possible race with delegations */
5202 5319
5203 5320 /*
5204 5321 * We need to specially handle size changes because it is
5205 5322 * possible for the client to create a file with read-only
5206 5323 * modes, but with the file opened for writing. If the client
5207 5324 * then tries to set the file size, e.g. ftruncate(3C),
5208 5325 * fcntl(F_FREESP), the normal access checking done in
5209 5326 * VOP_SETATTR would prevent the client from doing it even though
5210 5327 * it should be allowed to do so. To get around this, we do the
5211 5328 * access checking for ourselves and use VOP_SPACE which doesn't
5212 5329 * do the access checking.
5213 5330 * Also the client should not be allowed to change the file
5214 5331 * size if there is a conflicting non-blocking mandatory lock in
5215 5332 * the region of the change.
5216 5333 */
5217 5334 if (vp->v_type == VREG && (sarg.vap->va_mask & AT_SIZE)) {
5218 5335 u_offset_t offset;
5219 5336 ssize_t length;
5220 5337
5221 5338 /*
5222 5339 * ufs_setattr clears AT_SIZE from vap->va_mask, but
5223 5340 * before returning, sarg.vap->va_mask is used to
5224 5341 * generate the setattr reply bitmap. We also clear
5225 5342 * AT_SIZE below before calling VOP_SPACE. For both
5226 5343 * of these cases, the va_mask needs to be saved here
5227 5344 * and restored after calling VOP_SETATTR.
5228 5345 */
5229 5346 saved_mask = sarg.vap->va_mask;
5230 5347
5231 5348 /*
5232 5349 * Check any possible conflict due to NBMAND locks.
5233 5350 * Get into critical region before VOP_GETATTR, so the
5234 5351 * size attribute is valid when checking conflicts.
5235 5352 */
5236 5353 if (nbl_need_check(vp)) {
5237 5354 nbl_start_crit(vp, RW_READER);
5238 5355 in_crit = 1;
5239 5356 }
5240 5357
5241 5358 bva.va_mask = AT_UID|AT_SIZE;
5242 5359 if (error = VOP_GETATTR(vp, &bva, 0, cr, &ct)) {
5243 5360 status = puterrno4(error);
5244 5361 goto done;
5245 5362 }
5246 5363
5247 5364 if (in_crit) {
5248 5365 if (sarg.vap->va_size < bva.va_size) {
5249 5366 offset = sarg.vap->va_size;
5250 5367 length = bva.va_size - sarg.vap->va_size;
5251 5368 } else {
5252 5369 offset = bva.va_size;
5253 5370 length = sarg.vap->va_size - bva.va_size;
5254 5371 }
5255 5372 if (nbl_conflict(vp, NBL_WRITE, offset, length, 0,
5256 5373 &ct)) {
5257 5374 status = NFS4ERR_LOCKED;
5258 5375 goto done;
5259 5376 }
5260 5377 }
5261 5378
5262 5379 if (crgetuid(cr) == bva.va_uid) {
5263 5380 sarg.vap->va_mask &= ~AT_SIZE;
5264 5381 bf.l_type = F_WRLCK;
5265 5382 bf.l_whence = 0;
5266 5383 bf.l_start = (off64_t)sarg.vap->va_size;
5267 5384 bf.l_len = 0;
5268 5385 bf.l_sysid = 0;
5269 5386 bf.l_pid = 0;
5270 5387 error = VOP_SPACE(vp, F_FREESP, &bf, FWRITE,
5271 5388 (offset_t)sarg.vap->va_size, cr, &ct);
5272 5389 }
5273 5390 }
5274 5391
5275 5392 if (!error && sarg.vap->va_mask != 0)
5276 5393 error = VOP_SETATTR(vp, sarg.vap, sarg.flag, cr, &ct);
5277 5394
5278 5395 /* restore va_mask -- ufs_setattr clears AT_SIZE */
5279 5396 if (saved_mask & AT_SIZE)
5280 5397 sarg.vap->va_mask |= AT_SIZE;
5281 5398
5282 5399 /*
5283 5400 * If an ACL was being set, it has been delayed until now,
5284 5401 * in order to set the mode (via the VOP_SETATTR() above) first.
5285 5402 */
5286 5403 if ((! error) && (fattrp->attrmask & FATTR4_ACL_MASK)) {
5287 5404 int i;
5288 5405
5289 5406 for (i = 0; i < NFS4_MAXNUM_ATTRS; i++)
5290 5407 if (ntov.amap[i] == FATTR4_ACL)
5291 5408 break;
5292 5409 if (i < NFS4_MAXNUM_ATTRS) {
5293 5410 error = (*nfs4_ntov_map[FATTR4_ACL].sv_getit)(
5294 5411 NFS4ATTR_SETIT, &sarg, &ntov.na[i]);
5295 5412 if (error == 0) {
5296 5413 *resp |= FATTR4_ACL_MASK;
5297 5414 } else if (error == ENOTSUP) {
5298 5415 (void) rfs4_verify_attr(&sarg, resp, &ntov);
5299 5416 status = NFS4ERR_ATTRNOTSUPP;
5300 5417 goto done;
5301 5418 }
5302 5419 } else {
5303 5420 NFS4_DEBUG(rfs4_debug,
5304 5421 (CE_NOTE, "do_rfs4_op_setattr: "
5305 5422 "unable to find ACL in fattr4"));
5306 5423 error = EINVAL;
5307 5424 }
5308 5425 }
5309 5426
5310 5427 if (error) {
5311 5428 /* check if a monitor detected a delegation conflict */
5312 5429 if (error == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK))
5313 5430 status = NFS4ERR_DELAY;
5314 5431 else
5315 5432 status = puterrno4(error);
5316 5433
5317 5434 /*
5318 5435 * Set the response bitmap when setattr failed.
5319 5436 * If VOP_SETATTR partially succeeded, test by doing a
5320 5437 * VOP_GETATTR on the object and comparing the data
5321 5438 * to the setattr arguments.
5322 5439 */
5323 5440 (void) rfs4_verify_attr(&sarg, resp, &ntov);
5324 5441 } else {
5325 5442 /*
5326 5443 * Force modified metadata out to stable storage.
5327 5444 */
5328 5445 (void) VOP_FSYNC(vp, FNODSYNC, cr, &ct);
5329 5446 /*
5330 5447 * Set response bitmap
5331 5448 */
5332 5449 nfs4_vmask_to_nmask_set(sarg.vap->va_mask, resp);
5333 5450 }
5334 5451
5335 5452 /* Return early and already have a NFSv4 error */
5336 5453 done:
5337 5454 /*
5338 5455 * Except for nfs4_vmask_to_nmask_set(), vattr --> fattr
5339 5456 * conversion sets both readable and writeable NFS4 attrs
5340 5457 * for AT_MTIME and AT_ATIME. The line below masks out
5341 5458 * unrequested attrs from the setattr result bitmap. This
5342 5459 * is placed after the done: label to catch the ATTRNOTSUP
5343 5460 * case.
5344 5461 */
5345 5462 *resp &= fattrp->attrmask;
5346 5463
5347 5464 if (in_crit)
5348 5465 nbl_end_crit(vp);
5349 5466
5350 5467 nfs4_ntov_table_free(&ntov, &sarg);
5351 5468
5352 5469 return (status);
5353 5470 }
5354 5471
5355 5472 /* ARGSUSED */
5356 5473 static void
5357 5474 rfs4_op_setattr(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
5358 5475 struct compound_state *cs)
5359 5476 {
5360 5477 SETATTR4args *args = &argop->nfs_argop4_u.opsetattr;
5361 5478 SETATTR4res *resp = &resop->nfs_resop4_u.opsetattr;
5362 5479 bslabel_t *clabel;
5363 5480
5364 5481 DTRACE_NFSV4_2(op__setattr__start, struct compound_state *, cs,
5365 5482 SETATTR4args *, args);
5366 5483
5367 5484 if (cs->vp == NULL) {
5368 5485 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
5369 5486 goto out;
5370 5487 }
5371 5488
5372 5489 /*
5373 5490 * If there is an unshared filesystem mounted on this vnode,
5374 5491 * do not allow to setattr on this vnode.
5375 5492 */
5376 5493 if (vn_ismntpt(cs->vp)) {
5377 5494 *cs->statusp = resp->status = NFS4ERR_ACCESS;
5378 5495 goto out;
5379 5496 }
5380 5497
5381 5498 resp->attrsset = 0;
5382 5499
5383 5500 if (rdonly4(req, cs)) {
5384 5501 *cs->statusp = resp->status = NFS4ERR_ROFS;
5385 5502 goto out;
5386 5503 }
5387 5504
5388 5505 /* check label before setting attributes */
5389 5506 if (is_system_labeled()) {
5390 5507 ASSERT(req->rq_label != NULL);
5391 5508 clabel = req->rq_label;
5392 5509 DTRACE_PROBE2(tx__rfs4__log__info__opsetattr__clabel, char *,
5393 5510 "got client label from request(1)",
5394 5511 struct svc_req *, req);
5395 5512 if (!blequal(&l_admin_low->tsl_label, clabel)) {
5396 5513 if (!do_rfs_label_check(clabel, cs->vp,
5397 5514 EQUALITY_CHECK, cs->exi)) {
5398 5515 *cs->statusp = resp->status = NFS4ERR_ACCESS;
5399 5516 goto out;
5400 5517 }
5401 5518 }
5402 5519 }
5403 5520
5404 5521 *cs->statusp = resp->status =
5405 5522 do_rfs4_op_setattr(&resp->attrsset, &args->obj_attributes, cs,
5406 5523 &args->stateid);
5407 5524
5408 5525 out:
5409 5526 DTRACE_NFSV4_2(op__setattr__done, struct compound_state *, cs,
5410 5527 SETATTR4res *, resp);
5411 5528 }
5412 5529
5413 5530 /* ARGSUSED */
5414 5531 static void
5415 5532 rfs4_op_verify(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
5416 5533 struct compound_state *cs)
5417 5534 {
5418 5535 /*
5419 5536 * verify and nverify are exactly the same, except that nverify
5420 5537 * succeeds when some argument changed, and verify succeeds when
5421 5538 * when none changed.
5422 5539 */
5423 5540
5424 5541 VERIFY4args *args = &argop->nfs_argop4_u.opverify;
5425 5542 VERIFY4res *resp = &resop->nfs_resop4_u.opverify;
5426 5543
5427 5544 int error;
5428 5545 struct nfs4_svgetit_arg sarg;
5429 5546 struct statvfs64 sb;
5430 5547 struct nfs4_ntov_table ntov;
5431 5548
5432 5549 DTRACE_NFSV4_2(op__verify__start, struct compound_state *, cs,
5433 5550 VERIFY4args *, args);
5434 5551
5435 5552 if (cs->vp == NULL) {
5436 5553 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
5437 5554 goto out;
5438 5555 }
5439 5556
5440 5557 sarg.sbp = &sb;
5441 5558 sarg.is_referral = B_FALSE;
5442 5559 nfs4_ntov_table_init(&ntov);
5443 5560 resp->status = do_rfs4_set_attrs(NULL, &args->obj_attributes, cs,
5444 5561 &sarg, &ntov, NFS4ATTR_VERIT);
5445 5562 if (resp->status != NFS4_OK) {
5446 5563 /*
5447 5564 * do_rfs4_set_attrs will try to verify systemwide attrs,
5448 5565 * so could return -1 for "no match".
5449 5566 */
5450 5567 if (resp->status == -1)
5451 5568 resp->status = NFS4ERR_NOT_SAME;
5452 5569 goto done;
5453 5570 }
5454 5571 error = rfs4_verify_attr(&sarg, NULL, &ntov);
5455 5572 switch (error) {
5456 5573 case 0:
5457 5574 resp->status = NFS4_OK;
5458 5575 break;
5459 5576 case -1:
5460 5577 resp->status = NFS4ERR_NOT_SAME;
5461 5578 break;
5462 5579 default:
5463 5580 resp->status = puterrno4(error);
5464 5581 break;
5465 5582 }
5466 5583 done:
5467 5584 *cs->statusp = resp->status;
5468 5585 nfs4_ntov_table_free(&ntov, &sarg);
5469 5586 out:
5470 5587 DTRACE_NFSV4_2(op__verify__done, struct compound_state *, cs,
5471 5588 VERIFY4res *, resp);
5472 5589 }
5473 5590
5474 5591 /* ARGSUSED */
5475 5592 static void
5476 5593 rfs4_op_nverify(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
5477 5594 struct compound_state *cs)
5478 5595 {
5479 5596 /*
5480 5597 * verify and nverify are exactly the same, except that nverify
5481 5598 * succeeds when some argument changed, and verify succeeds when
5482 5599 * when none changed.
5483 5600 */
5484 5601
5485 5602 NVERIFY4args *args = &argop->nfs_argop4_u.opnverify;
5486 5603 NVERIFY4res *resp = &resop->nfs_resop4_u.opnverify;
5487 5604
5488 5605 int error;
5489 5606 struct nfs4_svgetit_arg sarg;
5490 5607 struct statvfs64 sb;
5491 5608 struct nfs4_ntov_table ntov;
5492 5609
5493 5610 DTRACE_NFSV4_2(op__nverify__start, struct compound_state *, cs,
5494 5611 NVERIFY4args *, args);
5495 5612
5496 5613 if (cs->vp == NULL) {
5497 5614 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
5498 5615 DTRACE_NFSV4_2(op__nverify__done, struct compound_state *, cs,
5499 5616 NVERIFY4res *, resp);
5500 5617 return;
5501 5618 }
5502 5619 sarg.sbp = &sb;
5503 5620 sarg.is_referral = B_FALSE;
5504 5621 nfs4_ntov_table_init(&ntov);
5505 5622 resp->status = do_rfs4_set_attrs(NULL, &args->obj_attributes, cs,
5506 5623 &sarg, &ntov, NFS4ATTR_VERIT);
5507 5624 if (resp->status != NFS4_OK) {
5508 5625 /*
5509 5626 * do_rfs4_set_attrs will try to verify systemwide attrs,
5510 5627 * so could return -1 for "no match".
5511 5628 */
5512 5629 if (resp->status == -1)
5513 5630 resp->status = NFS4_OK;
5514 5631 goto done;
5515 5632 }
5516 5633 error = rfs4_verify_attr(&sarg, NULL, &ntov);
5517 5634 switch (error) {
5518 5635 case 0:
5519 5636 resp->status = NFS4ERR_SAME;
5520 5637 break;
5521 5638 case -1:
5522 5639 resp->status = NFS4_OK;
5523 5640 break;
5524 5641 default:
5525 5642 resp->status = puterrno4(error);
5526 5643 break;
5527 5644 }
5528 5645 done:
5529 5646 *cs->statusp = resp->status;
5530 5647 nfs4_ntov_table_free(&ntov, &sarg);
5531 5648
5532 5649 DTRACE_NFSV4_2(op__nverify__done, struct compound_state *, cs,
5533 5650 NVERIFY4res *, resp);
5534 5651 }
5535 5652
5536 5653 /*
5537 5654 * XXX - This should live in an NFS header file.
5538 5655 */
5539 5656 #define MAX_IOVECS 12
5540 5657
5541 5658 /* ARGSUSED */
5542 5659 static void
5543 5660 rfs4_op_write(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
5544 5661 struct compound_state *cs)
5545 5662 {
5546 5663 WRITE4args *args = &argop->nfs_argop4_u.opwrite;
5547 5664 WRITE4res *resp = &resop->nfs_resop4_u.opwrite;
5548 5665 int error;
5549 5666 vnode_t *vp;
5550 5667 struct vattr bva;
5551 5668 u_offset_t rlimit;
|
↓ open down ↓ |
916 lines elided |
↑ open up ↑ |
5552 5669 struct uio uio;
5553 5670 struct iovec iov[MAX_IOVECS];
5554 5671 struct iovec *iovp;
5555 5672 int iovcnt;
5556 5673 int ioflag;
5557 5674 cred_t *savecred, *cr;
5558 5675 bool_t *deleg = &cs->deleg;
5559 5676 nfsstat4 stat;
5560 5677 int in_crit = 0;
5561 5678 caller_context_t ct;
5679 + nfs4_srv_t *nsrv4;
5562 5680
5563 5681 DTRACE_NFSV4_2(op__write__start, struct compound_state *, cs,
5564 5682 WRITE4args *, args);
5565 5683
5566 5684 vp = cs->vp;
5567 5685 if (vp == NULL) {
5568 5686 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
5569 5687 goto out;
5570 5688 }
5571 5689 if (cs->access == CS_ACCESS_DENIED) {
5572 5690 *cs->statusp = resp->status = NFS4ERR_ACCESS;
5573 5691 goto out;
5574 5692 }
5575 5693
5576 5694 cr = cs->cr;
5577 5695
5578 5696 if ((stat = rfs4_check_stateid(FWRITE, vp, &args->stateid, FALSE,
5579 5697 deleg, TRUE, &ct)) != NFS4_OK) {
5580 5698 *cs->statusp = resp->status = stat;
5581 5699 goto out;
5582 5700 }
5583 5701
5584 5702 /*
5585 5703 * We have to enter the critical region before calling VOP_RWLOCK
5586 5704 * to avoid a deadlock with ufs.
5587 5705 */
5588 5706 if (nbl_need_check(vp)) {
5589 5707 nbl_start_crit(vp, RW_READER);
5590 5708 in_crit = 1;
5591 5709 if (nbl_conflict(vp, NBL_WRITE,
5592 5710 args->offset, args->data_len, 0, &ct)) {
5593 5711 *cs->statusp = resp->status = NFS4ERR_LOCKED;
5594 5712 goto out;
5595 5713 }
5596 5714 }
5597 5715
5598 5716 bva.va_mask = AT_MODE | AT_UID;
5599 5717 error = VOP_GETATTR(vp, &bva, 0, cr, &ct);
5600 5718
5601 5719 /*
5602 5720 * If we can't get the attributes, then we can't do the
5603 5721 * right access checking. So, we'll fail the request.
5604 5722 */
5605 5723 if (error) {
5606 5724 *cs->statusp = resp->status = puterrno4(error);
5607 5725 goto out;
5608 5726 }
5609 5727
5610 5728 if (rdonly4(req, cs)) {
5611 5729 *cs->statusp = resp->status = NFS4ERR_ROFS;
5612 5730 goto out;
5613 5731 }
5614 5732
5615 5733 if (vp->v_type != VREG) {
5616 5734 *cs->statusp = resp->status =
5617 5735 ((vp->v_type == VDIR) ? NFS4ERR_ISDIR : NFS4ERR_INVAL);
5618 5736 goto out;
5619 5737 }
5620 5738
5621 5739 if (crgetuid(cr) != bva.va_uid &&
|
↓ open down ↓ |
50 lines elided |
↑ open up ↑ |
5622 5740 (error = VOP_ACCESS(vp, VWRITE, 0, cr, &ct))) {
5623 5741 *cs->statusp = resp->status = puterrno4(error);
5624 5742 goto out;
5625 5743 }
5626 5744
5627 5745 if (MANDLOCK(vp, bva.va_mode)) {
5628 5746 *cs->statusp = resp->status = NFS4ERR_ACCESS;
5629 5747 goto out;
5630 5748 }
5631 5749
5750 + nsrv4 = zone_getspecific(rfs4_zone_key, curzone);
5632 5751 if (args->data_len == 0) {
5633 5752 *cs->statusp = resp->status = NFS4_OK;
5634 5753 resp->count = 0;
5635 5754 resp->committed = args->stable;
5636 - resp->writeverf = Write4verf;
5755 + resp->writeverf = nsrv4->write4verf;
5637 5756 goto out;
5638 5757 }
5639 5758
5640 5759 if (args->mblk != NULL) {
5641 5760 mblk_t *m;
5642 5761 uint_t bytes, round_len;
5643 5762
5644 5763 iovcnt = 0;
5645 5764 bytes = 0;
5646 5765 round_len = roundup(args->data_len, BYTES_PER_XDR_UNIT);
5647 5766 for (m = args->mblk;
5648 5767 m != NULL && bytes < round_len;
5649 5768 m = m->b_cont) {
5650 5769 iovcnt++;
5651 5770 bytes += MBLKL(m);
5652 5771 }
5653 5772 #ifdef DEBUG
5654 5773 /* should have ended on an mblk boundary */
5655 5774 if (bytes != round_len) {
5656 5775 printf("bytes=0x%x, round_len=0x%x, req len=0x%x\n",
5657 5776 bytes, round_len, args->data_len);
5658 5777 printf("args=%p, args->mblk=%p, m=%p", (void *)args,
5659 5778 (void *)args->mblk, (void *)m);
5660 5779 ASSERT(bytes == round_len);
5661 5780 }
5662 5781 #endif
5663 5782 if (iovcnt <= MAX_IOVECS) {
5664 5783 iovp = iov;
5665 5784 } else {
5666 5785 iovp = kmem_alloc(sizeof (*iovp) * iovcnt, KM_SLEEP);
5667 5786 }
5668 5787 mblk_to_iov(args->mblk, iovcnt, iovp);
5669 5788 } else if (args->rlist != NULL) {
5670 5789 iovcnt = 1;
5671 5790 iovp = iov;
5672 5791 iovp->iov_base = (char *)((args->rlist)->u.c_daddr3);
5673 5792 iovp->iov_len = args->data_len;
5674 5793 } else {
5675 5794 iovcnt = 1;
5676 5795 iovp = iov;
5677 5796 iovp->iov_base = args->data_val;
5678 5797 iovp->iov_len = args->data_len;
5679 5798 }
5680 5799
5681 5800 uio.uio_iov = iovp;
5682 5801 uio.uio_iovcnt = iovcnt;
5683 5802
5684 5803 uio.uio_segflg = UIO_SYSSPACE;
5685 5804 uio.uio_extflg = UIO_COPY_DEFAULT;
5686 5805 uio.uio_loffset = args->offset;
5687 5806 uio.uio_resid = args->data_len;
5688 5807 uio.uio_llimit = curproc->p_fsz_ctl;
5689 5808 rlimit = uio.uio_llimit - args->offset;
5690 5809 if (rlimit < (u_offset_t)uio.uio_resid)
5691 5810 uio.uio_resid = (int)rlimit;
5692 5811
5693 5812 if (args->stable == UNSTABLE4)
5694 5813 ioflag = 0;
5695 5814 else if (args->stable == FILE_SYNC4)
5696 5815 ioflag = FSYNC;
5697 5816 else if (args->stable == DATA_SYNC4)
5698 5817 ioflag = FDSYNC;
5699 5818 else {
5700 5819 if (iovp != iov)
5701 5820 kmem_free(iovp, sizeof (*iovp) * iovcnt);
5702 5821 *cs->statusp = resp->status = NFS4ERR_INVAL;
5703 5822 goto out;
5704 5823 }
5705 5824
5706 5825 /*
5707 5826 * We're changing creds because VM may fault and we need
5708 5827 * the cred of the current thread to be used if quota
5709 5828 * checking is enabled.
5710 5829 */
5711 5830 savecred = curthread->t_cred;
5712 5831 curthread->t_cred = cr;
5713 5832 error = do_io(FWRITE, vp, &uio, ioflag, cr, &ct);
5714 5833 curthread->t_cred = savecred;
5715 5834
5716 5835 if (iovp != iov)
5717 5836 kmem_free(iovp, sizeof (*iovp) * iovcnt);
5718 5837
5719 5838 if (error) {
5720 5839 *cs->statusp = resp->status = puterrno4(error);
5721 5840 goto out;
|
↓ open down ↓ |
75 lines elided |
↑ open up ↑ |
5722 5841 }
5723 5842
5724 5843 *cs->statusp = resp->status = NFS4_OK;
5725 5844 resp->count = args->data_len - uio.uio_resid;
5726 5845
5727 5846 if (ioflag == 0)
5728 5847 resp->committed = UNSTABLE4;
5729 5848 else
5730 5849 resp->committed = FILE_SYNC4;
5731 5850
5732 - resp->writeverf = Write4verf;
5851 + resp->writeverf = nsrv4->write4verf;
5733 5852
5734 5853 out:
5735 5854 if (in_crit)
5736 5855 nbl_end_crit(vp);
5737 5856
5738 5857 DTRACE_NFSV4_2(op__write__done, struct compound_state *, cs,
5739 5858 WRITE4res *, resp);
5740 5859 }
5741 5860
5742 5861
5743 5862 /* XXX put in a header file */
5744 5863 extern int sec_svc_getcred(struct svc_req *, cred_t *, caddr_t *, int *);
5745 5864
5746 5865 void
5747 5866 rfs4_compound(COMPOUND4args *args, COMPOUND4res *resp, struct exportinfo *exi,
5748 5867 struct svc_req *req, cred_t *cr, int *rv)
5749 5868 {
5750 5869 uint_t i;
5751 5870 struct compound_state cs;
5871 + nfs4_srv_t *nsrv4;
5872 + nfs_export_t *ne = nfs_get_export();
5752 5873
5753 5874 if (rv != NULL)
5754 5875 *rv = 0;
5755 5876 rfs4_init_compound_state(&cs);
5756 5877 /*
5757 5878 * Form a reply tag by copying over the reqeuest tag.
5758 5879 */
5759 5880 resp->tag.utf8string_val =
5760 5881 kmem_alloc(args->tag.utf8string_len, KM_SLEEP);
5761 5882 resp->tag.utf8string_len = args->tag.utf8string_len;
5762 5883 bcopy(args->tag.utf8string_val, resp->tag.utf8string_val,
5763 5884 resp->tag.utf8string_len);
5764 5885
5765 5886 cs.statusp = &resp->status;
5766 5887 cs.req = req;
5767 5888 resp->array = NULL;
5768 5889 resp->array_len = 0;
5769 5890
5770 5891 /*
5771 5892 * XXX for now, minorversion should be zero
5772 5893 */
5773 5894 if (args->minorversion != NFS4_MINORVERSION) {
5774 5895 DTRACE_NFSV4_2(compound__start, struct compound_state *,
5775 5896 &cs, COMPOUND4args *, args);
5776 5897 resp->status = NFS4ERR_MINOR_VERS_MISMATCH;
5777 5898 DTRACE_NFSV4_2(compound__done, struct compound_state *,
5778 5899 &cs, COMPOUND4res *, resp);
5779 5900 return;
5780 5901 }
5781 5902
5782 5903 if (args->array_len == 0) {
5783 5904 resp->status = NFS4_OK;
5784 5905 return;
5785 5906 }
5786 5907
5787 5908 ASSERT(exi == NULL);
5788 5909 ASSERT(cr == NULL);
5789 5910
5790 5911 cr = crget();
5791 5912 ASSERT(cr != NULL);
5792 5913
5793 5914 if (sec_svc_getcred(req, cr, &cs.principal, &cs.nfsflavor) == 0) {
5794 5915 DTRACE_NFSV4_2(compound__start, struct compound_state *,
5795 5916 &cs, COMPOUND4args *, args);
5796 5917 crfree(cr);
5797 5918 DTRACE_NFSV4_2(compound__done, struct compound_state *,
5798 5919 &cs, COMPOUND4res *, resp);
|
↓ open down ↓ |
37 lines elided |
↑ open up ↑ |
5799 5920 svcerr_badcred(req->rq_xprt);
5800 5921 if (rv != NULL)
5801 5922 *rv = 1;
5802 5923 return;
5803 5924 }
5804 5925 resp->array_len = args->array_len;
5805 5926 resp->array = kmem_zalloc(args->array_len * sizeof (nfs_resop4),
5806 5927 KM_SLEEP);
5807 5928
5808 5929 cs.basecr = cr;
5930 + nsrv4 = zone_getspecific(rfs4_zone_key, curzone);
5809 5931
5810 5932 DTRACE_NFSV4_2(compound__start, struct compound_state *, &cs,
5811 5933 COMPOUND4args *, args);
5812 5934
5813 5935 /*
5814 5936 * For now, NFS4 compound processing must be protected by
5815 5937 * exported_lock because it can access more than one exportinfo
5816 5938 * per compound and share/unshare can now change multiple
5817 5939 * exinfo structs. The NFS2/3 code only refs 1 exportinfo
5818 5940 * per proc (excluding public exinfo), and exi_count design
5819 5941 * is sufficient to protect concurrent execution of NFS2/3
5820 5942 * ops along with unexport. This lock will be removed as
5821 5943 * part of the NFSv4 phase 2 namespace redesign work.
5822 5944 */
5823 - rw_enter(&exported_lock, RW_READER);
5945 + rw_enter(&ne->exported_lock, RW_READER);
5824 5946
5825 5947 /*
5826 5948 * If this is the first compound we've seen, we need to start all
5827 5949 * new instances' grace periods.
5828 5950 */
5829 - if (rfs4_seen_first_compound == 0) {
5830 - rfs4_grace_start_new();
5951 + if (nsrv4->seen_first_compound == 0) {
5952 + rfs4_grace_start_new(nsrv4);
5831 5953 /*
5832 5954 * This must be set after rfs4_grace_start_new(), otherwise
5833 5955 * another thread could proceed past here before the former
5834 5956 * is finished.
5835 5957 */
5836 - rfs4_seen_first_compound = 1;
5958 + nsrv4->seen_first_compound = 1;
5837 5959 }
5838 5960
5839 5961 for (i = 0; i < args->array_len && cs.cont; i++) {
5840 5962 nfs_argop4 *argop;
5841 5963 nfs_resop4 *resop;
5842 5964 uint_t op;
5843 5965
5844 5966 argop = &args->array[i];
5845 5967 resop = &resp->array[i];
5846 5968 resop->resop = argop->argop;
5847 5969 op = (uint_t)resop->resop;
5848 5970
5849 5971 if (op < rfsv4disp_cnt) {
5972 + kstat_t *ksp = rfsprocio_v4_ptr[op];
5973 + kstat_t *exi_ksp = NULL;
5974 +
5850 5975 /*
5851 5976 * Count the individual ops here; NULL and COMPOUND
5852 5977 * are counted in common_dispatch()
5853 5978 */
5854 5979 rfsproccnt_v4_ptr[op].value.ui64++;
5855 5980
5981 + if (ksp != NULL) {
5982 + mutex_enter(ksp->ks_lock);
5983 + kstat_runq_enter(KSTAT_IO_PTR(ksp));
5984 + mutex_exit(ksp->ks_lock);
5985 + }
5986 +
5987 + switch (rfsv4disptab[op].op_type) {
5988 + case NFS4_OP_CFH:
5989 + resop->exi = cs.exi;
5990 + break;
5991 + case NFS4_OP_SFH:
5992 + resop->exi = cs.saved_exi;
5993 + break;
5994 + default:
5995 + ASSERT(resop->exi == NULL);
5996 + break;
5997 + }
5998 +
5999 + if (resop->exi != NULL) {
6000 + exi_ksp = NULL;
6001 + if (resop->exi->exi_kstats != NULL) {
6002 + exi_ksp = exp_kstats_v4(
6003 + resop->exi->exi_kstats, op);
6004 + }
6005 + if (exi_ksp != NULL) {
6006 + mutex_enter(exi_ksp->ks_lock);
6007 + kstat_runq_enter(KSTAT_IO_PTR(exi_ksp));
6008 + mutex_exit(exi_ksp->ks_lock);
6009 + }
6010 + }
6011 +
5856 6012 NFS4_DEBUG(rfs4_debug > 1,
5857 6013 (CE_NOTE, "Executing %s", rfs4_op_string[op]));
5858 6014 (*rfsv4disptab[op].dis_proc)(argop, resop, req, &cs);
5859 6015 NFS4_DEBUG(rfs4_debug > 1, (CE_NOTE, "%s returned %d",
5860 6016 rfs4_op_string[op], *cs.statusp));
5861 6017 if (*cs.statusp != NFS4_OK)
5862 6018 cs.cont = FALSE;
6019 +
6020 + if (rfsv4disptab[op].op_type == NFS4_OP_POSTCFH &&
6021 + *cs.statusp == NFS4_OK &&
6022 + (resop->exi = cs.exi) != NULL) {
6023 + exi_ksp = NULL;
6024 + if (resop->exi->exi_kstats != NULL) {
6025 + exi_ksp = exp_kstats_v4(
6026 + resop->exi->exi_kstats, op);
6027 + }
6028 + }
6029 +
6030 + if (exi_ksp != NULL) {
6031 + mutex_enter(exi_ksp->ks_lock);
6032 + KSTAT_IO_PTR(exi_ksp)->nwritten +=
6033 + argop->opsize;
6034 + KSTAT_IO_PTR(exi_ksp)->writes++;
6035 + if (rfsv4disptab[op].op_type != NFS4_OP_POSTCFH)
6036 + kstat_runq_exit(KSTAT_IO_PTR(exi_ksp));
6037 + mutex_exit(exi_ksp->ks_lock);
6038 + } else {
6039 + resop->exi = NULL;
6040 + }
6041 +
6042 + if (ksp != NULL) {
6043 + mutex_enter(ksp->ks_lock);
6044 + kstat_runq_exit(KSTAT_IO_PTR(ksp));
6045 + mutex_exit(ksp->ks_lock);
6046 + }
5863 6047 } else {
5864 6048 /*
5865 6049 * This is effectively dead code since XDR code
5866 6050 * will have already returned BADXDR if op doesn't
5867 6051 * decode to legal value. This only done for a
5868 6052 * day when XDR code doesn't verify v4 opcodes.
5869 6053 */
5870 6054 op = OP_ILLEGAL;
5871 6055 rfsproccnt_v4_ptr[OP_ILLEGAL_IDX].value.ui64++;
5872 6056
5873 6057 rfs4_op_illegal(argop, resop, req, &cs);
5874 6058 cs.cont = FALSE;
5875 6059 }
5876 6060
5877 6061 /*
6062 + * The exi saved in the resop to be used for kstats update
6063 + * once the opsize is calculated during XDR response encoding.
6064 + * Put a hold on resop->exi so that it can't be destroyed.
6065 + */
6066 + if (resop->exi != NULL)
6067 + exi_hold(resop->exi);
6068 +
6069 + /*
5878 6070 * If not at last op, and if we are to stop, then
5879 6071 * compact the results array.
5880 6072 */
5881 6073 if ((i + 1) < args->array_len && !cs.cont) {
5882 6074 nfs_resop4 *new_res = kmem_alloc(
5883 - (i+1) * sizeof (nfs_resop4), KM_SLEEP);
6075 + (i + 1) * sizeof (nfs_resop4), KM_SLEEP);
5884 6076 bcopy(resp->array,
5885 - new_res, (i+1) * sizeof (nfs_resop4));
6077 + new_res, (i + 1) * sizeof (nfs_resop4));
5886 6078 kmem_free(resp->array,
5887 6079 args->array_len * sizeof (nfs_resop4));
5888 6080
5889 - resp->array_len = i + 1;
6081 + resp->array_len = i + 1;
5890 6082 resp->array = new_res;
5891 6083 }
5892 6084 }
5893 6085
5894 - rw_exit(&exported_lock);
6086 + rw_exit(&ne->exported_lock);
5895 6087
5896 - DTRACE_NFSV4_2(compound__done, struct compound_state *, &cs,
5897 - COMPOUND4res *, resp);
5898 -
6088 + /*
6089 + * clear exportinfo and vnode fields from compound_state before dtrace
6090 + * probe, to avoid tracing residual values for path and share path.
6091 + */
5899 6092 if (cs.vp)
5900 6093 VN_RELE(cs.vp);
5901 6094 if (cs.saved_vp)
5902 6095 VN_RELE(cs.saved_vp);
6096 + cs.exi = cs.saved_exi = NULL;
6097 + cs.vp = cs.saved_vp = NULL;
6098 +
6099 + DTRACE_NFSV4_2(compound__done, struct compound_state *, &cs,
6100 + COMPOUND4res *, resp);
6101 +
5903 6102 if (cs.saved_fh.nfs_fh4_val)
5904 6103 kmem_free(cs.saved_fh.nfs_fh4_val, NFS4_FHSIZE);
5905 6104
5906 6105 if (cs.basecr)
5907 6106 crfree(cs.basecr);
5908 6107 if (cs.cr)
5909 6108 crfree(cs.cr);
5910 6109 /*
5911 6110 * done with this compound request, free the label
5912 6111 */
5913 6112
5914 6113 if (req->rq_label != NULL) {
5915 6114 kmem_free(req->rq_label, sizeof (bslabel_t));
5916 6115 req->rq_label = NULL;
5917 6116 }
5918 6117 }
5919 6118
5920 6119 /*
5921 6120 * XXX because of what appears to be duplicate calls to rfs4_compound_free
5922 6121 * XXX zero out the tag and array values. Need to investigate why the
5923 6122 * XXX calls occur, but at least prevent the panic for now.
5924 6123 */
5925 6124 void
5926 6125 rfs4_compound_free(COMPOUND4res *resp)
5927 6126 {
5928 6127 uint_t i;
5929 6128
5930 6129 if (resp->tag.utf8string_val) {
5931 6130 UTF8STRING_FREE(resp->tag)
5932 6131 }
5933 6132
5934 6133 for (i = 0; i < resp->array_len; i++) {
5935 6134 nfs_resop4 *resop;
5936 6135 uint_t op;
5937 6136
5938 6137 resop = &resp->array[i];
5939 6138 op = (uint_t)resop->resop;
5940 6139 if (op < rfsv4disp_cnt) {
5941 6140 (*rfsv4disptab[op].dis_resfree)(resop);
5942 6141 }
5943 6142 }
5944 6143 if (resp->array != NULL) {
5945 6144 kmem_free(resp->array, resp->array_len * sizeof (nfs_resop4));
5946 6145 }
5947 6146 }
5948 6147
5949 6148 /*
5950 6149 * Process the value of the compound request rpc flags, as a bit-AND
5951 6150 * of the individual per-op flags (idempotent, allowork, publicfh_ok)
5952 6151 */
5953 6152 void
5954 6153 rfs4_compound_flagproc(COMPOUND4args *args, int *flagp)
5955 6154 {
5956 6155 int i;
5957 6156 int flag = RPC_ALL;
5958 6157
5959 6158 for (i = 0; flag && i < args->array_len; i++) {
5960 6159 uint_t op;
5961 6160
|
↓ open down ↓ |
49 lines elided |
↑ open up ↑ |
5962 6161 op = (uint_t)args->array[i].argop;
5963 6162
5964 6163 if (op < rfsv4disp_cnt)
5965 6164 flag &= rfsv4disptab[op].dis_flags;
5966 6165 else
5967 6166 flag = 0;
5968 6167 }
5969 6168 *flagp = flag;
5970 6169 }
5971 6170
6171 +/*
6172 + * Update the kstats for the received requests.
6173 + * Note: writes/nwritten are used to hold count and nbytes of requests received.
6174 + *
6175 + * Per export request statistics need to be updated during the compound request
6176 + * processing (rfs4_compound()) as that is where it is known which exportinfo to
6177 + * associate the kstats with.
6178 + */
6179 +void
6180 +rfs4_compound_kstat_args(COMPOUND4args *args)
6181 +{
6182 + int i;
6183 +
6184 + for (i = 0; i < args->array_len; i++) {
6185 + uint_t op = (uint_t)args->array[i].argop;
6186 +
6187 + if (op < rfsv4disp_cnt) {
6188 + kstat_t *ksp = rfsprocio_v4_ptr[op];
6189 +
6190 + if (ksp != NULL) {
6191 + mutex_enter(ksp->ks_lock);
6192 + KSTAT_IO_PTR(ksp)->nwritten +=
6193 + args->array[i].opsize;
6194 + KSTAT_IO_PTR(ksp)->writes++;
6195 + mutex_exit(ksp->ks_lock);
6196 + }
6197 + }
6198 + }
6199 +}
6200 +
6201 +/*
6202 + * Update the kstats for the sent responses.
6203 + * Note: reads/nread are used to hold count and nbytes of responses sent.
6204 + *
6205 + * Per export response statistics cannot be updated until here, after the
6206 + * response send has generated the opsize (bytes sent) in the XDR encoding.
6207 + * The exportinfo with which the kstats should be associated is thus saved
6208 + * in the response structure (by rfs4_compound()) for use here. A hold is
6209 + * placed on the exi to ensure it cannot be deleted before use. This hold
6210 + * is released, and the exi set to NULL, here.
6211 + */
6212 +void
6213 +rfs4_compound_kstat_res(COMPOUND4res *res)
6214 +{
6215 + int i;
6216 + nfs_export_t *ne = nfs_get_export();
6217 +
6218 + for (i = 0; i < res->array_len; i++) {
6219 + uint_t op = (uint_t)res->array[i].resop;
6220 +
6221 + if (op < rfsv4disp_cnt) {
6222 + kstat_t *ksp = rfsprocio_v4_ptr[op];
6223 + struct exportinfo *exi = res->array[i].exi;
6224 +
6225 + if (ksp != NULL) {
6226 + mutex_enter(ksp->ks_lock);
6227 + KSTAT_IO_PTR(ksp)->nread +=
6228 + res->array[i].opsize;
6229 + KSTAT_IO_PTR(ksp)->reads++;
6230 + mutex_exit(ksp->ks_lock);
6231 + }
6232 +
6233 + if (exi != NULL) {
6234 + kstat_t *exi_ksp = NULL;
6235 +
6236 + rw_enter(&ne->exported_lock, RW_READER);
6237 +
6238 + if (exi->exi_kstats != NULL) {
6239 + /*CSTYLED*/
6240 + exi_ksp = exp_kstats_v4(exi->exi_kstats, op);
6241 + }
6242 + if (exi_ksp != NULL) {
6243 + mutex_enter(exi_ksp->ks_lock);
6244 + KSTAT_IO_PTR(exi_ksp)->nread +=
6245 + res->array[i].opsize;
6246 + KSTAT_IO_PTR(exi_ksp)->reads++;
6247 + mutex_exit(exi_ksp->ks_lock);
6248 + }
6249 +
6250 + exi_rele(&exi);
6251 + res->array[i].exi = NULL;
6252 + rw_exit(&ne->exported_lock);
6253 + }
6254 + }
6255 + }
6256 +}
6257 +
5972 6258 nfsstat4
5973 6259 rfs4_client_sysid(rfs4_client_t *cp, sysid_t *sp)
5974 6260 {
5975 6261 nfsstat4 e;
5976 6262
5977 6263 rfs4_dbe_lock(cp->rc_dbe);
5978 6264
5979 6265 if (cp->rc_sysidt != LM_NOSYSID) {
5980 6266 *sp = cp->rc_sysidt;
5981 6267 e = NFS4_OK;
5982 6268
5983 6269 } else if ((cp->rc_sysidt = lm_alloc_sysidt()) != LM_NOSYSID) {
5984 6270 *sp = cp->rc_sysidt;
5985 6271 e = NFS4_OK;
5986 6272
5987 6273 NFS4_DEBUG(rfs4_debug, (CE_NOTE,
5988 6274 "rfs4_client_sysid: allocated 0x%x\n", *sp));
5989 6275 } else
5990 6276 e = NFS4ERR_DELAY;
5991 6277
5992 6278 rfs4_dbe_unlock(cp->rc_dbe);
5993 6279 return (e);
5994 6280 }
5995 6281
5996 6282 #if defined(DEBUG) && ! defined(lint)
5997 6283 static void lock_print(char *str, int operation, struct flock64 *flk)
5998 6284 {
5999 6285 char *op, *type;
6000 6286
6001 6287 switch (operation) {
6002 6288 case F_GETLK: op = "F_GETLK";
6003 6289 break;
6004 6290 case F_SETLK: op = "F_SETLK";
6005 6291 break;
6006 6292 case F_SETLK_NBMAND: op = "F_SETLK_NBMAND";
6007 6293 break;
6008 6294 default: op = "F_UNKNOWN";
6009 6295 break;
6010 6296 }
6011 6297 switch (flk->l_type) {
6012 6298 case F_UNLCK: type = "F_UNLCK";
6013 6299 break;
6014 6300 case F_RDLCK: type = "F_RDLCK";
6015 6301 break;
6016 6302 case F_WRLCK: type = "F_WRLCK";
6017 6303 break;
6018 6304 default: type = "F_UNKNOWN";
6019 6305 break;
6020 6306 }
6021 6307
6022 6308 ASSERT(flk->l_whence == 0);
6023 6309 cmn_err(CE_NOTE, "%s: %s, type = %s, off = %llx len = %llx pid = %d",
6024 6310 str, op, type, (longlong_t)flk->l_start,
6025 6311 flk->l_len ? (longlong_t)flk->l_len : ~0LL, flk->l_pid);
6026 6312 }
6027 6313
6028 6314 #define LOCK_PRINT(d, s, t, f) if (d) lock_print(s, t, f)
6029 6315 #else
6030 6316 #define LOCK_PRINT(d, s, t, f)
6031 6317 #endif
6032 6318
6033 6319 /*ARGSUSED*/
6034 6320 static bool_t
6035 6321 creds_ok(cred_set_t cr_set, struct svc_req *req, struct compound_state *cs)
6036 6322 {
6037 6323 return (TRUE);
6038 6324 }
6039 6325
6040 6326 /*
6041 6327 * Look up the pathname using the vp in cs as the directory vnode.
6042 6328 * cs->vp will be the vnode for the file on success
6043 6329 */
6044 6330
6045 6331 static nfsstat4
6046 6332 rfs4_lookup(component4 *component, struct svc_req *req,
6047 6333 struct compound_state *cs)
6048 6334 {
6049 6335 char *nm;
6050 6336 uint32_t len;
6051 6337 nfsstat4 status;
6052 6338 struct sockaddr *ca;
6053 6339 char *name;
6054 6340
6055 6341 if (cs->vp == NULL) {
6056 6342 return (NFS4ERR_NOFILEHANDLE);
6057 6343 }
6058 6344 if (cs->vp->v_type != VDIR) {
6059 6345 return (NFS4ERR_NOTDIR);
6060 6346 }
6061 6347
6062 6348 status = utf8_dir_verify(component);
6063 6349 if (status != NFS4_OK)
6064 6350 return (status);
6065 6351
6066 6352 nm = utf8_to_fn(component, &len, NULL);
6067 6353 if (nm == NULL) {
6068 6354 return (NFS4ERR_INVAL);
6069 6355 }
6070 6356
6071 6357 if (len > MAXNAMELEN) {
6072 6358 kmem_free(nm, len);
6073 6359 return (NFS4ERR_NAMETOOLONG);
6074 6360 }
6075 6361
6076 6362 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
6077 6363 name = nfscmd_convname(ca, cs->exi, nm, NFSCMD_CONV_INBOUND,
6078 6364 MAXPATHLEN + 1);
6079 6365
6080 6366 if (name == NULL) {
6081 6367 kmem_free(nm, len);
6082 6368 return (NFS4ERR_INVAL);
6083 6369 }
6084 6370
6085 6371 status = do_rfs4_op_lookup(name, req, cs);
6086 6372
6087 6373 if (name != nm)
6088 6374 kmem_free(name, MAXPATHLEN + 1);
6089 6375
6090 6376 kmem_free(nm, len);
6091 6377
6092 6378 return (status);
6093 6379 }
6094 6380
6095 6381 static nfsstat4
6096 6382 rfs4_lookupfile(component4 *component, struct svc_req *req,
6097 6383 struct compound_state *cs, uint32_t access, change_info4 *cinfo)
6098 6384 {
6099 6385 nfsstat4 status;
6100 6386 vnode_t *dvp = cs->vp;
6101 6387 vattr_t bva, ava, fva;
6102 6388 int error;
6103 6389
6104 6390 /* Get "before" change value */
6105 6391 bva.va_mask = AT_CTIME|AT_SEQ;
6106 6392 error = VOP_GETATTR(dvp, &bva, 0, cs->cr, NULL);
6107 6393 if (error)
6108 6394 return (puterrno4(error));
6109 6395
6110 6396 /* rfs4_lookup may VN_RELE directory */
6111 6397 VN_HOLD(dvp);
6112 6398
6113 6399 status = rfs4_lookup(component, req, cs);
6114 6400 if (status != NFS4_OK) {
6115 6401 VN_RELE(dvp);
6116 6402 return (status);
6117 6403 }
6118 6404
6119 6405 /*
6120 6406 * Get "after" change value, if it fails, simply return the
6121 6407 * before value.
6122 6408 */
6123 6409 ava.va_mask = AT_CTIME|AT_SEQ;
6124 6410 if (VOP_GETATTR(dvp, &ava, 0, cs->cr, NULL)) {
6125 6411 ava.va_ctime = bva.va_ctime;
6126 6412 ava.va_seq = 0;
6127 6413 }
6128 6414 VN_RELE(dvp);
6129 6415
6130 6416 /*
6131 6417 * Validate the file is a file
6132 6418 */
6133 6419 fva.va_mask = AT_TYPE|AT_MODE;
6134 6420 error = VOP_GETATTR(cs->vp, &fva, 0, cs->cr, NULL);
6135 6421 if (error)
6136 6422 return (puterrno4(error));
6137 6423
6138 6424 if (fva.va_type != VREG) {
6139 6425 if (fva.va_type == VDIR)
6140 6426 return (NFS4ERR_ISDIR);
6141 6427 if (fva.va_type == VLNK)
6142 6428 return (NFS4ERR_SYMLINK);
6143 6429 return (NFS4ERR_INVAL);
6144 6430 }
6145 6431
6146 6432 NFS4_SET_FATTR4_CHANGE(cinfo->before, bva.va_ctime);
6147 6433 NFS4_SET_FATTR4_CHANGE(cinfo->after, ava.va_ctime);
6148 6434
6149 6435 /*
6150 6436 * It is undefined if VOP_LOOKUP will change va_seq, so
6151 6437 * cinfo.atomic = TRUE only if we have
6152 6438 * non-zero va_seq's, and they have not changed.
6153 6439 */
6154 6440 if (bva.va_seq && ava.va_seq && ava.va_seq == bva.va_seq)
6155 6441 cinfo->atomic = TRUE;
6156 6442 else
6157 6443 cinfo->atomic = FALSE;
6158 6444
6159 6445 /* Check for mandatory locking */
6160 6446 cs->mandlock = MANDLOCK(cs->vp, fva.va_mode);
6161 6447 return (check_open_access(access, cs, req));
6162 6448 }
6163 6449
6164 6450 static nfsstat4
6165 6451 create_vnode(vnode_t *dvp, char *nm, vattr_t *vap, createmode4 mode,
6166 6452 cred_t *cr, vnode_t **vpp, bool_t *created)
6167 6453 {
6168 6454 int error;
6169 6455 nfsstat4 status = NFS4_OK;
6170 6456 vattr_t va;
6171 6457
6172 6458 tryagain:
6173 6459
6174 6460 /*
6175 6461 * The file open mode used is VWRITE. If the client needs
6176 6462 * some other semantic, then it should do the access checking
6177 6463 * itself. It would have been nice to have the file open mode
6178 6464 * passed as part of the arguments.
6179 6465 */
6180 6466
6181 6467 *created = TRUE;
6182 6468 error = VOP_CREATE(dvp, nm, vap, EXCL, VWRITE, vpp, cr, 0, NULL, NULL);
6183 6469
6184 6470 if (error) {
6185 6471 *created = FALSE;
6186 6472
6187 6473 /*
6188 6474 * If we got something other than file already exists
6189 6475 * then just return this error. Otherwise, we got
6190 6476 * EEXIST. If we were doing a GUARDED create, then
6191 6477 * just return this error. Otherwise, we need to
6192 6478 * make sure that this wasn't a duplicate of an
6193 6479 * exclusive create request.
6194 6480 *
6195 6481 * The assumption is made that a non-exclusive create
6196 6482 * request will never return EEXIST.
6197 6483 */
6198 6484
6199 6485 if (error != EEXIST || mode == GUARDED4) {
6200 6486 status = puterrno4(error);
6201 6487 return (status);
6202 6488 }
6203 6489 error = VOP_LOOKUP(dvp, nm, vpp, NULL, 0, NULL, cr,
6204 6490 NULL, NULL, NULL);
6205 6491
6206 6492 if (error) {
6207 6493 /*
6208 6494 * We couldn't find the file that we thought that
6209 6495 * we just created. So, we'll just try creating
6210 6496 * it again.
6211 6497 */
6212 6498 if (error == ENOENT)
6213 6499 goto tryagain;
6214 6500
6215 6501 status = puterrno4(error);
6216 6502 return (status);
6217 6503 }
6218 6504
6219 6505 if (mode == UNCHECKED4) {
6220 6506 /* existing object must be regular file */
6221 6507 if ((*vpp)->v_type != VREG) {
6222 6508 if ((*vpp)->v_type == VDIR)
6223 6509 status = NFS4ERR_ISDIR;
6224 6510 else if ((*vpp)->v_type == VLNK)
6225 6511 status = NFS4ERR_SYMLINK;
6226 6512 else
6227 6513 status = NFS4ERR_INVAL;
6228 6514 VN_RELE(*vpp);
6229 6515 return (status);
6230 6516 }
6231 6517
6232 6518 return (NFS4_OK);
6233 6519 }
6234 6520
6235 6521 /* Check for duplicate request */
6236 6522 va.va_mask = AT_MTIME;
6237 6523 error = VOP_GETATTR(*vpp, &va, 0, cr, NULL);
6238 6524 if (!error) {
6239 6525 /* We found the file */
6240 6526 const timestruc_t *mtime = &vap->va_mtime;
6241 6527
6242 6528 if (va.va_mtime.tv_sec != mtime->tv_sec ||
6243 6529 va.va_mtime.tv_nsec != mtime->tv_nsec) {
6244 6530 /* but its not our creation */
6245 6531 VN_RELE(*vpp);
6246 6532 return (NFS4ERR_EXIST);
6247 6533 }
6248 6534 *created = TRUE; /* retrans of create == created */
6249 6535 return (NFS4_OK);
6250 6536 }
6251 6537 VN_RELE(*vpp);
6252 6538 return (NFS4ERR_EXIST);
6253 6539 }
6254 6540
6255 6541 return (NFS4_OK);
6256 6542 }
6257 6543
6258 6544 static nfsstat4
6259 6545 check_open_access(uint32_t access, struct compound_state *cs,
6260 6546 struct svc_req *req)
6261 6547 {
6262 6548 int error;
6263 6549 vnode_t *vp;
6264 6550 bool_t readonly;
6265 6551 cred_t *cr = cs->cr;
6266 6552
6267 6553 /* For now we don't allow mandatory locking as per V2/V3 */
6268 6554 if (cs->access == CS_ACCESS_DENIED || cs->mandlock) {
6269 6555 return (NFS4ERR_ACCESS);
6270 6556 }
6271 6557
6272 6558 vp = cs->vp;
6273 6559 ASSERT(cr != NULL && vp->v_type == VREG);
6274 6560
6275 6561 /*
6276 6562 * If the file system is exported read only and we are trying
6277 6563 * to open for write, then return NFS4ERR_ROFS
6278 6564 */
6279 6565
6280 6566 readonly = rdonly4(req, cs);
6281 6567
6282 6568 if ((access & OPEN4_SHARE_ACCESS_WRITE) && readonly)
6283 6569 return (NFS4ERR_ROFS);
6284 6570
6285 6571 if (access & OPEN4_SHARE_ACCESS_READ) {
6286 6572 if ((VOP_ACCESS(vp, VREAD, 0, cr, NULL) != 0) &&
6287 6573 (VOP_ACCESS(vp, VEXEC, 0, cr, NULL) != 0)) {
6288 6574 return (NFS4ERR_ACCESS);
6289 6575 }
6290 6576 }
6291 6577
6292 6578 if (access & OPEN4_SHARE_ACCESS_WRITE) {
6293 6579 error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL);
6294 6580 if (error)
6295 6581 return (NFS4ERR_ACCESS);
6296 6582 }
6297 6583
6298 6584 return (NFS4_OK);
6299 6585 }
6300 6586
6301 6587 static nfsstat4
6302 6588 rfs4_createfile(OPEN4args *args, struct svc_req *req, struct compound_state *cs,
6303 6589 change_info4 *cinfo, bitmap4 *attrset, clientid4 clientid)
6304 6590 {
6305 6591 struct nfs4_svgetit_arg sarg;
6306 6592 struct nfs4_ntov_table ntov;
6307 6593
6308 6594 bool_t ntov_table_init = FALSE;
6309 6595 struct statvfs64 sb;
6310 6596 nfsstat4 status;
6311 6597 vnode_t *vp;
6312 6598 vattr_t bva, ava, iva, cva, *vap;
6313 6599 vnode_t *dvp;
6314 6600 timespec32_t *mtime;
6315 6601 char *nm = NULL;
6316 6602 uint_t buflen;
6317 6603 bool_t created;
6318 6604 bool_t setsize = FALSE;
6319 6605 len_t reqsize;
6320 6606 int error;
6321 6607 bool_t trunc;
6322 6608 caller_context_t ct;
6323 6609 component4 *component;
6324 6610 bslabel_t *clabel;
6325 6611 struct sockaddr *ca;
6326 6612 char *name = NULL;
6327 6613
6328 6614 sarg.sbp = &sb;
6329 6615 sarg.is_referral = B_FALSE;
6330 6616
6331 6617 dvp = cs->vp;
6332 6618
6333 6619 /* Check if the file system is read only */
6334 6620 if (rdonly4(req, cs))
6335 6621 return (NFS4ERR_ROFS);
6336 6622
6337 6623 /* check the label of including directory */
6338 6624 if (is_system_labeled()) {
6339 6625 ASSERT(req->rq_label != NULL);
6340 6626 clabel = req->rq_label;
6341 6627 DTRACE_PROBE2(tx__rfs4__log__info__opremove__clabel, char *,
6342 6628 "got client label from request(1)",
6343 6629 struct svc_req *, req);
6344 6630 if (!blequal(&l_admin_low->tsl_label, clabel)) {
6345 6631 if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
6346 6632 cs->exi)) {
6347 6633 return (NFS4ERR_ACCESS);
6348 6634 }
6349 6635 }
6350 6636 }
6351 6637
6352 6638 /*
6353 6639 * Get the last component of path name in nm. cs will reference
6354 6640 * the including directory on success.
6355 6641 */
6356 6642 component = &args->open_claim4_u.file;
6357 6643 status = utf8_dir_verify(component);
6358 6644 if (status != NFS4_OK)
6359 6645 return (status);
6360 6646
6361 6647 nm = utf8_to_fn(component, &buflen, NULL);
6362 6648
6363 6649 if (nm == NULL)
6364 6650 return (NFS4ERR_RESOURCE);
6365 6651
6366 6652 if (buflen > MAXNAMELEN) {
6367 6653 kmem_free(nm, buflen);
6368 6654 return (NFS4ERR_NAMETOOLONG);
6369 6655 }
6370 6656
6371 6657 bva.va_mask = AT_TYPE|AT_CTIME|AT_SEQ;
6372 6658 error = VOP_GETATTR(dvp, &bva, 0, cs->cr, NULL);
6373 6659 if (error) {
6374 6660 kmem_free(nm, buflen);
6375 6661 return (puterrno4(error));
6376 6662 }
6377 6663
6378 6664 if (bva.va_type != VDIR) {
6379 6665 kmem_free(nm, buflen);
6380 6666 return (NFS4ERR_NOTDIR);
6381 6667 }
6382 6668
6383 6669 NFS4_SET_FATTR4_CHANGE(cinfo->before, bva.va_ctime)
6384 6670
6385 6671 switch (args->mode) {
6386 6672 case GUARDED4:
6387 6673 /*FALLTHROUGH*/
6388 6674 case UNCHECKED4:
6389 6675 nfs4_ntov_table_init(&ntov);
6390 6676 ntov_table_init = TRUE;
6391 6677
6392 6678 *attrset = 0;
6393 6679 status = do_rfs4_set_attrs(attrset,
6394 6680 &args->createhow4_u.createattrs,
6395 6681 cs, &sarg, &ntov, NFS4ATTR_SETIT);
6396 6682
6397 6683 if (status == NFS4_OK && (sarg.vap->va_mask & AT_TYPE) &&
6398 6684 sarg.vap->va_type != VREG) {
6399 6685 if (sarg.vap->va_type == VDIR)
6400 6686 status = NFS4ERR_ISDIR;
6401 6687 else if (sarg.vap->va_type == VLNK)
6402 6688 status = NFS4ERR_SYMLINK;
6403 6689 else
6404 6690 status = NFS4ERR_INVAL;
6405 6691 }
6406 6692
6407 6693 if (status != NFS4_OK) {
6408 6694 kmem_free(nm, buflen);
6409 6695 nfs4_ntov_table_free(&ntov, &sarg);
6410 6696 *attrset = 0;
6411 6697 return (status);
6412 6698 }
6413 6699
6414 6700 vap = sarg.vap;
6415 6701 vap->va_type = VREG;
6416 6702 vap->va_mask |= AT_TYPE;
6417 6703
6418 6704 if ((vap->va_mask & AT_MODE) == 0) {
6419 6705 vap->va_mask |= AT_MODE;
6420 6706 vap->va_mode = (mode_t)0600;
6421 6707 }
6422 6708
6423 6709 if (vap->va_mask & AT_SIZE) {
6424 6710
6425 6711 /* Disallow create with a non-zero size */
6426 6712
6427 6713 if ((reqsize = sarg.vap->va_size) != 0) {
6428 6714 kmem_free(nm, buflen);
6429 6715 nfs4_ntov_table_free(&ntov, &sarg);
6430 6716 *attrset = 0;
6431 6717 return (NFS4ERR_INVAL);
6432 6718 }
6433 6719 setsize = TRUE;
6434 6720 }
6435 6721 break;
6436 6722
6437 6723 case EXCLUSIVE4:
6438 6724 /* prohibit EXCL create of named attributes */
6439 6725 if (dvp->v_flag & V_XATTRDIR) {
6440 6726 kmem_free(nm, buflen);
6441 6727 *attrset = 0;
6442 6728 return (NFS4ERR_INVAL);
6443 6729 }
6444 6730
6445 6731 cva.va_mask = AT_TYPE | AT_MTIME | AT_MODE;
6446 6732 cva.va_type = VREG;
6447 6733 /*
6448 6734 * Ensure no time overflows. Assumes underlying
6449 6735 * filesystem supports at least 32 bits.
6450 6736 * Truncate nsec to usec resolution to allow valid
6451 6737 * compares even if the underlying filesystem truncates.
6452 6738 */
6453 6739 mtime = (timespec32_t *)&args->createhow4_u.createverf;
6454 6740 cva.va_mtime.tv_sec = mtime->tv_sec % TIME32_MAX;
6455 6741 cva.va_mtime.tv_nsec = (mtime->tv_nsec / 1000) * 1000;
6456 6742 cva.va_mode = (mode_t)0;
6457 6743 vap = &cva;
6458 6744
6459 6745 /*
6460 6746 * For EXCL create, attrset is set to the server attr
6461 6747 * used to cache the client's verifier.
6462 6748 */
6463 6749 *attrset = FATTR4_TIME_MODIFY_MASK;
6464 6750 break;
6465 6751 }
6466 6752
6467 6753 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
6468 6754 name = nfscmd_convname(ca, cs->exi, nm, NFSCMD_CONV_INBOUND,
6469 6755 MAXPATHLEN + 1);
6470 6756
6471 6757 if (name == NULL) {
6472 6758 kmem_free(nm, buflen);
6473 6759 return (NFS4ERR_SERVERFAULT);
6474 6760 }
6475 6761
6476 6762 status = create_vnode(dvp, name, vap, args->mode,
6477 6763 cs->cr, &vp, &created);
6478 6764 if (nm != name)
6479 6765 kmem_free(name, MAXPATHLEN + 1);
6480 6766 kmem_free(nm, buflen);
6481 6767
6482 6768 if (status != NFS4_OK) {
6483 6769 if (ntov_table_init)
6484 6770 nfs4_ntov_table_free(&ntov, &sarg);
6485 6771 *attrset = 0;
6486 6772 return (status);
6487 6773 }
6488 6774
6489 6775 trunc = (setsize && !created);
6490 6776
6491 6777 if (args->mode != EXCLUSIVE4) {
6492 6778 bitmap4 createmask = args->createhow4_u.createattrs.attrmask;
6493 6779
6494 6780 /*
6495 6781 * True verification that object was created with correct
6496 6782 * attrs is impossible. The attrs could have been changed
6497 6783 * immediately after object creation. If attributes did
6498 6784 * not verify, the only recourse for the server is to
6499 6785 * destroy the object. Maybe if some attrs (like gid)
6500 6786 * are set incorrectly, the object should be destroyed;
6501 6787 * however, seems bad as a default policy. Do we really
6502 6788 * want to destroy an object over one of the times not
6503 6789 * verifying correctly? For these reasons, the server
6504 6790 * currently sets bits in attrset for createattrs
6505 6791 * that were set; however, no verification is done.
6506 6792 *
6507 6793 * vmask_to_nmask accounts for vattr bits set on create
6508 6794 * [do_rfs4_set_attrs() only sets resp bits for
6509 6795 * non-vattr/vfs bits.]
6510 6796 * Mask off any bits we set by default so as not to return
6511 6797 * more attrset bits than were requested in createattrs
6512 6798 */
6513 6799 if (created) {
6514 6800 nfs4_vmask_to_nmask(sarg.vap->va_mask, attrset);
6515 6801 *attrset &= createmask;
6516 6802 } else {
6517 6803 /*
6518 6804 * We did not create the vnode (we tried but it
6519 6805 * already existed). In this case, the only createattr
6520 6806 * that the spec allows the server to set is size,
6521 6807 * and even then, it can only be set if it is 0.
6522 6808 */
6523 6809 *attrset = 0;
6524 6810 if (trunc)
6525 6811 *attrset = FATTR4_SIZE_MASK;
6526 6812 }
6527 6813 }
6528 6814 if (ntov_table_init)
6529 6815 nfs4_ntov_table_free(&ntov, &sarg);
6530 6816
6531 6817 /*
6532 6818 * Get the initial "after" sequence number, if it fails,
6533 6819 * set to zero, time to before.
6534 6820 */
6535 6821 iva.va_mask = AT_CTIME|AT_SEQ;
6536 6822 if (VOP_GETATTR(dvp, &iva, 0, cs->cr, NULL)) {
6537 6823 iva.va_seq = 0;
6538 6824 iva.va_ctime = bva.va_ctime;
6539 6825 }
6540 6826
6541 6827 /*
6542 6828 * create_vnode attempts to create the file exclusive,
6543 6829 * if it already exists the VOP_CREATE will fail and
6544 6830 * may not increase va_seq. It is atomic if
6545 6831 * we haven't changed the directory, but if it has changed
6546 6832 * we don't know what changed it.
6547 6833 */
6548 6834 if (!created) {
6549 6835 if (bva.va_seq && iva.va_seq &&
6550 6836 bva.va_seq == iva.va_seq)
6551 6837 cinfo->atomic = TRUE;
6552 6838 else
6553 6839 cinfo->atomic = FALSE;
6554 6840 NFS4_SET_FATTR4_CHANGE(cinfo->after, iva.va_ctime);
6555 6841 } else {
6556 6842 /*
6557 6843 * The entry was created, we need to sync the
6558 6844 * directory metadata.
6559 6845 */
6560 6846 (void) VOP_FSYNC(dvp, 0, cs->cr, NULL);
6561 6847
6562 6848 /*
6563 6849 * Get "after" change value, if it fails, simply return the
6564 6850 * before value.
6565 6851 */
6566 6852 ava.va_mask = AT_CTIME|AT_SEQ;
6567 6853 if (VOP_GETATTR(dvp, &ava, 0, cs->cr, NULL)) {
6568 6854 ava.va_ctime = bva.va_ctime;
6569 6855 ava.va_seq = 0;
6570 6856 }
6571 6857
6572 6858 NFS4_SET_FATTR4_CHANGE(cinfo->after, ava.va_ctime);
6573 6859
6574 6860 /*
6575 6861 * The cinfo->atomic = TRUE only if we have
6576 6862 * non-zero va_seq's, and it has incremented by exactly one
6577 6863 * during the create_vnode and it didn't
6578 6864 * change during the VOP_FSYNC.
6579 6865 */
6580 6866 if (bva.va_seq && iva.va_seq && ava.va_seq &&
6581 6867 iva.va_seq == (bva.va_seq + 1) && iva.va_seq == ava.va_seq)
6582 6868 cinfo->atomic = TRUE;
6583 6869 else
6584 6870 cinfo->atomic = FALSE;
6585 6871 }
6586 6872
6587 6873 /* Check for mandatory locking and that the size gets set. */
6588 6874 cva.va_mask = AT_MODE;
6589 6875 if (setsize)
6590 6876 cva.va_mask |= AT_SIZE;
6591 6877
6592 6878 /* Assume the worst */
6593 6879 cs->mandlock = TRUE;
6594 6880
6595 6881 if (VOP_GETATTR(vp, &cva, 0, cs->cr, NULL) == 0) {
|
↓ open down ↓ |
614 lines elided |
↑ open up ↑ |
6596 6882 cs->mandlock = MANDLOCK(cs->vp, cva.va_mode);
6597 6883
6598 6884 /*
6599 6885 * Truncate the file if necessary; this would be
6600 6886 * the case for create over an existing file.
6601 6887 */
6602 6888
6603 6889 if (trunc) {
6604 6890 int in_crit = 0;
6605 6891 rfs4_file_t *fp;
6892 + nfs4_srv_t *nsrv4;
6606 6893 bool_t create = FALSE;
6607 6894
6608 6895 /*
6609 6896 * We are writing over an existing file.
6610 6897 * Check to see if we need to recall a delegation.
6611 6898 */
6612 - rfs4_hold_deleg_policy();
6899 + nsrv4 = zone_getspecific(rfs4_zone_key, curzone);
6900 + rfs4_hold_deleg_policy(nsrv4);
6613 6901 if ((fp = rfs4_findfile(vp, NULL, &create)) != NULL) {
6614 6902 if (rfs4_check_delegated_byfp(FWRITE, fp,
6615 6903 (reqsize == 0), FALSE, FALSE, &clientid)) {
6616 6904 rfs4_file_rele(fp);
6617 - rfs4_rele_deleg_policy();
6905 + rfs4_rele_deleg_policy(nsrv4);
6618 6906 VN_RELE(vp);
6619 6907 *attrset = 0;
6620 6908 return (NFS4ERR_DELAY);
6621 6909 }
6622 6910 rfs4_file_rele(fp);
6623 6911 }
6624 - rfs4_rele_deleg_policy();
6912 + rfs4_rele_deleg_policy(nsrv4);
6625 6913
6626 6914 if (nbl_need_check(vp)) {
6627 6915 in_crit = 1;
6628 6916
6629 6917 ASSERT(reqsize == 0);
6630 6918
6631 6919 nbl_start_crit(vp, RW_READER);
6632 6920 if (nbl_conflict(vp, NBL_WRITE, 0,
6633 6921 cva.va_size, 0, NULL)) {
6634 6922 in_crit = 0;
6635 6923 nbl_end_crit(vp);
6636 6924 VN_RELE(vp);
6637 6925 *attrset = 0;
6638 6926 return (NFS4ERR_ACCESS);
6639 6927 }
6640 6928 }
6641 6929 ct.cc_sysid = 0;
6642 6930 ct.cc_pid = 0;
6643 6931 ct.cc_caller_id = nfs4_srv_caller_id;
6644 6932 ct.cc_flags = CC_DONTBLOCK;
6645 6933
6646 6934 cva.va_mask = AT_SIZE;
6647 6935 cva.va_size = reqsize;
6648 6936 (void) VOP_SETATTR(vp, &cva, 0, cs->cr, &ct);
6649 6937 if (in_crit)
6650 6938 nbl_end_crit(vp);
6651 6939 }
6652 6940 }
6653 6941
6654 6942 error = makefh4(&cs->fh, vp, cs->exi);
6655 6943
6656 6944 /*
6657 6945 * Force modified data and metadata out to stable storage.
6658 6946 */
6659 6947 (void) VOP_FSYNC(vp, FNODSYNC, cs->cr, NULL);
6660 6948
6661 6949 if (error) {
6662 6950 VN_RELE(vp);
6663 6951 *attrset = 0;
6664 6952 return (puterrno4(error));
6665 6953 }
6666 6954
6667 6955 /* if parent dir is attrdir, set namedattr fh flag */
6668 6956 if (dvp->v_flag & V_XATTRDIR)
6669 6957 set_fh4_flag(&cs->fh, FH4_NAMEDATTR);
6670 6958
6671 6959 if (cs->vp)
6672 6960 VN_RELE(cs->vp);
6673 6961
6674 6962 cs->vp = vp;
6675 6963
6676 6964 /*
6677 6965 * if we did not create the file, we will need to check
6678 6966 * the access bits on the file
6679 6967 */
6680 6968
6681 6969 if (!created) {
6682 6970 if (setsize)
6683 6971 args->share_access |= OPEN4_SHARE_ACCESS_WRITE;
6684 6972 status = check_open_access(args->share_access, cs, req);
6685 6973 if (status != NFS4_OK)
6686 6974 *attrset = 0;
6687 6975 }
6688 6976 return (status);
6689 6977 }
6690 6978
6691 6979 /*ARGSUSED*/
6692 6980 static void
6693 6981 rfs4_do_open(struct compound_state *cs, struct svc_req *req,
6694 6982 rfs4_openowner_t *oo, delegreq_t deleg,
6695 6983 uint32_t access, uint32_t deny,
6696 6984 OPEN4res *resp, int deleg_cur)
6697 6985 {
6698 6986 /* XXX Currently not using req */
6699 6987 rfs4_state_t *sp;
6700 6988 rfs4_file_t *fp;
6701 6989 bool_t screate = TRUE;
6702 6990 bool_t fcreate = TRUE;
6703 6991 uint32_t open_a, share_a;
6704 6992 uint32_t open_d, share_d;
6705 6993 rfs4_deleg_state_t *dsp;
6706 6994 sysid_t sysid;
6707 6995 nfsstat4 status;
6708 6996 caller_context_t ct;
6709 6997 int fflags = 0;
6710 6998 int recall = 0;
6711 6999 int err;
6712 7000 int first_open;
6713 7001
6714 7002 /* get the file struct and hold a lock on it during initial open */
6715 7003 fp = rfs4_findfile_withlock(cs->vp, &cs->fh, &fcreate);
6716 7004 if (fp == NULL) {
6717 7005 resp->status = NFS4ERR_RESOURCE;
6718 7006 DTRACE_PROBE1(nfss__e__do__open1, nfsstat4, resp->status);
6719 7007 return;
6720 7008 }
6721 7009
6722 7010 sp = rfs4_findstate_by_owner_file(oo, fp, &screate);
6723 7011 if (sp == NULL) {
6724 7012 resp->status = NFS4ERR_RESOURCE;
6725 7013 DTRACE_PROBE1(nfss__e__do__open2, nfsstat4, resp->status);
6726 7014 /* No need to keep any reference */
6727 7015 rw_exit(&fp->rf_file_rwlock);
6728 7016 rfs4_file_rele(fp);
6729 7017 return;
6730 7018 }
6731 7019
6732 7020 /* try to get the sysid before continuing */
6733 7021 if ((status = rfs4_client_sysid(oo->ro_client, &sysid)) != NFS4_OK) {
6734 7022 resp->status = status;
6735 7023 rfs4_file_rele(fp);
6736 7024 /* Not a fully formed open; "close" it */
6737 7025 if (screate == TRUE)
6738 7026 rfs4_state_close(sp, FALSE, FALSE, cs->cr);
6739 7027 rfs4_state_rele(sp);
6740 7028 return;
6741 7029 }
6742 7030
6743 7031 /* Calculate the fflags for this OPEN. */
6744 7032 if (access & OPEN4_SHARE_ACCESS_READ)
6745 7033 fflags |= FREAD;
6746 7034 if (access & OPEN4_SHARE_ACCESS_WRITE)
6747 7035 fflags |= FWRITE;
6748 7036
6749 7037 rfs4_dbe_lock(sp->rs_dbe);
6750 7038
6751 7039 /*
6752 7040 * Calculate the new deny and access mode that this open is adding to
6753 7041 * the file for this open owner;
6754 7042 */
6755 7043 open_d = (deny & ~sp->rs_open_deny);
6756 7044 open_a = (access & ~sp->rs_open_access);
6757 7045
6758 7046 /*
6759 7047 * Calculate the new share access and share deny modes that this open
6760 7048 * is adding to the file for this open owner;
6761 7049 */
6762 7050 share_a = (access & ~sp->rs_share_access);
6763 7051 share_d = (deny & ~sp->rs_share_deny);
6764 7052
6765 7053 first_open = (sp->rs_open_access & OPEN4_SHARE_ACCESS_BOTH) == 0;
6766 7054
6767 7055 /*
6768 7056 * Check to see the client has already sent an open for this
6769 7057 * open owner on this file with the same share/deny modes.
6770 7058 * If so, we don't need to check for a conflict and we don't
6771 7059 * need to add another shrlock. If not, then we need to
6772 7060 * check for conflicts in deny and access before checking for
6773 7061 * conflicts in delegation. We don't want to recall a
6774 7062 * delegation based on an open that will eventually fail based
6775 7063 * on shares modes.
6776 7064 */
6777 7065
6778 7066 if (share_a || share_d) {
6779 7067 if ((err = rfs4_share(sp, access, deny)) != 0) {
6780 7068 rfs4_dbe_unlock(sp->rs_dbe);
6781 7069 resp->status = err;
6782 7070
6783 7071 rfs4_file_rele(fp);
6784 7072 /* Not a fully formed open; "close" it */
6785 7073 if (screate == TRUE)
6786 7074 rfs4_state_close(sp, FALSE, FALSE, cs->cr);
6787 7075 rfs4_state_rele(sp);
6788 7076 return;
6789 7077 }
6790 7078 }
6791 7079
6792 7080 rfs4_dbe_lock(fp->rf_dbe);
6793 7081
6794 7082 /*
6795 7083 * Check to see if this file is delegated and if so, if a
6796 7084 * recall needs to be done.
6797 7085 */
6798 7086 if (rfs4_check_recall(sp, access)) {
6799 7087 rfs4_dbe_unlock(fp->rf_dbe);
6800 7088 rfs4_dbe_unlock(sp->rs_dbe);
6801 7089 rfs4_recall_deleg(fp, FALSE, sp->rs_owner->ro_client);
6802 7090 delay(NFS4_DELEGATION_CONFLICT_DELAY);
6803 7091 rfs4_dbe_lock(sp->rs_dbe);
6804 7092
6805 7093 /* if state closed while lock was dropped */
6806 7094 if (sp->rs_closed) {
6807 7095 if (share_a || share_d)
6808 7096 (void) rfs4_unshare(sp);
6809 7097 rfs4_dbe_unlock(sp->rs_dbe);
6810 7098 rfs4_file_rele(fp);
6811 7099 /* Not a fully formed open; "close" it */
6812 7100 if (screate == TRUE)
6813 7101 rfs4_state_close(sp, FALSE, FALSE, cs->cr);
6814 7102 rfs4_state_rele(sp);
6815 7103 resp->status = NFS4ERR_OLD_STATEID;
6816 7104 return;
6817 7105 }
6818 7106
6819 7107 rfs4_dbe_lock(fp->rf_dbe);
6820 7108 /* Let's see if the delegation was returned */
6821 7109 if (rfs4_check_recall(sp, access)) {
6822 7110 rfs4_dbe_unlock(fp->rf_dbe);
6823 7111 if (share_a || share_d)
6824 7112 (void) rfs4_unshare(sp);
6825 7113 rfs4_dbe_unlock(sp->rs_dbe);
6826 7114 rfs4_file_rele(fp);
6827 7115 rfs4_update_lease(sp->rs_owner->ro_client);
6828 7116
6829 7117 /* Not a fully formed open; "close" it */
6830 7118 if (screate == TRUE)
6831 7119 rfs4_state_close(sp, FALSE, FALSE, cs->cr);
6832 7120 rfs4_state_rele(sp);
6833 7121 resp->status = NFS4ERR_DELAY;
6834 7122 return;
6835 7123 }
6836 7124 }
6837 7125 /*
6838 7126 * the share check passed and any delegation conflict has been
6839 7127 * taken care of, now call vop_open.
6840 7128 * if this is the first open then call vop_open with fflags.
6841 7129 * if not, call vn_open_upgrade with just the upgrade flags.
6842 7130 *
6843 7131 * if the file has been opened already, it will have the current
6844 7132 * access mode in the state struct. if it has no share access, then
6845 7133 * this is a new open.
6846 7134 *
6847 7135 * However, if this is open with CLAIM_DLEGATE_CUR, then don't
6848 7136 * call VOP_OPEN(), just do the open upgrade.
6849 7137 */
6850 7138 if (first_open && !deleg_cur) {
6851 7139 ct.cc_sysid = sysid;
6852 7140 ct.cc_pid = rfs4_dbe_getid(sp->rs_owner->ro_dbe);
6853 7141 ct.cc_caller_id = nfs4_srv_caller_id;
6854 7142 ct.cc_flags = CC_DONTBLOCK;
6855 7143 err = VOP_OPEN(&cs->vp, fflags, cs->cr, &ct);
6856 7144 if (err) {
6857 7145 rfs4_dbe_unlock(fp->rf_dbe);
6858 7146 if (share_a || share_d)
6859 7147 (void) rfs4_unshare(sp);
6860 7148 rfs4_dbe_unlock(sp->rs_dbe);
6861 7149 rfs4_file_rele(fp);
6862 7150
6863 7151 /* Not a fully formed open; "close" it */
6864 7152 if (screate == TRUE)
6865 7153 rfs4_state_close(sp, FALSE, FALSE, cs->cr);
6866 7154 rfs4_state_rele(sp);
6867 7155 /* check if a monitor detected a delegation conflict */
6868 7156 if (err == EAGAIN && (ct.cc_flags & CC_WOULDBLOCK))
6869 7157 resp->status = NFS4ERR_DELAY;
6870 7158 else
6871 7159 resp->status = NFS4ERR_SERVERFAULT;
6872 7160 return;
6873 7161 }
6874 7162 } else { /* open upgrade */
6875 7163 /*
6876 7164 * calculate the fflags for the new mode that is being added
6877 7165 * by this upgrade.
6878 7166 */
6879 7167 fflags = 0;
6880 7168 if (open_a & OPEN4_SHARE_ACCESS_READ)
6881 7169 fflags |= FREAD;
6882 7170 if (open_a & OPEN4_SHARE_ACCESS_WRITE)
6883 7171 fflags |= FWRITE;
6884 7172 vn_open_upgrade(cs->vp, fflags);
6885 7173 }
6886 7174 sp->rs_open_access |= access;
6887 7175 sp->rs_open_deny |= deny;
6888 7176
6889 7177 if (open_d & OPEN4_SHARE_DENY_READ)
6890 7178 fp->rf_deny_read++;
6891 7179 if (open_d & OPEN4_SHARE_DENY_WRITE)
6892 7180 fp->rf_deny_write++;
6893 7181 fp->rf_share_deny |= deny;
6894 7182
6895 7183 if (open_a & OPEN4_SHARE_ACCESS_READ)
6896 7184 fp->rf_access_read++;
6897 7185 if (open_a & OPEN4_SHARE_ACCESS_WRITE)
6898 7186 fp->rf_access_write++;
6899 7187 fp->rf_share_access |= access;
6900 7188
6901 7189 /*
6902 7190 * Check for delegation here. if the deleg argument is not
6903 7191 * DELEG_ANY, then this is a reclaim from a client and
6904 7192 * we must honor the delegation requested. If necessary we can
6905 7193 * set the recall flag.
6906 7194 */
6907 7195
6908 7196 dsp = rfs4_grant_delegation(deleg, sp, &recall);
6909 7197
6910 7198 cs->deleg = (fp->rf_dinfo.rd_dtype == OPEN_DELEGATE_WRITE);
6911 7199
6912 7200 next_stateid(&sp->rs_stateid);
6913 7201
6914 7202 resp->stateid = sp->rs_stateid.stateid;
6915 7203
6916 7204 rfs4_dbe_unlock(fp->rf_dbe);
6917 7205 rfs4_dbe_unlock(sp->rs_dbe);
6918 7206
6919 7207 if (dsp) {
6920 7208 rfs4_set_deleg_response(dsp, &resp->delegation, NULL, recall);
6921 7209 rfs4_deleg_state_rele(dsp);
6922 7210 }
6923 7211
6924 7212 rfs4_file_rele(fp);
6925 7213 rfs4_state_rele(sp);
6926 7214
6927 7215 resp->status = NFS4_OK;
6928 7216 }
6929 7217
6930 7218 /*ARGSUSED*/
6931 7219 static void
6932 7220 rfs4_do_opennull(struct compound_state *cs, struct svc_req *req,
6933 7221 OPEN4args *args, rfs4_openowner_t *oo, OPEN4res *resp)
6934 7222 {
6935 7223 change_info4 *cinfo = &resp->cinfo;
6936 7224 bitmap4 *attrset = &resp->attrset;
6937 7225
6938 7226 if (args->opentype == OPEN4_NOCREATE)
6939 7227 resp->status = rfs4_lookupfile(&args->open_claim4_u.file,
6940 7228 req, cs, args->share_access, cinfo);
6941 7229 else {
6942 7230 /* inhibit delegation grants during exclusive create */
6943 7231
6944 7232 if (args->mode == EXCLUSIVE4)
6945 7233 rfs4_disable_delegation();
6946 7234
6947 7235 resp->status = rfs4_createfile(args, req, cs, cinfo, attrset,
6948 7236 oo->ro_client->rc_clientid);
6949 7237 }
6950 7238
6951 7239 if (resp->status == NFS4_OK) {
6952 7240
6953 7241 /* cs->vp cs->fh now reference the desired file */
6954 7242
6955 7243 rfs4_do_open(cs, req, oo,
6956 7244 oo->ro_need_confirm ? DELEG_NONE : DELEG_ANY,
6957 7245 args->share_access, args->share_deny, resp, 0);
6958 7246
6959 7247 /*
6960 7248 * If rfs4_createfile set attrset, we must
6961 7249 * clear this attrset before the response is copied.
6962 7250 */
6963 7251 if (resp->status != NFS4_OK && resp->attrset) {
6964 7252 resp->attrset = 0;
6965 7253 }
6966 7254 }
6967 7255 else
6968 7256 *cs->statusp = resp->status;
6969 7257
6970 7258 if (args->mode == EXCLUSIVE4)
6971 7259 rfs4_enable_delegation();
6972 7260 }
6973 7261
6974 7262 /*ARGSUSED*/
6975 7263 static void
6976 7264 rfs4_do_openprev(struct compound_state *cs, struct svc_req *req,
6977 7265 OPEN4args *args, rfs4_openowner_t *oo, OPEN4res *resp)
6978 7266 {
6979 7267 change_info4 *cinfo = &resp->cinfo;
6980 7268 vattr_t va;
6981 7269 vtype_t v_type = cs->vp->v_type;
6982 7270 int error = 0;
6983 7271
6984 7272 /* Verify that we have a regular file */
6985 7273 if (v_type != VREG) {
6986 7274 if (v_type == VDIR)
6987 7275 resp->status = NFS4ERR_ISDIR;
6988 7276 else if (v_type == VLNK)
6989 7277 resp->status = NFS4ERR_SYMLINK;
6990 7278 else
6991 7279 resp->status = NFS4ERR_INVAL;
6992 7280 return;
6993 7281 }
6994 7282
6995 7283 va.va_mask = AT_MODE|AT_UID;
6996 7284 error = VOP_GETATTR(cs->vp, &va, 0, cs->cr, NULL);
6997 7285 if (error) {
6998 7286 resp->status = puterrno4(error);
6999 7287 return;
7000 7288 }
7001 7289
7002 7290 cs->mandlock = MANDLOCK(cs->vp, va.va_mode);
7003 7291
7004 7292 /*
7005 7293 * Check if we have access to the file, Note the the file
7006 7294 * could have originally been open UNCHECKED or GUARDED
7007 7295 * with mode bits that will now fail, but there is nothing
7008 7296 * we can really do about that except in the case that the
7009 7297 * owner of the file is the one requesting the open.
7010 7298 */
7011 7299 if (crgetuid(cs->cr) != va.va_uid) {
7012 7300 resp->status = check_open_access(args->share_access, cs, req);
7013 7301 if (resp->status != NFS4_OK) {
7014 7302 return;
7015 7303 }
7016 7304 }
7017 7305
7018 7306 /*
7019 7307 * cinfo on a CLAIM_PREVIOUS is undefined, initialize to zero
7020 7308 */
7021 7309 cinfo->before = 0;
7022 7310 cinfo->after = 0;
7023 7311 cinfo->atomic = FALSE;
7024 7312
7025 7313 rfs4_do_open(cs, req, oo,
7026 7314 NFS4_DELEG4TYPE2REQTYPE(args->open_claim4_u.delegate_type),
7027 7315 args->share_access, args->share_deny, resp, 0);
7028 7316 }
7029 7317
7030 7318 static void
7031 7319 rfs4_do_opendelcur(struct compound_state *cs, struct svc_req *req,
7032 7320 OPEN4args *args, rfs4_openowner_t *oo, OPEN4res *resp)
7033 7321 {
7034 7322 int error;
7035 7323 nfsstat4 status;
7036 7324 stateid4 stateid =
7037 7325 args->open_claim4_u.delegate_cur_info.delegate_stateid;
7038 7326 rfs4_deleg_state_t *dsp;
7039 7327
7040 7328 /*
7041 7329 * Find the state info from the stateid and confirm that the
7042 7330 * file is delegated. If the state openowner is the same as
7043 7331 * the supplied openowner we're done. If not, get the file
7044 7332 * info from the found state info. Use that file info to
7045 7333 * create the state for this lock owner. Note solaris doen't
7046 7334 * really need the pathname to find the file. We may want to
7047 7335 * lookup the pathname and make sure that the vp exist and
7048 7336 * matches the vp in the file structure. However it is
7049 7337 * possible that the pathname nolonger exists (local process
7050 7338 * unlinks the file), so this may not be that useful.
7051 7339 */
7052 7340
7053 7341 status = rfs4_get_deleg_state(&stateid, &dsp);
7054 7342 if (status != NFS4_OK) {
7055 7343 resp->status = status;
7056 7344 return;
7057 7345 }
7058 7346
7059 7347 ASSERT(dsp->rds_finfo->rf_dinfo.rd_dtype != OPEN_DELEGATE_NONE);
7060 7348
7061 7349 /*
7062 7350 * New lock owner, create state. Since this was probably called
7063 7351 * in response to a CB_RECALL we set deleg to DELEG_NONE
7064 7352 */
7065 7353
7066 7354 ASSERT(cs->vp != NULL);
7067 7355 VN_RELE(cs->vp);
7068 7356 VN_HOLD(dsp->rds_finfo->rf_vp);
7069 7357 cs->vp = dsp->rds_finfo->rf_vp;
7070 7358
7071 7359 if (error = makefh4(&cs->fh, cs->vp, cs->exi)) {
7072 7360 rfs4_deleg_state_rele(dsp);
7073 7361 *cs->statusp = resp->status = puterrno4(error);
7074 7362 return;
7075 7363 }
7076 7364
7077 7365 /* Mark progress for delegation returns */
7078 7366 dsp->rds_finfo->rf_dinfo.rd_time_lastwrite = gethrestime_sec();
7079 7367 rfs4_deleg_state_rele(dsp);
7080 7368 rfs4_do_open(cs, req, oo, DELEG_NONE,
7081 7369 args->share_access, args->share_deny, resp, 1);
7082 7370 }
7083 7371
7084 7372 /*ARGSUSED*/
7085 7373 static void
7086 7374 rfs4_do_opendelprev(struct compound_state *cs, struct svc_req *req,
7087 7375 OPEN4args *args, rfs4_openowner_t *oo, OPEN4res *resp)
7088 7376 {
7089 7377 /*
7090 7378 * Lookup the pathname, it must already exist since this file
7091 7379 * was delegated.
7092 7380 *
7093 7381 * Find the file and state info for this vp and open owner pair.
7094 7382 * check that they are in fact delegated.
7095 7383 * check that the state access and deny modes are the same.
7096 7384 *
7097 7385 * Return the delgation possibly seting the recall flag.
7098 7386 */
7099 7387 rfs4_file_t *fp;
7100 7388 rfs4_state_t *sp;
7101 7389 bool_t create = FALSE;
7102 7390 bool_t dcreate = FALSE;
7103 7391 rfs4_deleg_state_t *dsp;
7104 7392 nfsace4 *ace;
7105 7393
7106 7394 /* Note we ignore oflags */
7107 7395 resp->status = rfs4_lookupfile(&args->open_claim4_u.file_delegate_prev,
7108 7396 req, cs, args->share_access, &resp->cinfo);
7109 7397
7110 7398 if (resp->status != NFS4_OK) {
7111 7399 return;
7112 7400 }
7113 7401
7114 7402 /* get the file struct and hold a lock on it during initial open */
7115 7403 fp = rfs4_findfile_withlock(cs->vp, NULL, &create);
7116 7404 if (fp == NULL) {
7117 7405 resp->status = NFS4ERR_RESOURCE;
7118 7406 DTRACE_PROBE1(nfss__e__do_opendelprev1, nfsstat4, resp->status);
7119 7407 return;
7120 7408 }
7121 7409
7122 7410 sp = rfs4_findstate_by_owner_file(oo, fp, &create);
7123 7411 if (sp == NULL) {
7124 7412 resp->status = NFS4ERR_SERVERFAULT;
7125 7413 DTRACE_PROBE1(nfss__e__do_opendelprev2, nfsstat4, resp->status);
7126 7414 rw_exit(&fp->rf_file_rwlock);
7127 7415 rfs4_file_rele(fp);
7128 7416 return;
7129 7417 }
7130 7418
7131 7419 rfs4_dbe_lock(sp->rs_dbe);
7132 7420 rfs4_dbe_lock(fp->rf_dbe);
7133 7421 if (args->share_access != sp->rs_share_access ||
7134 7422 args->share_deny != sp->rs_share_deny ||
7135 7423 sp->rs_finfo->rf_dinfo.rd_dtype == OPEN_DELEGATE_NONE) {
7136 7424 NFS4_DEBUG(rfs4_debug,
7137 7425 (CE_NOTE, "rfs4_do_opendelprev: state mixup"));
7138 7426 rfs4_dbe_unlock(fp->rf_dbe);
7139 7427 rfs4_dbe_unlock(sp->rs_dbe);
7140 7428 rfs4_file_rele(fp);
7141 7429 rfs4_state_rele(sp);
7142 7430 resp->status = NFS4ERR_SERVERFAULT;
7143 7431 return;
7144 7432 }
7145 7433 rfs4_dbe_unlock(fp->rf_dbe);
7146 7434 rfs4_dbe_unlock(sp->rs_dbe);
7147 7435
7148 7436 dsp = rfs4_finddeleg(sp, &dcreate);
7149 7437 if (dsp == NULL) {
7150 7438 rfs4_state_rele(sp);
7151 7439 rfs4_file_rele(fp);
7152 7440 resp->status = NFS4ERR_SERVERFAULT;
7153 7441 return;
7154 7442 }
7155 7443
7156 7444 next_stateid(&sp->rs_stateid);
7157 7445
7158 7446 resp->stateid = sp->rs_stateid.stateid;
7159 7447
7160 7448 resp->delegation.delegation_type = dsp->rds_dtype;
7161 7449
7162 7450 if (dsp->rds_dtype == OPEN_DELEGATE_READ) {
7163 7451 open_read_delegation4 *rv =
7164 7452 &resp->delegation.open_delegation4_u.read;
7165 7453
7166 7454 rv->stateid = dsp->rds_delegid.stateid;
7167 7455 rv->recall = FALSE; /* no policy in place to set to TRUE */
7168 7456 ace = &rv->permissions;
7169 7457 } else {
7170 7458 open_write_delegation4 *rv =
7171 7459 &resp->delegation.open_delegation4_u.write;
7172 7460
7173 7461 rv->stateid = dsp->rds_delegid.stateid;
7174 7462 rv->recall = FALSE; /* no policy in place to set to TRUE */
7175 7463 ace = &rv->permissions;
7176 7464 rv->space_limit.limitby = NFS_LIMIT_SIZE;
7177 7465 rv->space_limit.nfs_space_limit4_u.filesize = UINT64_MAX;
7178 7466 }
7179 7467
7180 7468 /* XXX For now */
7181 7469 ace->type = ACE4_ACCESS_ALLOWED_ACE_TYPE;
7182 7470 ace->flag = 0;
7183 7471 ace->access_mask = 0;
7184 7472 ace->who.utf8string_len = 0;
7185 7473 ace->who.utf8string_val = 0;
7186 7474
7187 7475 rfs4_deleg_state_rele(dsp);
7188 7476 rfs4_state_rele(sp);
7189 7477 rfs4_file_rele(fp);
7190 7478 }
7191 7479
7192 7480 typedef enum {
7193 7481 NFS4_CHKSEQ_OKAY = 0,
7194 7482 NFS4_CHKSEQ_REPLAY = 1,
7195 7483 NFS4_CHKSEQ_BAD = 2
7196 7484 } rfs4_chkseq_t;
7197 7485
7198 7486 /*
7199 7487 * Generic function for sequence number checks.
7200 7488 */
7201 7489 static rfs4_chkseq_t
7202 7490 rfs4_check_seqid(seqid4 seqid, nfs_resop4 *lastop,
7203 7491 seqid4 rqst_seq, nfs_resop4 *resop, bool_t copyres)
7204 7492 {
7205 7493 /* Same sequence ids and matching operations? */
7206 7494 if (seqid == rqst_seq && resop->resop == lastop->resop) {
7207 7495 if (copyres == TRUE) {
7208 7496 rfs4_free_reply(resop);
7209 7497 rfs4_copy_reply(resop, lastop);
7210 7498 }
7211 7499 NFS4_DEBUG(rfs4_debug, (CE_NOTE,
7212 7500 "Replayed SEQID %d\n", seqid));
7213 7501 return (NFS4_CHKSEQ_REPLAY);
7214 7502 }
7215 7503
7216 7504 /* If the incoming sequence is not the next expected then it is bad */
7217 7505 if (rqst_seq != seqid + 1) {
7218 7506 if (rqst_seq == seqid) {
7219 7507 NFS4_DEBUG(rfs4_debug,
7220 7508 (CE_NOTE, "BAD SEQID: Replayed sequence id "
7221 7509 "but last op was %d current op is %d\n",
7222 7510 lastop->resop, resop->resop));
7223 7511 return (NFS4_CHKSEQ_BAD);
7224 7512 }
7225 7513 NFS4_DEBUG(rfs4_debug,
7226 7514 (CE_NOTE, "BAD SEQID: got %u expecting %u\n",
7227 7515 rqst_seq, seqid));
7228 7516 return (NFS4_CHKSEQ_BAD);
7229 7517 }
7230 7518
7231 7519 /* Everything okay -- next expected */
7232 7520 return (NFS4_CHKSEQ_OKAY);
7233 7521 }
7234 7522
7235 7523
7236 7524 static rfs4_chkseq_t
7237 7525 rfs4_check_open_seqid(seqid4 seqid, rfs4_openowner_t *op, nfs_resop4 *resop)
7238 7526 {
7239 7527 rfs4_chkseq_t rc;
7240 7528
7241 7529 rfs4_dbe_lock(op->ro_dbe);
7242 7530 rc = rfs4_check_seqid(op->ro_open_seqid, &op->ro_reply, seqid, resop,
7243 7531 TRUE);
7244 7532 rfs4_dbe_unlock(op->ro_dbe);
7245 7533
7246 7534 if (rc == NFS4_CHKSEQ_OKAY)
7247 7535 rfs4_update_lease(op->ro_client);
7248 7536
7249 7537 return (rc);
7250 7538 }
7251 7539
7252 7540 static rfs4_chkseq_t
7253 7541 rfs4_check_olo_seqid(seqid4 olo_seqid, rfs4_openowner_t *op, nfs_resop4 *resop)
7254 7542 {
7255 7543 rfs4_chkseq_t rc;
7256 7544
7257 7545 rfs4_dbe_lock(op->ro_dbe);
7258 7546 rc = rfs4_check_seqid(op->ro_open_seqid, &op->ro_reply,
7259 7547 olo_seqid, resop, FALSE);
7260 7548 rfs4_dbe_unlock(op->ro_dbe);
7261 7549
7262 7550 return (rc);
7263 7551 }
7264 7552
7265 7553 static rfs4_chkseq_t
7266 7554 rfs4_check_lock_seqid(seqid4 seqid, rfs4_lo_state_t *lsp, nfs_resop4 *resop)
7267 7555 {
7268 7556 rfs4_chkseq_t rc = NFS4_CHKSEQ_OKAY;
7269 7557
7270 7558 rfs4_dbe_lock(lsp->rls_dbe);
7271 7559 if (!lsp->rls_skip_seqid_check)
7272 7560 rc = rfs4_check_seqid(lsp->rls_seqid, &lsp->rls_reply, seqid,
7273 7561 resop, TRUE);
7274 7562 rfs4_dbe_unlock(lsp->rls_dbe);
7275 7563
7276 7564 return (rc);
7277 7565 }
7278 7566
7279 7567 static void
7280 7568 rfs4_op_open(nfs_argop4 *argop, nfs_resop4 *resop,
7281 7569 struct svc_req *req, struct compound_state *cs)
7282 7570 {
7283 7571 OPEN4args *args = &argop->nfs_argop4_u.opopen;
7284 7572 OPEN4res *resp = &resop->nfs_resop4_u.opopen;
7285 7573 open_owner4 *owner = &args->owner;
7286 7574 open_claim_type4 claim = args->claim;
7287 7575 rfs4_client_t *cp;
7288 7576 rfs4_openowner_t *oo;
7289 7577 bool_t create;
7290 7578 bool_t replay = FALSE;
7291 7579 int can_reclaim;
7292 7580
7293 7581 DTRACE_NFSV4_2(op__open__start, struct compound_state *, cs,
7294 7582 OPEN4args *, args);
7295 7583
7296 7584 if (cs->vp == NULL) {
7297 7585 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
7298 7586 goto end;
7299 7587 }
7300 7588
7301 7589 /*
7302 7590 * Need to check clientid and lease expiration first based on
7303 7591 * error ordering and incrementing sequence id.
7304 7592 */
7305 7593 cp = rfs4_findclient_by_id(owner->clientid, FALSE);
7306 7594 if (cp == NULL) {
7307 7595 *cs->statusp = resp->status =
7308 7596 rfs4_check_clientid(&owner->clientid, 0);
7309 7597 goto end;
7310 7598 }
7311 7599
7312 7600 if (rfs4_lease_expired(cp)) {
7313 7601 rfs4_client_close(cp);
7314 7602 *cs->statusp = resp->status = NFS4ERR_EXPIRED;
7315 7603 goto end;
7316 7604 }
7317 7605 can_reclaim = cp->rc_can_reclaim;
7318 7606
7319 7607 /*
7320 7608 * Find the open_owner for use from this point forward. Take
7321 7609 * care in updating the sequence id based on the type of error
7322 7610 * being returned.
7323 7611 */
7324 7612 retry:
7325 7613 create = TRUE;
7326 7614 oo = rfs4_findopenowner(owner, &create, args->seqid);
7327 7615 if (oo == NULL) {
7328 7616 *cs->statusp = resp->status = NFS4ERR_RESOURCE;
7329 7617 rfs4_client_rele(cp);
7330 7618 goto end;
7331 7619 }
7332 7620
7333 7621 /* Hold off access to the sequence space while the open is done */
7334 7622 rfs4_sw_enter(&oo->ro_sw);
7335 7623
7336 7624 /*
7337 7625 * If the open_owner existed before at the server, then check
7338 7626 * the sequence id.
7339 7627 */
7340 7628 if (!create && !oo->ro_postpone_confirm) {
7341 7629 switch (rfs4_check_open_seqid(args->seqid, oo, resop)) {
7342 7630 case NFS4_CHKSEQ_BAD:
7343 7631 if ((args->seqid > oo->ro_open_seqid) &&
7344 7632 oo->ro_need_confirm) {
7345 7633 rfs4_free_opens(oo, TRUE, FALSE);
7346 7634 rfs4_sw_exit(&oo->ro_sw);
7347 7635 rfs4_openowner_rele(oo);
7348 7636 goto retry;
7349 7637 }
7350 7638 resp->status = NFS4ERR_BAD_SEQID;
7351 7639 goto out;
7352 7640 case NFS4_CHKSEQ_REPLAY: /* replay of previous request */
7353 7641 replay = TRUE;
7354 7642 goto out;
7355 7643 default:
7356 7644 break;
7357 7645 }
7358 7646
7359 7647 /*
7360 7648 * Sequence was ok and open owner exists
7361 7649 * check to see if we have yet to see an
7362 7650 * open_confirm.
7363 7651 */
7364 7652 if (oo->ro_need_confirm) {
7365 7653 rfs4_free_opens(oo, TRUE, FALSE);
7366 7654 rfs4_sw_exit(&oo->ro_sw);
7367 7655 rfs4_openowner_rele(oo);
7368 7656 goto retry;
7369 7657 }
7370 7658 }
7371 7659 /* Grace only applies to regular-type OPENs */
7372 7660 if (rfs4_clnt_in_grace(cp) &&
7373 7661 (claim == CLAIM_NULL || claim == CLAIM_DELEGATE_CUR)) {
7374 7662 *cs->statusp = resp->status = NFS4ERR_GRACE;
7375 7663 goto out;
7376 7664 }
7377 7665
7378 7666 /*
7379 7667 * If previous state at the server existed then can_reclaim
7380 7668 * will be set. If not reply NFS4ERR_NO_GRACE to the
7381 7669 * client.
7382 7670 */
7383 7671 if (rfs4_clnt_in_grace(cp) && claim == CLAIM_PREVIOUS && !can_reclaim) {
7384 7672 *cs->statusp = resp->status = NFS4ERR_NO_GRACE;
7385 7673 goto out;
7386 7674 }
7387 7675
7388 7676
7389 7677 /*
7390 7678 * Reject the open if the client has missed the grace period
7391 7679 */
7392 7680 if (!rfs4_clnt_in_grace(cp) && claim == CLAIM_PREVIOUS) {
7393 7681 *cs->statusp = resp->status = NFS4ERR_NO_GRACE;
7394 7682 goto out;
7395 7683 }
7396 7684
7397 7685 /* Couple of up-front bookkeeping items */
7398 7686 if (oo->ro_need_confirm) {
7399 7687 /*
7400 7688 * If this is a reclaim OPEN then we should not ask
7401 7689 * for a confirmation of the open_owner per the
7402 7690 * protocol specification.
7403 7691 */
7404 7692 if (claim == CLAIM_PREVIOUS)
7405 7693 oo->ro_need_confirm = FALSE;
7406 7694 else
7407 7695 resp->rflags |= OPEN4_RESULT_CONFIRM;
7408 7696 }
7409 7697 resp->rflags |= OPEN4_RESULT_LOCKTYPE_POSIX;
7410 7698
7411 7699 /*
7412 7700 * If there is an unshared filesystem mounted on this vnode,
7413 7701 * do not allow to open/create in this directory.
7414 7702 */
7415 7703 if (vn_ismntpt(cs->vp)) {
7416 7704 *cs->statusp = resp->status = NFS4ERR_ACCESS;
7417 7705 goto out;
7418 7706 }
7419 7707
7420 7708 /*
7421 7709 * access must READ, WRITE, or BOTH. No access is invalid.
7422 7710 * deny can be READ, WRITE, BOTH, or NONE.
7423 7711 * bits not defined for access/deny are invalid.
7424 7712 */
7425 7713 if (! (args->share_access & OPEN4_SHARE_ACCESS_BOTH) ||
7426 7714 (args->share_access & ~OPEN4_SHARE_ACCESS_BOTH) ||
7427 7715 (args->share_deny & ~OPEN4_SHARE_DENY_BOTH)) {
7428 7716 *cs->statusp = resp->status = NFS4ERR_INVAL;
7429 7717 goto out;
7430 7718 }
7431 7719
7432 7720
7433 7721 /*
7434 7722 * make sure attrset is zero before response is built.
7435 7723 */
7436 7724 resp->attrset = 0;
7437 7725
7438 7726 switch (claim) {
7439 7727 case CLAIM_NULL:
7440 7728 rfs4_do_opennull(cs, req, args, oo, resp);
7441 7729 break;
7442 7730 case CLAIM_PREVIOUS:
7443 7731 rfs4_do_openprev(cs, req, args, oo, resp);
7444 7732 break;
7445 7733 case CLAIM_DELEGATE_CUR:
7446 7734 rfs4_do_opendelcur(cs, req, args, oo, resp);
7447 7735 break;
7448 7736 case CLAIM_DELEGATE_PREV:
7449 7737 rfs4_do_opendelprev(cs, req, args, oo, resp);
7450 7738 break;
7451 7739 default:
7452 7740 resp->status = NFS4ERR_INVAL;
7453 7741 break;
7454 7742 }
7455 7743
7456 7744 out:
7457 7745 rfs4_client_rele(cp);
7458 7746
7459 7747 /* Catch sequence id handling here to make it a little easier */
7460 7748 switch (resp->status) {
7461 7749 case NFS4ERR_BADXDR:
7462 7750 case NFS4ERR_BAD_SEQID:
7463 7751 case NFS4ERR_BAD_STATEID:
7464 7752 case NFS4ERR_NOFILEHANDLE:
7465 7753 case NFS4ERR_RESOURCE:
7466 7754 case NFS4ERR_STALE_CLIENTID:
7467 7755 case NFS4ERR_STALE_STATEID:
7468 7756 /*
7469 7757 * The protocol states that if any of these errors are
7470 7758 * being returned, the sequence id should not be
7471 7759 * incremented. Any other return requires an
7472 7760 * increment.
7473 7761 */
7474 7762 break;
7475 7763 default:
7476 7764 /* Always update the lease in this case */
7477 7765 rfs4_update_lease(oo->ro_client);
7478 7766
7479 7767 /* Regular response - copy the result */
7480 7768 if (!replay)
7481 7769 rfs4_update_open_resp(oo, resop, &cs->fh);
7482 7770
7483 7771 /*
7484 7772 * REPLAY case: Only if the previous response was OK
7485 7773 * do we copy the filehandle. If not OK, no
7486 7774 * filehandle to copy.
7487 7775 */
7488 7776 if (replay == TRUE &&
7489 7777 resp->status == NFS4_OK &&
7490 7778 oo->ro_reply_fh.nfs_fh4_val) {
7491 7779 /*
7492 7780 * If this is a replay, we must restore the
7493 7781 * current filehandle/vp to that of what was
7494 7782 * returned originally. Try our best to do
7495 7783 * it.
7496 7784 */
7497 7785 nfs_fh4_fmt_t *fh_fmtp =
7498 7786 (nfs_fh4_fmt_t *)oo->ro_reply_fh.nfs_fh4_val;
7499 7787
7500 7788 cs->exi = checkexport4(&fh_fmtp->fh4_fsid,
7501 7789 (fid_t *)&fh_fmtp->fh4_xlen, NULL);
7502 7790
7503 7791 if (cs->exi == NULL) {
7504 7792 resp->status = NFS4ERR_STALE;
7505 7793 goto finish;
7506 7794 }
7507 7795
7508 7796 VN_RELE(cs->vp);
7509 7797
7510 7798 cs->vp = nfs4_fhtovp(&oo->ro_reply_fh, cs->exi,
7511 7799 &resp->status);
7512 7800
7513 7801 if (cs->vp == NULL)
7514 7802 goto finish;
7515 7803
7516 7804 nfs_fh4_copy(&oo->ro_reply_fh, &cs->fh);
7517 7805 }
7518 7806
7519 7807 /*
7520 7808 * If this was a replay, no need to update the
7521 7809 * sequence id. If the open_owner was not created on
7522 7810 * this pass, then update. The first use of an
7523 7811 * open_owner will not bump the sequence id.
7524 7812 */
7525 7813 if (replay == FALSE && !create)
7526 7814 rfs4_update_open_sequence(oo);
7527 7815 /*
7528 7816 * If the client is receiving an error and the
7529 7817 * open_owner needs to be confirmed, there is no way
7530 7818 * to notify the client of this fact ignoring the fact
7531 7819 * that the server has no method of returning a
7532 7820 * stateid to confirm. Therefore, the server needs to
7533 7821 * mark this open_owner in a way as to avoid the
7534 7822 * sequence id checking the next time the client uses
7535 7823 * this open_owner.
7536 7824 */
7537 7825 if (resp->status != NFS4_OK && oo->ro_need_confirm)
7538 7826 oo->ro_postpone_confirm = TRUE;
7539 7827 /*
7540 7828 * If OK response then clear the postpone flag and
7541 7829 * reset the sequence id to keep in sync with the
7542 7830 * client.
7543 7831 */
7544 7832 if (resp->status == NFS4_OK && oo->ro_postpone_confirm) {
7545 7833 oo->ro_postpone_confirm = FALSE;
7546 7834 oo->ro_open_seqid = args->seqid;
7547 7835 }
7548 7836 break;
7549 7837 }
7550 7838
7551 7839 finish:
7552 7840 *cs->statusp = resp->status;
7553 7841
7554 7842 rfs4_sw_exit(&oo->ro_sw);
7555 7843 rfs4_openowner_rele(oo);
7556 7844
7557 7845 end:
7558 7846 DTRACE_NFSV4_2(op__open__done, struct compound_state *, cs,
7559 7847 OPEN4res *, resp);
7560 7848 }
7561 7849
7562 7850 /*ARGSUSED*/
7563 7851 void
7564 7852 rfs4_op_open_confirm(nfs_argop4 *argop, nfs_resop4 *resop,
7565 7853 struct svc_req *req, struct compound_state *cs)
7566 7854 {
7567 7855 OPEN_CONFIRM4args *args = &argop->nfs_argop4_u.opopen_confirm;
7568 7856 OPEN_CONFIRM4res *resp = &resop->nfs_resop4_u.opopen_confirm;
7569 7857 rfs4_state_t *sp;
7570 7858 nfsstat4 status;
7571 7859
7572 7860 DTRACE_NFSV4_2(op__open__confirm__start, struct compound_state *, cs,
7573 7861 OPEN_CONFIRM4args *, args);
7574 7862
7575 7863 if (cs->vp == NULL) {
7576 7864 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
7577 7865 goto out;
7578 7866 }
7579 7867
7580 7868 if (cs->vp->v_type != VREG) {
7581 7869 *cs->statusp = resp->status =
7582 7870 cs->vp->v_type == VDIR ? NFS4ERR_ISDIR : NFS4ERR_INVAL;
7583 7871 return;
7584 7872 }
7585 7873
7586 7874 status = rfs4_get_state(&args->open_stateid, &sp, RFS4_DBS_VALID);
7587 7875 if (status != NFS4_OK) {
7588 7876 *cs->statusp = resp->status = status;
7589 7877 goto out;
7590 7878 }
7591 7879
7592 7880 /* Ensure specified filehandle matches */
7593 7881 if (cs->vp != sp->rs_finfo->rf_vp) {
7594 7882 rfs4_state_rele(sp);
7595 7883 *cs->statusp = resp->status = NFS4ERR_BAD_STATEID;
7596 7884 goto out;
7597 7885 }
7598 7886
7599 7887 /* hold off other access to open_owner while we tinker */
7600 7888 rfs4_sw_enter(&sp->rs_owner->ro_sw);
7601 7889
7602 7890 switch (rfs4_check_stateid_seqid(sp, &args->open_stateid)) {
7603 7891 case NFS4_CHECK_STATEID_OKAY:
7604 7892 if (rfs4_check_open_seqid(args->seqid, sp->rs_owner,
7605 7893 resop) != 0) {
7606 7894 *cs->statusp = resp->status = NFS4ERR_BAD_SEQID;
7607 7895 break;
7608 7896 }
7609 7897 /*
7610 7898 * If it is the appropriate stateid and determined to
7611 7899 * be "OKAY" then this means that the stateid does not
7612 7900 * need to be confirmed and the client is in error for
7613 7901 * sending an OPEN_CONFIRM.
7614 7902 */
7615 7903 *cs->statusp = resp->status = NFS4ERR_BAD_STATEID;
7616 7904 break;
7617 7905 case NFS4_CHECK_STATEID_OLD:
7618 7906 *cs->statusp = resp->status = NFS4ERR_OLD_STATEID;
7619 7907 break;
7620 7908 case NFS4_CHECK_STATEID_BAD:
7621 7909 *cs->statusp = resp->status = NFS4ERR_BAD_STATEID;
7622 7910 break;
7623 7911 case NFS4_CHECK_STATEID_EXPIRED:
7624 7912 *cs->statusp = resp->status = NFS4ERR_EXPIRED;
7625 7913 break;
7626 7914 case NFS4_CHECK_STATEID_CLOSED:
7627 7915 *cs->statusp = resp->status = NFS4ERR_OLD_STATEID;
7628 7916 break;
7629 7917 case NFS4_CHECK_STATEID_REPLAY:
7630 7918 switch (rfs4_check_open_seqid(args->seqid, sp->rs_owner,
7631 7919 resop)) {
7632 7920 case NFS4_CHKSEQ_OKAY:
7633 7921 /*
7634 7922 * This is replayed stateid; if seqid matches
7635 7923 * next expected, then client is using wrong seqid.
7636 7924 */
7637 7925 /* fall through */
7638 7926 case NFS4_CHKSEQ_BAD:
7639 7927 *cs->statusp = resp->status = NFS4ERR_BAD_SEQID;
7640 7928 break;
7641 7929 case NFS4_CHKSEQ_REPLAY:
7642 7930 /*
7643 7931 * Note this case is the duplicate case so
7644 7932 * resp->status is already set.
7645 7933 */
7646 7934 *cs->statusp = resp->status;
7647 7935 rfs4_update_lease(sp->rs_owner->ro_client);
7648 7936 break;
7649 7937 }
7650 7938 break;
7651 7939 case NFS4_CHECK_STATEID_UNCONFIRMED:
7652 7940 if (rfs4_check_open_seqid(args->seqid, sp->rs_owner,
7653 7941 resop) != NFS4_CHKSEQ_OKAY) {
7654 7942 *cs->statusp = resp->status = NFS4ERR_BAD_SEQID;
7655 7943 break;
7656 7944 }
7657 7945 *cs->statusp = resp->status = NFS4_OK;
7658 7946
7659 7947 next_stateid(&sp->rs_stateid);
7660 7948 resp->open_stateid = sp->rs_stateid.stateid;
7661 7949 sp->rs_owner->ro_need_confirm = FALSE;
7662 7950 rfs4_update_lease(sp->rs_owner->ro_client);
7663 7951 rfs4_update_open_sequence(sp->rs_owner);
7664 7952 rfs4_update_open_resp(sp->rs_owner, resop, NULL);
7665 7953 break;
7666 7954 default:
7667 7955 ASSERT(FALSE);
7668 7956 *cs->statusp = resp->status = NFS4ERR_SERVERFAULT;
7669 7957 break;
7670 7958 }
7671 7959 rfs4_sw_exit(&sp->rs_owner->ro_sw);
7672 7960 rfs4_state_rele(sp);
7673 7961
7674 7962 out:
7675 7963 DTRACE_NFSV4_2(op__open__confirm__done, struct compound_state *, cs,
7676 7964 OPEN_CONFIRM4res *, resp);
7677 7965 }
7678 7966
7679 7967 /*ARGSUSED*/
7680 7968 void
7681 7969 rfs4_op_open_downgrade(nfs_argop4 *argop, nfs_resop4 *resop,
7682 7970 struct svc_req *req, struct compound_state *cs)
7683 7971 {
7684 7972 OPEN_DOWNGRADE4args *args = &argop->nfs_argop4_u.opopen_downgrade;
7685 7973 OPEN_DOWNGRADE4res *resp = &resop->nfs_resop4_u.opopen_downgrade;
7686 7974 uint32_t access = args->share_access;
7687 7975 uint32_t deny = args->share_deny;
7688 7976 nfsstat4 status;
7689 7977 rfs4_state_t *sp;
7690 7978 rfs4_file_t *fp;
7691 7979 int fflags = 0;
7692 7980
7693 7981 DTRACE_NFSV4_2(op__open__downgrade__start, struct compound_state *, cs,
7694 7982 OPEN_DOWNGRADE4args *, args);
7695 7983
7696 7984 if (cs->vp == NULL) {
7697 7985 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
7698 7986 goto out;
7699 7987 }
7700 7988
7701 7989 if (cs->vp->v_type != VREG) {
7702 7990 *cs->statusp = resp->status = NFS4ERR_INVAL;
7703 7991 return;
7704 7992 }
7705 7993
7706 7994 status = rfs4_get_state(&args->open_stateid, &sp, RFS4_DBS_VALID);
7707 7995 if (status != NFS4_OK) {
7708 7996 *cs->statusp = resp->status = status;
7709 7997 goto out;
7710 7998 }
7711 7999
7712 8000 /* Ensure specified filehandle matches */
7713 8001 if (cs->vp != sp->rs_finfo->rf_vp) {
7714 8002 rfs4_state_rele(sp);
7715 8003 *cs->statusp = resp->status = NFS4ERR_BAD_STATEID;
7716 8004 goto out;
7717 8005 }
7718 8006
7719 8007 /* hold off other access to open_owner while we tinker */
7720 8008 rfs4_sw_enter(&sp->rs_owner->ro_sw);
7721 8009
7722 8010 switch (rfs4_check_stateid_seqid(sp, &args->open_stateid)) {
7723 8011 case NFS4_CHECK_STATEID_OKAY:
7724 8012 if (rfs4_check_open_seqid(args->seqid, sp->rs_owner,
7725 8013 resop) != NFS4_CHKSEQ_OKAY) {
7726 8014 *cs->statusp = resp->status = NFS4ERR_BAD_SEQID;
7727 8015 goto end;
7728 8016 }
7729 8017 break;
7730 8018 case NFS4_CHECK_STATEID_OLD:
7731 8019 *cs->statusp = resp->status = NFS4ERR_OLD_STATEID;
7732 8020 goto end;
7733 8021 case NFS4_CHECK_STATEID_BAD:
7734 8022 *cs->statusp = resp->status = NFS4ERR_BAD_STATEID;
7735 8023 goto end;
7736 8024 case NFS4_CHECK_STATEID_EXPIRED:
7737 8025 *cs->statusp = resp->status = NFS4ERR_EXPIRED;
7738 8026 goto end;
7739 8027 case NFS4_CHECK_STATEID_CLOSED:
7740 8028 *cs->statusp = resp->status = NFS4ERR_OLD_STATEID;
7741 8029 goto end;
7742 8030 case NFS4_CHECK_STATEID_UNCONFIRMED:
7743 8031 *cs->statusp = resp->status = NFS4ERR_BAD_STATEID;
7744 8032 goto end;
7745 8033 case NFS4_CHECK_STATEID_REPLAY:
7746 8034 /* Check the sequence id for the open owner */
7747 8035 switch (rfs4_check_open_seqid(args->seqid, sp->rs_owner,
7748 8036 resop)) {
7749 8037 case NFS4_CHKSEQ_OKAY:
7750 8038 /*
7751 8039 * This is replayed stateid; if seqid matches
7752 8040 * next expected, then client is using wrong seqid.
7753 8041 */
7754 8042 /* fall through */
7755 8043 case NFS4_CHKSEQ_BAD:
7756 8044 *cs->statusp = resp->status = NFS4ERR_BAD_SEQID;
7757 8045 goto end;
7758 8046 case NFS4_CHKSEQ_REPLAY:
7759 8047 /*
7760 8048 * Note this case is the duplicate case so
7761 8049 * resp->status is already set.
7762 8050 */
7763 8051 *cs->statusp = resp->status;
7764 8052 rfs4_update_lease(sp->rs_owner->ro_client);
7765 8053 goto end;
7766 8054 }
7767 8055 break;
7768 8056 default:
7769 8057 ASSERT(FALSE);
7770 8058 break;
7771 8059 }
7772 8060
7773 8061 rfs4_dbe_lock(sp->rs_dbe);
7774 8062 /*
7775 8063 * Check that the new access modes and deny modes are valid.
7776 8064 * Check that no invalid bits are set.
7777 8065 */
7778 8066 if ((access & ~(OPEN4_SHARE_ACCESS_READ | OPEN4_SHARE_ACCESS_WRITE)) ||
7779 8067 (deny & ~(OPEN4_SHARE_DENY_READ | OPEN4_SHARE_DENY_WRITE))) {
7780 8068 *cs->statusp = resp->status = NFS4ERR_INVAL;
7781 8069 rfs4_update_open_sequence(sp->rs_owner);
7782 8070 rfs4_dbe_unlock(sp->rs_dbe);
7783 8071 goto end;
7784 8072 }
7785 8073
7786 8074 /*
7787 8075 * The new modes must be a subset of the current modes and
7788 8076 * the access must specify at least one mode. To test that
7789 8077 * the new mode is a subset of the current modes we bitwise
7790 8078 * AND them together and check that the result equals the new
7791 8079 * mode. For example:
7792 8080 * New mode, access == R and current mode, sp->rs_open_access == RW
7793 8081 * access & sp->rs_open_access == R == access, so the new access mode
7794 8082 * is valid. Consider access == RW, sp->rs_open_access = R
7795 8083 * access & sp->rs_open_access == R != access, so the new access mode
7796 8084 * is invalid.
7797 8085 */
7798 8086 if ((access & sp->rs_open_access) != access ||
7799 8087 (deny & sp->rs_open_deny) != deny ||
7800 8088 (access &
7801 8089 (OPEN4_SHARE_ACCESS_READ | OPEN4_SHARE_ACCESS_WRITE)) == 0) {
7802 8090 *cs->statusp = resp->status = NFS4ERR_INVAL;
7803 8091 rfs4_update_open_sequence(sp->rs_owner);
7804 8092 rfs4_dbe_unlock(sp->rs_dbe);
7805 8093 goto end;
7806 8094 }
7807 8095
7808 8096 /*
7809 8097 * Release any share locks associated with this stateID.
7810 8098 * Strictly speaking, this violates the spec because the
7811 8099 * spec effectively requires that open downgrade be atomic.
7812 8100 * At present, fs_shrlock does not have this capability.
7813 8101 */
7814 8102 (void) rfs4_unshare(sp);
7815 8103
7816 8104 status = rfs4_share(sp, access, deny);
7817 8105 if (status != NFS4_OK) {
7818 8106 *cs->statusp = resp->status = NFS4ERR_SERVERFAULT;
7819 8107 rfs4_update_open_sequence(sp->rs_owner);
7820 8108 rfs4_dbe_unlock(sp->rs_dbe);
7821 8109 goto end;
7822 8110 }
7823 8111
7824 8112 fp = sp->rs_finfo;
7825 8113 rfs4_dbe_lock(fp->rf_dbe);
7826 8114
7827 8115 /*
7828 8116 * If the current mode has deny read and the new mode
7829 8117 * does not, decrement the number of deny read mode bits
7830 8118 * and if it goes to zero turn off the deny read bit
7831 8119 * on the file.
7832 8120 */
7833 8121 if ((sp->rs_open_deny & OPEN4_SHARE_DENY_READ) &&
7834 8122 (deny & OPEN4_SHARE_DENY_READ) == 0) {
7835 8123 fp->rf_deny_read--;
7836 8124 if (fp->rf_deny_read == 0)
7837 8125 fp->rf_share_deny &= ~OPEN4_SHARE_DENY_READ;
7838 8126 }
7839 8127
7840 8128 /*
7841 8129 * If the current mode has deny write and the new mode
7842 8130 * does not, decrement the number of deny write mode bits
7843 8131 * and if it goes to zero turn off the deny write bit
7844 8132 * on the file.
7845 8133 */
7846 8134 if ((sp->rs_open_deny & OPEN4_SHARE_DENY_WRITE) &&
7847 8135 (deny & OPEN4_SHARE_DENY_WRITE) == 0) {
7848 8136 fp->rf_deny_write--;
7849 8137 if (fp->rf_deny_write == 0)
7850 8138 fp->rf_share_deny &= ~OPEN4_SHARE_DENY_WRITE;
7851 8139 }
7852 8140
7853 8141 /*
7854 8142 * If the current mode has access read and the new mode
7855 8143 * does not, decrement the number of access read mode bits
7856 8144 * and if it goes to zero turn off the access read bit
7857 8145 * on the file. set fflags to FREAD for the call to
7858 8146 * vn_open_downgrade().
7859 8147 */
7860 8148 if ((sp->rs_open_access & OPEN4_SHARE_ACCESS_READ) &&
7861 8149 (access & OPEN4_SHARE_ACCESS_READ) == 0) {
7862 8150 fp->rf_access_read--;
7863 8151 if (fp->rf_access_read == 0)
7864 8152 fp->rf_share_access &= ~OPEN4_SHARE_ACCESS_READ;
7865 8153 fflags |= FREAD;
7866 8154 }
7867 8155
7868 8156 /*
7869 8157 * If the current mode has access write and the new mode
7870 8158 * does not, decrement the number of access write mode bits
7871 8159 * and if it goes to zero turn off the access write bit
7872 8160 * on the file. set fflags to FWRITE for the call to
7873 8161 * vn_open_downgrade().
7874 8162 */
7875 8163 if ((sp->rs_open_access & OPEN4_SHARE_ACCESS_WRITE) &&
7876 8164 (access & OPEN4_SHARE_ACCESS_WRITE) == 0) {
7877 8165 fp->rf_access_write--;
7878 8166 if (fp->rf_access_write == 0)
7879 8167 fp->rf_share_deny &= ~OPEN4_SHARE_ACCESS_WRITE;
7880 8168 fflags |= FWRITE;
7881 8169 }
7882 8170
7883 8171 /* Check that the file is still accessible */
7884 8172 ASSERT(fp->rf_share_access);
7885 8173
7886 8174 rfs4_dbe_unlock(fp->rf_dbe);
7887 8175
7888 8176 /* now set the new open access and deny modes */
7889 8177 sp->rs_open_access = access;
7890 8178 sp->rs_open_deny = deny;
7891 8179
7892 8180 /*
7893 8181 * we successfully downgraded the share lock, now we need to downgrade
7894 8182 * the open. it is possible that the downgrade was only for a deny
7895 8183 * mode and we have nothing else to do.
7896 8184 */
7897 8185 if ((fflags & (FREAD|FWRITE)) != 0)
7898 8186 vn_open_downgrade(cs->vp, fflags);
7899 8187
7900 8188 /* Update the stateid */
7901 8189 next_stateid(&sp->rs_stateid);
7902 8190 resp->open_stateid = sp->rs_stateid.stateid;
7903 8191
7904 8192 rfs4_dbe_unlock(sp->rs_dbe);
7905 8193
7906 8194 *cs->statusp = resp->status = NFS4_OK;
7907 8195 /* Update the lease */
7908 8196 rfs4_update_lease(sp->rs_owner->ro_client);
7909 8197 /* And the sequence */
7910 8198 rfs4_update_open_sequence(sp->rs_owner);
7911 8199 rfs4_update_open_resp(sp->rs_owner, resop, NULL);
7912 8200
7913 8201 end:
7914 8202 rfs4_sw_exit(&sp->rs_owner->ro_sw);
7915 8203 rfs4_state_rele(sp);
7916 8204 out:
7917 8205 DTRACE_NFSV4_2(op__open__downgrade__done, struct compound_state *, cs,
7918 8206 OPEN_DOWNGRADE4res *, resp);
7919 8207 }
7920 8208
7921 8209 static void *
7922 8210 memstr(const void *s1, const char *s2, size_t n)
7923 8211 {
7924 8212 size_t l = strlen(s2);
7925 8213 char *p = (char *)s1;
7926 8214
7927 8215 while (n >= l) {
7928 8216 if (bcmp(p, s2, l) == 0)
7929 8217 return (p);
7930 8218 p++;
7931 8219 n--;
7932 8220 }
7933 8221
7934 8222 return (NULL);
7935 8223 }
7936 8224
7937 8225 /*
7938 8226 * The logic behind this function is detailed in the NFSv4 RFC in the
7939 8227 * SETCLIENTID operation description under IMPLEMENTATION. Refer to
7940 8228 * that section for explicit guidance to server behavior for
7941 8229 * SETCLIENTID.
7942 8230 */
7943 8231 void
7944 8232 rfs4_op_setclientid(nfs_argop4 *argop, nfs_resop4 *resop,
7945 8233 struct svc_req *req, struct compound_state *cs)
7946 8234 {
7947 8235 SETCLIENTID4args *args = &argop->nfs_argop4_u.opsetclientid;
7948 8236 SETCLIENTID4res *res = &resop->nfs_resop4_u.opsetclientid;
7949 8237 rfs4_client_t *cp, *newcp, *cp_confirmed, *cp_unconfirmed;
7950 8238 rfs4_clntip_t *ci;
7951 8239 bool_t create;
7952 8240 char *addr, *netid;
7953 8241 int len;
7954 8242
7955 8243 DTRACE_NFSV4_2(op__setclientid__start, struct compound_state *, cs,
7956 8244 SETCLIENTID4args *, args);
7957 8245 retry:
7958 8246 newcp = cp_confirmed = cp_unconfirmed = NULL;
7959 8247
7960 8248 /*
7961 8249 * Save the caller's IP address
7962 8250 */
7963 8251 args->client.cl_addr =
7964 8252 (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
7965 8253
7966 8254 /*
7967 8255 * Record if it is a Solaris client that cannot handle referrals.
7968 8256 */
7969 8257 if (memstr(args->client.id_val, "Solaris", args->client.id_len) &&
7970 8258 !memstr(args->client.id_val, "+referrals", args->client.id_len)) {
7971 8259 /* Add a "yes, it's downrev" record */
7972 8260 create = TRUE;
7973 8261 ci = rfs4_find_clntip(args->client.cl_addr, &create);
7974 8262 ASSERT(ci != NULL);
7975 8263 rfs4_dbe_rele(ci->ri_dbe);
7976 8264 } else {
7977 8265 /* Remove any previous record */
7978 8266 rfs4_invalidate_clntip(args->client.cl_addr);
7979 8267 }
7980 8268
7981 8269 /*
7982 8270 * In search of an EXISTING client matching the incoming
7983 8271 * request to establish a new client identifier at the server
7984 8272 */
7985 8273 create = TRUE;
7986 8274 cp = rfs4_findclient(&args->client, &create, NULL);
7987 8275
7988 8276 /* Should never happen */
7989 8277 ASSERT(cp != NULL);
7990 8278
7991 8279 if (cp == NULL) {
7992 8280 *cs->statusp = res->status = NFS4ERR_SERVERFAULT;
7993 8281 goto out;
7994 8282 }
7995 8283
7996 8284 /*
7997 8285 * Easiest case. Client identifier is newly created and is
7998 8286 * unconfirmed. Also note that for this case, no other
7999 8287 * entries exist for the client identifier. Nothing else to
8000 8288 * check. Just setup the response and respond.
8001 8289 */
8002 8290 if (create) {
8003 8291 *cs->statusp = res->status = NFS4_OK;
8004 8292 res->SETCLIENTID4res_u.resok4.clientid = cp->rc_clientid;
8005 8293 res->SETCLIENTID4res_u.resok4.setclientid_confirm =
8006 8294 cp->rc_confirm_verf;
8007 8295 /* Setup callback information; CB_NULL confirmation later */
8008 8296 rfs4_client_setcb(cp, &args->callback, args->callback_ident);
8009 8297
8010 8298 rfs4_client_rele(cp);
8011 8299 goto out;
8012 8300 }
8013 8301
8014 8302 /*
8015 8303 * An existing, confirmed client may exist but it may not have
8016 8304 * been active for at least one lease period. If so, then
8017 8305 * "close" the client and create a new client identifier
8018 8306 */
8019 8307 if (rfs4_lease_expired(cp)) {
8020 8308 rfs4_client_close(cp);
8021 8309 goto retry;
8022 8310 }
8023 8311
8024 8312 if (cp->rc_need_confirm == TRUE)
8025 8313 cp_unconfirmed = cp;
8026 8314 else
8027 8315 cp_confirmed = cp;
8028 8316
8029 8317 cp = NULL;
8030 8318
8031 8319 /*
8032 8320 * We have a confirmed client, now check for an
8033 8321 * unconfimred entry
8034 8322 */
8035 8323 if (cp_confirmed) {
8036 8324 /* If creds don't match then client identifier is inuse */
8037 8325 if (!creds_ok(cp_confirmed->rc_cr_set, req, cs)) {
8038 8326 rfs4_cbinfo_t *cbp;
8039 8327 /*
8040 8328 * Some one else has established this client
8041 8329 * id. Try and say * who they are. We will use
8042 8330 * the call back address supplied by * the
8043 8331 * first client.
8044 8332 */
8045 8333 *cs->statusp = res->status = NFS4ERR_CLID_INUSE;
8046 8334
8047 8335 addr = netid = NULL;
8048 8336
8049 8337 cbp = &cp_confirmed->rc_cbinfo;
8050 8338 if (cbp->cb_callback.cb_location.r_addr &&
8051 8339 cbp->cb_callback.cb_location.r_netid) {
8052 8340 cb_client4 *cbcp = &cbp->cb_callback;
8053 8341
8054 8342 len = strlen(cbcp->cb_location.r_addr)+1;
8055 8343 addr = kmem_alloc(len, KM_SLEEP);
8056 8344 bcopy(cbcp->cb_location.r_addr, addr, len);
8057 8345 len = strlen(cbcp->cb_location.r_netid)+1;
8058 8346 netid = kmem_alloc(len, KM_SLEEP);
8059 8347 bcopy(cbcp->cb_location.r_netid, netid, len);
8060 8348 }
8061 8349
8062 8350 res->SETCLIENTID4res_u.client_using.r_addr = addr;
8063 8351 res->SETCLIENTID4res_u.client_using.r_netid = netid;
8064 8352
8065 8353 rfs4_client_rele(cp_confirmed);
8066 8354 }
8067 8355
8068 8356 /*
8069 8357 * Confirmed, creds match, and verifier matches; must
8070 8358 * be an update of the callback info
8071 8359 */
8072 8360 if (cp_confirmed->rc_nfs_client.verifier ==
8073 8361 args->client.verifier) {
8074 8362 /* Setup callback information */
8075 8363 rfs4_client_setcb(cp_confirmed, &args->callback,
8076 8364 args->callback_ident);
8077 8365
8078 8366 /* everything okay -- move ahead */
8079 8367 *cs->statusp = res->status = NFS4_OK;
8080 8368 res->SETCLIENTID4res_u.resok4.clientid =
8081 8369 cp_confirmed->rc_clientid;
8082 8370
8083 8371 /* update the confirm_verifier and return it */
8084 8372 rfs4_client_scv_next(cp_confirmed);
8085 8373 res->SETCLIENTID4res_u.resok4.setclientid_confirm =
8086 8374 cp_confirmed->rc_confirm_verf;
8087 8375
8088 8376 rfs4_client_rele(cp_confirmed);
8089 8377 goto out;
8090 8378 }
8091 8379
8092 8380 /*
8093 8381 * Creds match but the verifier doesn't. Must search
8094 8382 * for an unconfirmed client that would be replaced by
8095 8383 * this request.
8096 8384 */
8097 8385 create = FALSE;
8098 8386 cp_unconfirmed = rfs4_findclient(&args->client, &create,
8099 8387 cp_confirmed);
8100 8388 }
8101 8389
8102 8390 /*
8103 8391 * At this point, we have taken care of the brand new client
8104 8392 * struct, INUSE case, update of an existing, and confirmed
8105 8393 * client struct.
8106 8394 */
8107 8395
8108 8396 /*
8109 8397 * check to see if things have changed while we originally
8110 8398 * picked up the client struct. If they have, then return and
8111 8399 * retry the processing of this SETCLIENTID request.
8112 8400 */
8113 8401 if (cp_unconfirmed) {
8114 8402 rfs4_dbe_lock(cp_unconfirmed->rc_dbe);
8115 8403 if (!cp_unconfirmed->rc_need_confirm) {
8116 8404 rfs4_dbe_unlock(cp_unconfirmed->rc_dbe);
8117 8405 rfs4_client_rele(cp_unconfirmed);
8118 8406 if (cp_confirmed)
8119 8407 rfs4_client_rele(cp_confirmed);
8120 8408 goto retry;
8121 8409 }
8122 8410 /* do away with the old unconfirmed one */
8123 8411 rfs4_dbe_invalidate(cp_unconfirmed->rc_dbe);
8124 8412 rfs4_dbe_unlock(cp_unconfirmed->rc_dbe);
8125 8413 rfs4_client_rele(cp_unconfirmed);
8126 8414 cp_unconfirmed = NULL;
8127 8415 }
8128 8416
8129 8417 /*
8130 8418 * This search will temporarily hide the confirmed client
8131 8419 * struct while a new client struct is created as the
8132 8420 * unconfirmed one.
8133 8421 */
8134 8422 create = TRUE;
8135 8423 newcp = rfs4_findclient(&args->client, &create, cp_confirmed);
8136 8424
8137 8425 ASSERT(newcp != NULL);
8138 8426
8139 8427 if (newcp == NULL) {
8140 8428 *cs->statusp = res->status = NFS4ERR_SERVERFAULT;
8141 8429 rfs4_client_rele(cp_confirmed);
8142 8430 goto out;
8143 8431 }
8144 8432
8145 8433 /*
8146 8434 * If one was not created, then a similar request must be in
8147 8435 * process so release and start over with this one
8148 8436 */
8149 8437 if (create != TRUE) {
8150 8438 rfs4_client_rele(newcp);
8151 8439 if (cp_confirmed)
8152 8440 rfs4_client_rele(cp_confirmed);
8153 8441 goto retry;
8154 8442 }
8155 8443
8156 8444 *cs->statusp = res->status = NFS4_OK;
8157 8445 res->SETCLIENTID4res_u.resok4.clientid = newcp->rc_clientid;
8158 8446 res->SETCLIENTID4res_u.resok4.setclientid_confirm =
8159 8447 newcp->rc_confirm_verf;
8160 8448 /* Setup callback information; CB_NULL confirmation later */
8161 8449 rfs4_client_setcb(newcp, &args->callback, args->callback_ident);
8162 8450
8163 8451 newcp->rc_cp_confirmed = cp_confirmed;
8164 8452
8165 8453 rfs4_client_rele(newcp);
8166 8454
8167 8455 out:
8168 8456 DTRACE_NFSV4_2(op__setclientid__done, struct compound_state *, cs,
8169 8457 SETCLIENTID4res *, res);
8170 8458 }
8171 8459
|
↓ open down ↓ |
1537 lines elided |
↑ open up ↑ |
8172 8460 /*ARGSUSED*/
8173 8461 void
8174 8462 rfs4_op_setclientid_confirm(nfs_argop4 *argop, nfs_resop4 *resop,
8175 8463 struct svc_req *req, struct compound_state *cs)
8176 8464 {
8177 8465 SETCLIENTID_CONFIRM4args *args =
8178 8466 &argop->nfs_argop4_u.opsetclientid_confirm;
8179 8467 SETCLIENTID_CONFIRM4res *res =
8180 8468 &resop->nfs_resop4_u.opsetclientid_confirm;
8181 8469 rfs4_client_t *cp, *cptoclose = NULL;
8470 + nfs4_srv_t *nsrv4;
8182 8471
8183 8472 DTRACE_NFSV4_2(op__setclientid__confirm__start,
8184 8473 struct compound_state *, cs,
8185 8474 SETCLIENTID_CONFIRM4args *, args);
8186 8475
8476 + nsrv4 = zone_getspecific(rfs4_zone_key, curzone);
8187 8477 *cs->statusp = res->status = NFS4_OK;
8188 8478
8189 8479 cp = rfs4_findclient_by_id(args->clientid, TRUE);
8190 8480
8191 8481 if (cp == NULL) {
8192 8482 *cs->statusp = res->status =
8193 8483 rfs4_check_clientid(&args->clientid, 1);
8194 8484 goto out;
8195 8485 }
8196 8486
8197 8487 if (!creds_ok(cp, req, cs)) {
8198 8488 *cs->statusp = res->status = NFS4ERR_CLID_INUSE;
8199 8489 rfs4_client_rele(cp);
8200 8490 goto out;
8201 8491 }
8202 8492
8203 8493 /* If the verifier doesn't match, the record doesn't match */
8204 8494 if (cp->rc_confirm_verf != args->setclientid_confirm) {
8205 8495 *cs->statusp = res->status = NFS4ERR_STALE_CLIENTID;
8206 8496 rfs4_client_rele(cp);
8207 8497 goto out;
8208 8498 }
8209 8499
8210 8500 rfs4_dbe_lock(cp->rc_dbe);
8211 8501 cp->rc_need_confirm = FALSE;
|
↓ open down ↓ |
15 lines elided |
↑ open up ↑ |
8212 8502 if (cp->rc_cp_confirmed) {
8213 8503 cptoclose = cp->rc_cp_confirmed;
8214 8504 cptoclose->rc_ss_remove = 1;
8215 8505 cp->rc_cp_confirmed = NULL;
8216 8506 }
8217 8507
8218 8508 /*
8219 8509 * Update the client's associated server instance, if it's changed
8220 8510 * since the client was created.
8221 8511 */
8222 - if (rfs4_servinst(cp) != rfs4_cur_servinst)
8223 - rfs4_servinst_assign(cp, rfs4_cur_servinst);
8512 + if (rfs4_servinst(cp) != nsrv4->nfs4_cur_servinst)
8513 + rfs4_servinst_assign(nsrv4, cp, nsrv4->nfs4_cur_servinst);
8224 8514
8225 8515 /*
8226 8516 * Record clientid in stable storage.
8227 8517 * Must be done after server instance has been assigned.
8228 8518 */
8229 - rfs4_ss_clid(cp);
8519 + rfs4_ss_clid(nsrv4, cp);
8230 8520
8231 8521 rfs4_dbe_unlock(cp->rc_dbe);
8232 8522
8233 8523 if (cptoclose)
8234 8524 /* don't need to rele, client_close does it */
8235 8525 rfs4_client_close(cptoclose);
8236 8526
8237 8527 /* If needed, initiate CB_NULL call for callback path */
8238 8528 rfs4_deleg_cb_check(cp);
8239 8529 rfs4_update_lease(cp);
8240 8530
8241 8531 /*
8242 8532 * Check to see if client can perform reclaims
8243 8533 */
8244 - rfs4_ss_chkclid(cp);
8534 + rfs4_ss_chkclid(nsrv4, cp);
8245 8535
8246 8536 rfs4_client_rele(cp);
8247 8537
8248 8538 out:
8249 8539 DTRACE_NFSV4_2(op__setclientid__confirm__done,
8250 8540 struct compound_state *, cs,
8251 8541 SETCLIENTID_CONFIRM4 *, res);
8252 8542 }
8253 8543
8254 8544
8255 8545 /*ARGSUSED*/
8256 8546 void
8257 8547 rfs4_op_close(nfs_argop4 *argop, nfs_resop4 *resop,
8258 8548 struct svc_req *req, struct compound_state *cs)
8259 8549 {
8260 8550 CLOSE4args *args = &argop->nfs_argop4_u.opclose;
8261 8551 CLOSE4res *resp = &resop->nfs_resop4_u.opclose;
8262 8552 rfs4_state_t *sp;
8263 8553 nfsstat4 status;
8264 8554
8265 8555 DTRACE_NFSV4_2(op__close__start, struct compound_state *, cs,
8266 8556 CLOSE4args *, args);
8267 8557
8268 8558 if (cs->vp == NULL) {
8269 8559 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
8270 8560 goto out;
8271 8561 }
8272 8562
8273 8563 status = rfs4_get_state(&args->open_stateid, &sp, RFS4_DBS_INVALID);
8274 8564 if (status != NFS4_OK) {
8275 8565 *cs->statusp = resp->status = status;
8276 8566 goto out;
8277 8567 }
8278 8568
8279 8569 /* Ensure specified filehandle matches */
8280 8570 if (cs->vp != sp->rs_finfo->rf_vp) {
8281 8571 rfs4_state_rele(sp);
8282 8572 *cs->statusp = resp->status = NFS4ERR_BAD_STATEID;
8283 8573 goto out;
8284 8574 }
8285 8575
8286 8576 /* hold off other access to open_owner while we tinker */
8287 8577 rfs4_sw_enter(&sp->rs_owner->ro_sw);
8288 8578
8289 8579 switch (rfs4_check_stateid_seqid(sp, &args->open_stateid)) {
8290 8580 case NFS4_CHECK_STATEID_OKAY:
8291 8581 if (rfs4_check_open_seqid(args->seqid, sp->rs_owner,
8292 8582 resop) != NFS4_CHKSEQ_OKAY) {
8293 8583 *cs->statusp = resp->status = NFS4ERR_BAD_SEQID;
8294 8584 goto end;
8295 8585 }
8296 8586 break;
8297 8587 case NFS4_CHECK_STATEID_OLD:
8298 8588 *cs->statusp = resp->status = NFS4ERR_OLD_STATEID;
8299 8589 goto end;
8300 8590 case NFS4_CHECK_STATEID_BAD:
8301 8591 *cs->statusp = resp->status = NFS4ERR_BAD_STATEID;
8302 8592 goto end;
8303 8593 case NFS4_CHECK_STATEID_EXPIRED:
8304 8594 *cs->statusp = resp->status = NFS4ERR_EXPIRED;
8305 8595 goto end;
8306 8596 case NFS4_CHECK_STATEID_CLOSED:
8307 8597 *cs->statusp = resp->status = NFS4ERR_OLD_STATEID;
8308 8598 goto end;
8309 8599 case NFS4_CHECK_STATEID_UNCONFIRMED:
8310 8600 *cs->statusp = resp->status = NFS4ERR_BAD_STATEID;
8311 8601 goto end;
8312 8602 case NFS4_CHECK_STATEID_REPLAY:
8313 8603 /* Check the sequence id for the open owner */
8314 8604 switch (rfs4_check_open_seqid(args->seqid, sp->rs_owner,
8315 8605 resop)) {
8316 8606 case NFS4_CHKSEQ_OKAY:
8317 8607 /*
8318 8608 * This is replayed stateid; if seqid matches
8319 8609 * next expected, then client is using wrong seqid.
8320 8610 */
8321 8611 /* FALL THROUGH */
8322 8612 case NFS4_CHKSEQ_BAD:
8323 8613 *cs->statusp = resp->status = NFS4ERR_BAD_SEQID;
8324 8614 goto end;
8325 8615 case NFS4_CHKSEQ_REPLAY:
8326 8616 /*
8327 8617 * Note this case is the duplicate case so
8328 8618 * resp->status is already set.
8329 8619 */
8330 8620 *cs->statusp = resp->status;
8331 8621 rfs4_update_lease(sp->rs_owner->ro_client);
8332 8622 goto end;
8333 8623 }
8334 8624 break;
8335 8625 default:
8336 8626 ASSERT(FALSE);
8337 8627 break;
8338 8628 }
8339 8629
8340 8630 rfs4_dbe_lock(sp->rs_dbe);
8341 8631
8342 8632 /* Update the stateid. */
8343 8633 next_stateid(&sp->rs_stateid);
8344 8634 resp->open_stateid = sp->rs_stateid.stateid;
8345 8635
8346 8636 rfs4_dbe_unlock(sp->rs_dbe);
8347 8637
8348 8638 rfs4_update_lease(sp->rs_owner->ro_client);
8349 8639 rfs4_update_open_sequence(sp->rs_owner);
8350 8640 rfs4_update_open_resp(sp->rs_owner, resop, NULL);
8351 8641
8352 8642 rfs4_state_close(sp, FALSE, FALSE, cs->cr);
8353 8643
8354 8644 *cs->statusp = resp->status = status;
8355 8645
8356 8646 end:
8357 8647 rfs4_sw_exit(&sp->rs_owner->ro_sw);
8358 8648 rfs4_state_rele(sp);
8359 8649 out:
8360 8650 DTRACE_NFSV4_2(op__close__done, struct compound_state *, cs,
8361 8651 CLOSE4res *, resp);
8362 8652 }
8363 8653
8364 8654 /*
8365 8655 * Manage the counts on the file struct and close all file locks
8366 8656 */
8367 8657 /*ARGSUSED*/
8368 8658 void
8369 8659 rfs4_release_share_lock_state(rfs4_state_t *sp, cred_t *cr,
8370 8660 bool_t close_of_client)
8371 8661 {
8372 8662 rfs4_file_t *fp = sp->rs_finfo;
8373 8663 rfs4_lo_state_t *lsp;
8374 8664 int fflags = 0;
8375 8665
8376 8666 /*
8377 8667 * If this call is part of the larger closing down of client
8378 8668 * state then it is just easier to release all locks
8379 8669 * associated with this client instead of going through each
8380 8670 * individual file and cleaning locks there.
8381 8671 */
8382 8672 if (close_of_client) {
8383 8673 if (sp->rs_owner->ro_client->rc_unlksys_completed == FALSE &&
8384 8674 !list_is_empty(&sp->rs_lostatelist) &&
8385 8675 sp->rs_owner->ro_client->rc_sysidt != LM_NOSYSID) {
8386 8676 /* Is the PxFS kernel module loaded? */
8387 8677 if (lm_remove_file_locks != NULL) {
8388 8678 int new_sysid;
8389 8679
8390 8680 /* Encode the cluster nodeid in new sysid */
8391 8681 new_sysid = sp->rs_owner->ro_client->rc_sysidt;
8392 8682 lm_set_nlmid_flk(&new_sysid);
8393 8683
8394 8684 /*
8395 8685 * This PxFS routine removes file locks for a
8396 8686 * client over all nodes of a cluster.
8397 8687 */
8398 8688 NFS4_DEBUG(rfs4_debug, (CE_NOTE,
8399 8689 "lm_remove_file_locks(sysid=0x%x)\n",
8400 8690 new_sysid));
8401 8691 (*lm_remove_file_locks)(new_sysid);
8402 8692 } else {
8403 8693 struct flock64 flk;
8404 8694
8405 8695 /* Release all locks for this client */
8406 8696 flk.l_type = F_UNLKSYS;
8407 8697 flk.l_whence = 0;
8408 8698 flk.l_start = 0;
8409 8699 flk.l_len = 0;
8410 8700 flk.l_sysid =
8411 8701 sp->rs_owner->ro_client->rc_sysidt;
8412 8702 flk.l_pid = 0;
8413 8703 (void) VOP_FRLOCK(sp->rs_finfo->rf_vp, F_SETLK,
8414 8704 &flk, F_REMOTELOCK | FREAD | FWRITE,
8415 8705 (u_offset_t)0, NULL, CRED(), NULL);
8416 8706 }
8417 8707
8418 8708 sp->rs_owner->ro_client->rc_unlksys_completed = TRUE;
8419 8709 }
8420 8710 }
8421 8711
8422 8712 /*
8423 8713 * Release all locks on this file by this lock owner or at
8424 8714 * least mark the locks as having been released
8425 8715 */
8426 8716 for (lsp = list_head(&sp->rs_lostatelist); lsp != NULL;
8427 8717 lsp = list_next(&sp->rs_lostatelist, lsp)) {
8428 8718 lsp->rls_locks_cleaned = TRUE;
8429 8719
8430 8720 /* Was this already taken care of above? */
8431 8721 if (!close_of_client &&
8432 8722 sp->rs_owner->ro_client->rc_sysidt != LM_NOSYSID)
8433 8723 (void) cleanlocks(sp->rs_finfo->rf_vp,
8434 8724 lsp->rls_locker->rl_pid,
8435 8725 lsp->rls_locker->rl_client->rc_sysidt);
8436 8726 }
8437 8727
8438 8728 /*
8439 8729 * Release any shrlocks associated with this open state ID.
8440 8730 * This must be done before the rfs4_state gets marked closed.
8441 8731 */
8442 8732 if (sp->rs_owner->ro_client->rc_sysidt != LM_NOSYSID)
8443 8733 (void) rfs4_unshare(sp);
8444 8734
8445 8735 if (sp->rs_open_access) {
8446 8736 rfs4_dbe_lock(fp->rf_dbe);
8447 8737
8448 8738 /*
8449 8739 * Decrement the count for each access and deny bit that this
8450 8740 * state has contributed to the file.
8451 8741 * If the file counts go to zero
8452 8742 * clear the appropriate bit in the appropriate mask.
8453 8743 */
8454 8744 if (sp->rs_open_access & OPEN4_SHARE_ACCESS_READ) {
8455 8745 fp->rf_access_read--;
8456 8746 fflags |= FREAD;
8457 8747 if (fp->rf_access_read == 0)
8458 8748 fp->rf_share_access &= ~OPEN4_SHARE_ACCESS_READ;
8459 8749 }
8460 8750 if (sp->rs_open_access & OPEN4_SHARE_ACCESS_WRITE) {
8461 8751 fp->rf_access_write--;
8462 8752 fflags |= FWRITE;
8463 8753 if (fp->rf_access_write == 0)
8464 8754 fp->rf_share_access &=
8465 8755 ~OPEN4_SHARE_ACCESS_WRITE;
8466 8756 }
8467 8757 if (sp->rs_open_deny & OPEN4_SHARE_DENY_READ) {
8468 8758 fp->rf_deny_read--;
8469 8759 if (fp->rf_deny_read == 0)
8470 8760 fp->rf_share_deny &= ~OPEN4_SHARE_DENY_READ;
8471 8761 }
8472 8762 if (sp->rs_open_deny & OPEN4_SHARE_DENY_WRITE) {
8473 8763 fp->rf_deny_write--;
8474 8764 if (fp->rf_deny_write == 0)
8475 8765 fp->rf_share_deny &= ~OPEN4_SHARE_DENY_WRITE;
8476 8766 }
8477 8767
8478 8768 (void) VOP_CLOSE(fp->rf_vp, fflags, 1, (offset_t)0, cr, NULL);
8479 8769
8480 8770 rfs4_dbe_unlock(fp->rf_dbe);
8481 8771
8482 8772 sp->rs_open_access = 0;
8483 8773 sp->rs_open_deny = 0;
8484 8774 }
8485 8775 }
8486 8776
8487 8777 /*
8488 8778 * lock_denied: Fill in a LOCK4deneid structure given an flock64 structure.
8489 8779 */
8490 8780 static nfsstat4
8491 8781 lock_denied(LOCK4denied *dp, struct flock64 *flk)
8492 8782 {
8493 8783 rfs4_lockowner_t *lo;
8494 8784 rfs4_client_t *cp;
8495 8785 uint32_t len;
8496 8786
8497 8787 lo = rfs4_findlockowner_by_pid(flk->l_pid);
8498 8788 if (lo != NULL) {
8499 8789 cp = lo->rl_client;
8500 8790 if (rfs4_lease_expired(cp)) {
8501 8791 rfs4_lockowner_rele(lo);
8502 8792 rfs4_dbe_hold(cp->rc_dbe);
8503 8793 rfs4_client_close(cp);
8504 8794 return (NFS4ERR_EXPIRED);
8505 8795 }
8506 8796 dp->owner.clientid = lo->rl_owner.clientid;
8507 8797 len = lo->rl_owner.owner_len;
8508 8798 dp->owner.owner_val = kmem_alloc(len, KM_SLEEP);
8509 8799 bcopy(lo->rl_owner.owner_val, dp->owner.owner_val, len);
8510 8800 dp->owner.owner_len = len;
8511 8801 rfs4_lockowner_rele(lo);
8512 8802 goto finish;
8513 8803 }
8514 8804
8515 8805 /*
8516 8806 * Its not a NFS4 lock. We take advantage that the upper 32 bits
8517 8807 * of the client id contain the boot time for a NFS4 lock. So we
8518 8808 * fabricate and identity by setting clientid to the sysid, and
8519 8809 * the lock owner to the pid.
8520 8810 */
8521 8811 dp->owner.clientid = flk->l_sysid;
8522 8812 len = sizeof (pid_t);
8523 8813 dp->owner.owner_len = len;
8524 8814 dp->owner.owner_val = kmem_alloc(len, KM_SLEEP);
8525 8815 bcopy(&flk->l_pid, dp->owner.owner_val, len);
8526 8816 finish:
8527 8817 dp->offset = flk->l_start;
8528 8818 dp->length = flk->l_len;
8529 8819
8530 8820 if (flk->l_type == F_RDLCK)
8531 8821 dp->locktype = READ_LT;
8532 8822 else if (flk->l_type == F_WRLCK)
8533 8823 dp->locktype = WRITE_LT;
8534 8824 else
8535 8825 return (NFS4ERR_INVAL); /* no mapping from POSIX ltype to v4 */
8536 8826
8537 8827 return (NFS4_OK);
8538 8828 }
8539 8829
8540 8830 /*
8541 8831 * The NFSv4.0 LOCK operation does not support the blocking lock (at the
8542 8832 * NFSv4.0 protocol level) so the client needs to resend the LOCK request in a
8543 8833 * case the lock is denied by the NFSv4.0 server. NFSv4.0 clients are prepared
8544 8834 * for that (obviously); they are sending the LOCK requests with some delays
8545 8835 * between the attempts. See nfs4frlock() and nfs4_block_and_wait() for the
8546 8836 * locking and delay implementation at the client side.
8547 8837 *
8548 8838 * To make the life of the clients easier, the NFSv4.0 server tries to do some
8549 8839 * fast retries on its own (the for loop below) in a hope the lock will be
8550 8840 * available soon. And if not, the client won't need to resend the LOCK
8551 8841 * requests so fast to check the lock availability. This basically saves some
8552 8842 * network traffic and tries to make sure the client gets the lock ASAP.
8553 8843 */
8554 8844 static int
8555 8845 setlock(vnode_t *vp, struct flock64 *flock, int flag, cred_t *cred)
8556 8846 {
8557 8847 int error;
8558 8848 struct flock64 flk;
8559 8849 int i;
8560 8850 clock_t delaytime;
8561 8851 int cmd;
8562 8852 int spin_cnt = 0;
8563 8853
8564 8854 cmd = nbl_need_check(vp) ? F_SETLK_NBMAND : F_SETLK;
8565 8855 retry:
8566 8856 delaytime = MSEC_TO_TICK_ROUNDUP(rfs4_lock_delay);
8567 8857
8568 8858 for (i = 0; i < rfs4_maxlock_tries; i++) {
8569 8859 LOCK_PRINT(rfs4_debug, "setlock", cmd, flock);
8570 8860 error = VOP_FRLOCK(vp, cmd,
8571 8861 flock, flag, (u_offset_t)0, NULL, cred, NULL);
8572 8862
8573 8863 if (error != EAGAIN && error != EACCES)
8574 8864 break;
8575 8865
8576 8866 if (i < rfs4_maxlock_tries - 1) {
8577 8867 delay(delaytime);
8578 8868 delaytime *= 2;
8579 8869 }
8580 8870 }
8581 8871
8582 8872 if (error == EAGAIN || error == EACCES) {
8583 8873 /* Get the owner of the lock */
8584 8874 flk = *flock;
8585 8875 LOCK_PRINT(rfs4_debug, "setlock", F_GETLK, &flk);
8586 8876 if (VOP_FRLOCK(vp, F_GETLK, &flk, flag, 0, NULL, cred,
8587 8877 NULL) == 0) {
8588 8878 /*
8589 8879 * There's a race inherent in the current VOP_FRLOCK
8590 8880 * design where:
8591 8881 * a: "other guy" takes a lock that conflicts with a
8592 8882 * lock we want
8593 8883 * b: we attempt to take our lock (non-blocking) and
8594 8884 * the attempt fails.
8595 8885 * c: "other guy" releases the conflicting lock
8596 8886 * d: we ask what lock conflicts with the lock we want,
8597 8887 * getting F_UNLCK (no lock blocks us)
8598 8888 *
8599 8889 * If we retry the non-blocking lock attempt in this
8600 8890 * case (restart at step 'b') there's some possibility
8601 8891 * that many such attempts might fail. However a test
8602 8892 * designed to actually provoke this race shows that
8603 8893 * the vast majority of cases require no retry, and
8604 8894 * only a few took as many as three retries. Here's
8605 8895 * the test outcome:
8606 8896 *
8607 8897 * number of retries how many times we needed
8608 8898 * that many retries
8609 8899 * 0 79461
8610 8900 * 1 862
8611 8901 * 2 49
8612 8902 * 3 5
8613 8903 *
8614 8904 * Given those empirical results, we arbitrarily limit
8615 8905 * the retry count to ten.
8616 8906 *
8617 8907 * If we actually make to ten retries and give up,
8618 8908 * nothing catastrophic happens, but we're unable to
8619 8909 * return the information about the conflicting lock to
8620 8910 * the NFS client. That's an acceptable trade off vs.
8621 8911 * letting this retry loop run forever.
8622 8912 */
8623 8913 if (flk.l_type == F_UNLCK) {
8624 8914 if (spin_cnt++ < 10) {
8625 8915 /* No longer locked, retry */
8626 8916 goto retry;
8627 8917 }
8628 8918 } else {
8629 8919 *flock = flk;
8630 8920 LOCK_PRINT(rfs4_debug, "setlock(blocking lock)",
8631 8921 F_GETLK, &flk);
8632 8922 }
8633 8923 }
8634 8924 }
8635 8925
8636 8926 return (error);
8637 8927 }
8638 8928
8639 8929 /*ARGSUSED*/
8640 8930 static nfsstat4
8641 8931 rfs4_do_lock(rfs4_lo_state_t *lsp, nfs_lock_type4 locktype,
8642 8932 offset4 offset, length4 length, cred_t *cred, nfs_resop4 *resop)
8643 8933 {
8644 8934 nfsstat4 status;
8645 8935 rfs4_lockowner_t *lo = lsp->rls_locker;
8646 8936 rfs4_state_t *sp = lsp->rls_state;
8647 8937 struct flock64 flock;
8648 8938 int16_t ltype;
8649 8939 int flag;
8650 8940 int error;
8651 8941 sysid_t sysid;
8652 8942 LOCK4res *lres;
8653 8943 vnode_t *vp;
8654 8944
8655 8945 if (rfs4_lease_expired(lo->rl_client)) {
8656 8946 return (NFS4ERR_EXPIRED);
8657 8947 }
8658 8948
8659 8949 if ((status = rfs4_client_sysid(lo->rl_client, &sysid)) != NFS4_OK)
8660 8950 return (status);
8661 8951
8662 8952 /* Check for zero length. To lock to end of file use all ones for V4 */
8663 8953 if (length == 0)
8664 8954 return (NFS4ERR_INVAL);
8665 8955 else if (length == (length4)(~0))
8666 8956 length = 0; /* Posix to end of file */
8667 8957
8668 8958 retry:
8669 8959 rfs4_dbe_lock(sp->rs_dbe);
8670 8960 if (sp->rs_closed == TRUE) {
8671 8961 rfs4_dbe_unlock(sp->rs_dbe);
8672 8962 return (NFS4ERR_OLD_STATEID);
8673 8963 }
8674 8964
8675 8965 if (resop->resop != OP_LOCKU) {
8676 8966 switch (locktype) {
8677 8967 case READ_LT:
8678 8968 case READW_LT:
8679 8969 if ((sp->rs_share_access
8680 8970 & OPEN4_SHARE_ACCESS_READ) == 0) {
8681 8971 rfs4_dbe_unlock(sp->rs_dbe);
8682 8972
8683 8973 return (NFS4ERR_OPENMODE);
8684 8974 }
8685 8975 ltype = F_RDLCK;
8686 8976 break;
8687 8977 case WRITE_LT:
8688 8978 case WRITEW_LT:
8689 8979 if ((sp->rs_share_access
8690 8980 & OPEN4_SHARE_ACCESS_WRITE) == 0) {
8691 8981 rfs4_dbe_unlock(sp->rs_dbe);
8692 8982
8693 8983 return (NFS4ERR_OPENMODE);
8694 8984 }
8695 8985 ltype = F_WRLCK;
8696 8986 break;
8697 8987 }
8698 8988 } else
8699 8989 ltype = F_UNLCK;
8700 8990
8701 8991 flock.l_type = ltype;
8702 8992 flock.l_whence = 0; /* SEEK_SET */
8703 8993 flock.l_start = offset;
8704 8994 flock.l_len = length;
8705 8995 flock.l_sysid = sysid;
8706 8996 flock.l_pid = lsp->rls_locker->rl_pid;
8707 8997
8708 8998 /* Note that length4 is uint64_t but l_len and l_start are off64_t */
8709 8999 if (flock.l_len < 0 || flock.l_start < 0) {
8710 9000 rfs4_dbe_unlock(sp->rs_dbe);
8711 9001 return (NFS4ERR_INVAL);
8712 9002 }
8713 9003
8714 9004 /*
8715 9005 * N.B. FREAD has the same value as OPEN4_SHARE_ACCESS_READ and
8716 9006 * FWRITE has the same value as OPEN4_SHARE_ACCESS_WRITE.
8717 9007 */
8718 9008 flag = (int)sp->rs_share_access | F_REMOTELOCK;
8719 9009
8720 9010 vp = sp->rs_finfo->rf_vp;
8721 9011 VN_HOLD(vp);
8722 9012
8723 9013 /*
8724 9014 * We need to unlock sp before we call the underlying filesystem to
8725 9015 * acquire the file lock.
8726 9016 */
8727 9017 rfs4_dbe_unlock(sp->rs_dbe);
8728 9018
8729 9019 error = setlock(vp, &flock, flag, cred);
8730 9020
8731 9021 /*
8732 9022 * Make sure the file is still open. In a case the file was closed in
8733 9023 * the meantime, clean the lock we acquired using the setlock() call
8734 9024 * above, and return the appropriate error.
8735 9025 */
8736 9026 rfs4_dbe_lock(sp->rs_dbe);
8737 9027 if (sp->rs_closed == TRUE) {
8738 9028 cleanlocks(vp, lsp->rls_locker->rl_pid, sysid);
8739 9029 rfs4_dbe_unlock(sp->rs_dbe);
8740 9030
8741 9031 VN_RELE(vp);
8742 9032
8743 9033 return (NFS4ERR_OLD_STATEID);
8744 9034 }
8745 9035 rfs4_dbe_unlock(sp->rs_dbe);
8746 9036
8747 9037 VN_RELE(vp);
8748 9038
8749 9039 if (error == 0) {
8750 9040 rfs4_dbe_lock(lsp->rls_dbe);
8751 9041 next_stateid(&lsp->rls_lockid);
8752 9042 rfs4_dbe_unlock(lsp->rls_dbe);
8753 9043 }
8754 9044
8755 9045 /*
8756 9046 * N.B. We map error values to nfsv4 errors. This is differrent
8757 9047 * than puterrno4 routine.
8758 9048 */
8759 9049 switch (error) {
8760 9050 case 0:
8761 9051 status = NFS4_OK;
8762 9052 break;
8763 9053 case EAGAIN:
8764 9054 case EACCES: /* Old value */
8765 9055 /* Can only get here if op is OP_LOCK */
8766 9056 ASSERT(resop->resop == OP_LOCK);
8767 9057 lres = &resop->nfs_resop4_u.oplock;
8768 9058 status = NFS4ERR_DENIED;
8769 9059 if (lock_denied(&lres->LOCK4res_u.denied, &flock)
8770 9060 == NFS4ERR_EXPIRED)
8771 9061 goto retry;
8772 9062 break;
8773 9063 case ENOLCK:
8774 9064 status = NFS4ERR_DELAY;
8775 9065 break;
8776 9066 case EOVERFLOW:
8777 9067 status = NFS4ERR_INVAL;
8778 9068 break;
8779 9069 case EINVAL:
8780 9070 status = NFS4ERR_NOTSUPP;
8781 9071 break;
8782 9072 default:
8783 9073 status = NFS4ERR_SERVERFAULT;
8784 9074 break;
8785 9075 }
8786 9076
8787 9077 return (status);
8788 9078 }
8789 9079
8790 9080 /*ARGSUSED*/
8791 9081 void
8792 9082 rfs4_op_lock(nfs_argop4 *argop, nfs_resop4 *resop,
8793 9083 struct svc_req *req, struct compound_state *cs)
8794 9084 {
8795 9085 LOCK4args *args = &argop->nfs_argop4_u.oplock;
8796 9086 LOCK4res *resp = &resop->nfs_resop4_u.oplock;
8797 9087 nfsstat4 status;
8798 9088 stateid4 *stateid;
8799 9089 rfs4_lockowner_t *lo;
8800 9090 rfs4_client_t *cp;
8801 9091 rfs4_state_t *sp = NULL;
8802 9092 rfs4_lo_state_t *lsp = NULL;
8803 9093 bool_t ls_sw_held = FALSE;
8804 9094 bool_t create = TRUE;
8805 9095 bool_t lcreate = TRUE;
8806 9096 bool_t dup_lock = FALSE;
8807 9097 int rc;
8808 9098
8809 9099 DTRACE_NFSV4_2(op__lock__start, struct compound_state *, cs,
8810 9100 LOCK4args *, args);
8811 9101
8812 9102 if (cs->vp == NULL) {
8813 9103 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
8814 9104 DTRACE_NFSV4_2(op__lock__done, struct compound_state *,
8815 9105 cs, LOCK4res *, resp);
8816 9106 return;
8817 9107 }
8818 9108
8819 9109 if (args->locker.new_lock_owner) {
8820 9110 /* Create a new lockowner for this instance */
8821 9111 open_to_lock_owner4 *olo = &args->locker.locker4_u.open_owner;
8822 9112
8823 9113 NFS4_DEBUG(rfs4_debug, (CE_NOTE, "Creating new lock owner"));
8824 9114
8825 9115 stateid = &olo->open_stateid;
8826 9116 status = rfs4_get_state(stateid, &sp, RFS4_DBS_VALID);
8827 9117 if (status != NFS4_OK) {
8828 9118 NFS4_DEBUG(rfs4_debug,
8829 9119 (CE_NOTE, "Get state failed in lock %d", status));
8830 9120 *cs->statusp = resp->status = status;
8831 9121 DTRACE_NFSV4_2(op__lock__done, struct compound_state *,
8832 9122 cs, LOCK4res *, resp);
8833 9123 return;
8834 9124 }
8835 9125
8836 9126 /* Ensure specified filehandle matches */
8837 9127 if (cs->vp != sp->rs_finfo->rf_vp) {
8838 9128 rfs4_state_rele(sp);
8839 9129 *cs->statusp = resp->status = NFS4ERR_BAD_STATEID;
8840 9130 DTRACE_NFSV4_2(op__lock__done, struct compound_state *,
8841 9131 cs, LOCK4res *, resp);
8842 9132 return;
8843 9133 }
8844 9134
8845 9135 /* hold off other access to open_owner while we tinker */
8846 9136 rfs4_sw_enter(&sp->rs_owner->ro_sw);
8847 9137
8848 9138 switch (rc = rfs4_check_stateid_seqid(sp, stateid)) {
8849 9139 case NFS4_CHECK_STATEID_OLD:
8850 9140 *cs->statusp = resp->status = NFS4ERR_OLD_STATEID;
8851 9141 goto end;
8852 9142 case NFS4_CHECK_STATEID_BAD:
8853 9143 *cs->statusp = resp->status = NFS4ERR_BAD_STATEID;
8854 9144 goto end;
8855 9145 case NFS4_CHECK_STATEID_EXPIRED:
8856 9146 *cs->statusp = resp->status = NFS4ERR_EXPIRED;
8857 9147 goto end;
8858 9148 case NFS4_CHECK_STATEID_UNCONFIRMED:
8859 9149 *cs->statusp = resp->status = NFS4ERR_BAD_STATEID;
8860 9150 goto end;
8861 9151 case NFS4_CHECK_STATEID_CLOSED:
8862 9152 *cs->statusp = resp->status = NFS4ERR_OLD_STATEID;
8863 9153 goto end;
8864 9154 case NFS4_CHECK_STATEID_OKAY:
8865 9155 case NFS4_CHECK_STATEID_REPLAY:
8866 9156 switch (rfs4_check_olo_seqid(olo->open_seqid,
8867 9157 sp->rs_owner, resop)) {
8868 9158 case NFS4_CHKSEQ_OKAY:
8869 9159 if (rc == NFS4_CHECK_STATEID_OKAY)
8870 9160 break;
8871 9161 /*
8872 9162 * This is replayed stateid; if seqid
8873 9163 * matches next expected, then client
8874 9164 * is using wrong seqid.
8875 9165 */
8876 9166 /* FALLTHROUGH */
8877 9167 case NFS4_CHKSEQ_BAD:
8878 9168 *cs->statusp = resp->status = NFS4ERR_BAD_SEQID;
8879 9169 goto end;
8880 9170 case NFS4_CHKSEQ_REPLAY:
8881 9171 /* This is a duplicate LOCK request */
8882 9172 dup_lock = TRUE;
8883 9173
8884 9174 /*
8885 9175 * For a duplicate we do not want to
8886 9176 * create a new lockowner as it should
8887 9177 * already exist.
8888 9178 * Turn off the lockowner create flag.
8889 9179 */
8890 9180 lcreate = FALSE;
8891 9181 }
8892 9182 break;
8893 9183 }
8894 9184
8895 9185 lo = rfs4_findlockowner(&olo->lock_owner, &lcreate);
8896 9186 if (lo == NULL) {
8897 9187 NFS4_DEBUG(rfs4_debug,
8898 9188 (CE_NOTE, "rfs4_op_lock: no lock owner"));
8899 9189 *cs->statusp = resp->status = NFS4ERR_RESOURCE;
8900 9190 goto end;
8901 9191 }
8902 9192
8903 9193 lsp = rfs4_findlo_state_by_owner(lo, sp, &create);
8904 9194 if (lsp == NULL) {
8905 9195 rfs4_update_lease(sp->rs_owner->ro_client);
8906 9196 /*
8907 9197 * Only update theh open_seqid if this is not
8908 9198 * a duplicate request
8909 9199 */
8910 9200 if (dup_lock == FALSE) {
8911 9201 rfs4_update_open_sequence(sp->rs_owner);
8912 9202 }
8913 9203
8914 9204 NFS4_DEBUG(rfs4_debug,
8915 9205 (CE_NOTE, "rfs4_op_lock: no state"));
8916 9206 *cs->statusp = resp->status = NFS4ERR_SERVERFAULT;
8917 9207 rfs4_update_open_resp(sp->rs_owner, resop, NULL);
8918 9208 rfs4_lockowner_rele(lo);
8919 9209 goto end;
8920 9210 }
8921 9211
8922 9212 /*
8923 9213 * This is the new_lock_owner branch and the client is
8924 9214 * supposed to be associating a new lock_owner with
8925 9215 * the open file at this point. If we find that a
8926 9216 * lock_owner/state association already exists and a
8927 9217 * successful LOCK request was returned to the client,
8928 9218 * an error is returned to the client since this is
8929 9219 * not appropriate. The client should be using the
8930 9220 * existing lock_owner branch.
8931 9221 */
8932 9222 if (dup_lock == FALSE && create == FALSE) {
8933 9223 if (lsp->rls_lock_completed == TRUE) {
8934 9224 *cs->statusp =
8935 9225 resp->status = NFS4ERR_BAD_SEQID;
8936 9226 rfs4_lockowner_rele(lo);
8937 9227 goto end;
8938 9228 }
8939 9229 }
8940 9230
8941 9231 rfs4_update_lease(sp->rs_owner->ro_client);
8942 9232
8943 9233 /*
8944 9234 * Only update theh open_seqid if this is not
8945 9235 * a duplicate request
8946 9236 */
8947 9237 if (dup_lock == FALSE) {
8948 9238 rfs4_update_open_sequence(sp->rs_owner);
8949 9239 }
8950 9240
8951 9241 /*
8952 9242 * If this is a duplicate lock request, just copy the
8953 9243 * previously saved reply and return.
8954 9244 */
8955 9245 if (dup_lock == TRUE) {
8956 9246 /* verify that lock_seqid's match */
8957 9247 if (lsp->rls_seqid != olo->lock_seqid) {
8958 9248 NFS4_DEBUG(rfs4_debug,
8959 9249 (CE_NOTE, "rfs4_op_lock: Dup-Lock seqid bad"
8960 9250 "lsp->seqid=%d old->seqid=%d",
8961 9251 lsp->rls_seqid, olo->lock_seqid));
8962 9252 *cs->statusp = resp->status = NFS4ERR_BAD_SEQID;
8963 9253 } else {
8964 9254 rfs4_copy_reply(resop, &lsp->rls_reply);
8965 9255 /*
8966 9256 * Make sure to copy the just
8967 9257 * retrieved reply status into the
8968 9258 * overall compound status
8969 9259 */
8970 9260 *cs->statusp = resp->status;
8971 9261 }
8972 9262 rfs4_lockowner_rele(lo);
8973 9263 goto end;
8974 9264 }
8975 9265
8976 9266 rfs4_dbe_lock(lsp->rls_dbe);
8977 9267
8978 9268 /* Make sure to update the lock sequence id */
8979 9269 lsp->rls_seqid = olo->lock_seqid;
8980 9270
8981 9271 NFS4_DEBUG(rfs4_debug,
8982 9272 (CE_NOTE, "Lock seqid established as %d", lsp->rls_seqid));
8983 9273
8984 9274 /*
8985 9275 * This is used to signify the newly created lockowner
8986 9276 * stateid and its sequence number. The checks for
8987 9277 * sequence number and increment don't occur on the
8988 9278 * very first lock request for a lockowner.
8989 9279 */
8990 9280 lsp->rls_skip_seqid_check = TRUE;
8991 9281
8992 9282 /* hold off other access to lsp while we tinker */
8993 9283 rfs4_sw_enter(&lsp->rls_sw);
8994 9284 ls_sw_held = TRUE;
8995 9285
8996 9286 rfs4_dbe_unlock(lsp->rls_dbe);
8997 9287
8998 9288 rfs4_lockowner_rele(lo);
8999 9289 } else {
9000 9290 stateid = &args->locker.locker4_u.lock_owner.lock_stateid;
9001 9291 /* get lsp and hold the lock on the underlying file struct */
9002 9292 if ((status = rfs4_get_lo_state(stateid, &lsp, TRUE))
9003 9293 != NFS4_OK) {
9004 9294 *cs->statusp = resp->status = status;
9005 9295 DTRACE_NFSV4_2(op__lock__done, struct compound_state *,
9006 9296 cs, LOCK4res *, resp);
9007 9297 return;
9008 9298 }
9009 9299 create = FALSE; /* We didn't create lsp */
9010 9300
9011 9301 /* Ensure specified filehandle matches */
9012 9302 if (cs->vp != lsp->rls_state->rs_finfo->rf_vp) {
9013 9303 rfs4_lo_state_rele(lsp, TRUE);
9014 9304 *cs->statusp = resp->status = NFS4ERR_BAD_STATEID;
9015 9305 DTRACE_NFSV4_2(op__lock__done, struct compound_state *,
9016 9306 cs, LOCK4res *, resp);
9017 9307 return;
9018 9308 }
9019 9309
9020 9310 /* hold off other access to lsp while we tinker */
9021 9311 rfs4_sw_enter(&lsp->rls_sw);
9022 9312 ls_sw_held = TRUE;
9023 9313
9024 9314 switch (rfs4_check_lo_stateid_seqid(lsp, stateid)) {
9025 9315 /*
9026 9316 * The stateid looks like it was okay (expected to be
9027 9317 * the next one)
9028 9318 */
9029 9319 case NFS4_CHECK_STATEID_OKAY:
9030 9320 /*
9031 9321 * The sequence id is now checked. Determine
9032 9322 * if this is a replay or if it is in the
9033 9323 * expected (next) sequence. In the case of a
9034 9324 * replay, there are two replay conditions
9035 9325 * that may occur. The first is the normal
9036 9326 * condition where a LOCK is done with a
9037 9327 * NFS4_OK response and the stateid is
9038 9328 * updated. That case is handled below when
9039 9329 * the stateid is identified as a REPLAY. The
9040 9330 * second is the case where an error is
9041 9331 * returned, like NFS4ERR_DENIED, and the
9042 9332 * sequence number is updated but the stateid
9043 9333 * is not updated. This second case is dealt
9044 9334 * with here. So it may seem odd that the
9045 9335 * stateid is okay but the sequence id is a
9046 9336 * replay but it is okay.
9047 9337 */
9048 9338 switch (rfs4_check_lock_seqid(
9049 9339 args->locker.locker4_u.lock_owner.lock_seqid,
9050 9340 lsp, resop)) {
9051 9341 case NFS4_CHKSEQ_REPLAY:
9052 9342 if (resp->status != NFS4_OK) {
9053 9343 /*
9054 9344 * Here is our replay and need
9055 9345 * to verify that the last
9056 9346 * response was an error.
9057 9347 */
9058 9348 *cs->statusp = resp->status;
9059 9349 goto end;
9060 9350 }
9061 9351 /*
9062 9352 * This is done since the sequence id
9063 9353 * looked like a replay but it didn't
9064 9354 * pass our check so a BAD_SEQID is
9065 9355 * returned as a result.
9066 9356 */
9067 9357 /*FALLTHROUGH*/
9068 9358 case NFS4_CHKSEQ_BAD:
9069 9359 *cs->statusp = resp->status = NFS4ERR_BAD_SEQID;
9070 9360 goto end;
9071 9361 case NFS4_CHKSEQ_OKAY:
9072 9362 /* Everything looks okay move ahead */
9073 9363 break;
9074 9364 }
9075 9365 break;
9076 9366 case NFS4_CHECK_STATEID_OLD:
9077 9367 *cs->statusp = resp->status = NFS4ERR_OLD_STATEID;
9078 9368 goto end;
9079 9369 case NFS4_CHECK_STATEID_BAD:
9080 9370 *cs->statusp = resp->status = NFS4ERR_BAD_STATEID;
9081 9371 goto end;
9082 9372 case NFS4_CHECK_STATEID_EXPIRED:
9083 9373 *cs->statusp = resp->status = NFS4ERR_EXPIRED;
9084 9374 goto end;
9085 9375 case NFS4_CHECK_STATEID_CLOSED:
9086 9376 *cs->statusp = resp->status = NFS4ERR_OLD_STATEID;
9087 9377 goto end;
9088 9378 case NFS4_CHECK_STATEID_REPLAY:
9089 9379 switch (rfs4_check_lock_seqid(
9090 9380 args->locker.locker4_u.lock_owner.lock_seqid,
9091 9381 lsp, resop)) {
9092 9382 case NFS4_CHKSEQ_OKAY:
9093 9383 /*
9094 9384 * This is a replayed stateid; if
9095 9385 * seqid matches the next expected,
9096 9386 * then client is using wrong seqid.
9097 9387 */
9098 9388 case NFS4_CHKSEQ_BAD:
9099 9389 *cs->statusp = resp->status = NFS4ERR_BAD_SEQID;
9100 9390 goto end;
9101 9391 case NFS4_CHKSEQ_REPLAY:
9102 9392 rfs4_update_lease(lsp->rls_locker->rl_client);
9103 9393 *cs->statusp = status = resp->status;
9104 9394 goto end;
9105 9395 }
9106 9396 break;
9107 9397 default:
9108 9398 ASSERT(FALSE);
9109 9399 break;
9110 9400 }
9111 9401
9112 9402 rfs4_update_lock_sequence(lsp);
9113 9403 rfs4_update_lease(lsp->rls_locker->rl_client);
9114 9404 }
9115 9405
9116 9406 /*
9117 9407 * NFS4 only allows locking on regular files, so
9118 9408 * verify type of object.
9119 9409 */
9120 9410 if (cs->vp->v_type != VREG) {
9121 9411 if (cs->vp->v_type == VDIR)
9122 9412 status = NFS4ERR_ISDIR;
9123 9413 else
9124 9414 status = NFS4ERR_INVAL;
9125 9415 goto out;
9126 9416 }
9127 9417
9128 9418 cp = lsp->rls_state->rs_owner->ro_client;
9129 9419
9130 9420 if (rfs4_clnt_in_grace(cp) && !args->reclaim) {
9131 9421 status = NFS4ERR_GRACE;
9132 9422 goto out;
9133 9423 }
9134 9424
9135 9425 if (rfs4_clnt_in_grace(cp) && args->reclaim && !cp->rc_can_reclaim) {
9136 9426 status = NFS4ERR_NO_GRACE;
9137 9427 goto out;
9138 9428 }
9139 9429
9140 9430 if (!rfs4_clnt_in_grace(cp) && args->reclaim) {
9141 9431 status = NFS4ERR_NO_GRACE;
9142 9432 goto out;
9143 9433 }
9144 9434
9145 9435 if (lsp->rls_state->rs_finfo->rf_dinfo.rd_dtype == OPEN_DELEGATE_WRITE)
9146 9436 cs->deleg = TRUE;
9147 9437
9148 9438 status = rfs4_do_lock(lsp, args->locktype,
9149 9439 args->offset, args->length, cs->cr, resop);
9150 9440
9151 9441 out:
9152 9442 lsp->rls_skip_seqid_check = FALSE;
9153 9443
9154 9444 *cs->statusp = resp->status = status;
9155 9445
9156 9446 if (status == NFS4_OK) {
9157 9447 resp->LOCK4res_u.lock_stateid = lsp->rls_lockid.stateid;
9158 9448 lsp->rls_lock_completed = TRUE;
9159 9449 }
9160 9450 /*
9161 9451 * Only update the "OPEN" response here if this was a new
9162 9452 * lock_owner
9163 9453 */
9164 9454 if (sp)
9165 9455 rfs4_update_open_resp(sp->rs_owner, resop, NULL);
9166 9456
9167 9457 rfs4_update_lock_resp(lsp, resop);
9168 9458
9169 9459 end:
9170 9460 if (lsp) {
9171 9461 if (ls_sw_held)
9172 9462 rfs4_sw_exit(&lsp->rls_sw);
9173 9463 /*
9174 9464 * If an sp obtained, then the lsp does not represent
9175 9465 * a lock on the file struct.
9176 9466 */
9177 9467 if (sp != NULL)
9178 9468 rfs4_lo_state_rele(lsp, FALSE);
9179 9469 else
9180 9470 rfs4_lo_state_rele(lsp, TRUE);
9181 9471 }
9182 9472 if (sp) {
9183 9473 rfs4_sw_exit(&sp->rs_owner->ro_sw);
9184 9474 rfs4_state_rele(sp);
9185 9475 }
9186 9476
9187 9477 DTRACE_NFSV4_2(op__lock__done, struct compound_state *, cs,
9188 9478 LOCK4res *, resp);
9189 9479 }
9190 9480
9191 9481 /* free function for LOCK/LOCKT */
9192 9482 static void
9193 9483 lock_denied_free(nfs_resop4 *resop)
9194 9484 {
9195 9485 LOCK4denied *dp = NULL;
9196 9486
9197 9487 switch (resop->resop) {
9198 9488 case OP_LOCK:
9199 9489 if (resop->nfs_resop4_u.oplock.status == NFS4ERR_DENIED)
9200 9490 dp = &resop->nfs_resop4_u.oplock.LOCK4res_u.denied;
9201 9491 break;
9202 9492 case OP_LOCKT:
9203 9493 if (resop->nfs_resop4_u.oplockt.status == NFS4ERR_DENIED)
9204 9494 dp = &resop->nfs_resop4_u.oplockt.denied;
9205 9495 break;
9206 9496 default:
9207 9497 break;
9208 9498 }
9209 9499
9210 9500 if (dp)
9211 9501 kmem_free(dp->owner.owner_val, dp->owner.owner_len);
9212 9502 }
9213 9503
9214 9504 /*ARGSUSED*/
9215 9505 void
9216 9506 rfs4_op_locku(nfs_argop4 *argop, nfs_resop4 *resop,
9217 9507 struct svc_req *req, struct compound_state *cs)
9218 9508 {
9219 9509 LOCKU4args *args = &argop->nfs_argop4_u.oplocku;
9220 9510 LOCKU4res *resp = &resop->nfs_resop4_u.oplocku;
9221 9511 nfsstat4 status;
9222 9512 stateid4 *stateid = &args->lock_stateid;
9223 9513 rfs4_lo_state_t *lsp;
9224 9514
9225 9515 DTRACE_NFSV4_2(op__locku__start, struct compound_state *, cs,
9226 9516 LOCKU4args *, args);
9227 9517
9228 9518 if (cs->vp == NULL) {
9229 9519 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
9230 9520 DTRACE_NFSV4_2(op__locku__done, struct compound_state *, cs,
9231 9521 LOCKU4res *, resp);
9232 9522 return;
9233 9523 }
9234 9524
9235 9525 if ((status = rfs4_get_lo_state(stateid, &lsp, TRUE)) != NFS4_OK) {
9236 9526 *cs->statusp = resp->status = status;
9237 9527 DTRACE_NFSV4_2(op__locku__done, struct compound_state *, cs,
9238 9528 LOCKU4res *, resp);
9239 9529 return;
9240 9530 }
9241 9531
9242 9532 /* Ensure specified filehandle matches */
9243 9533 if (cs->vp != lsp->rls_state->rs_finfo->rf_vp) {
9244 9534 rfs4_lo_state_rele(lsp, TRUE);
9245 9535 *cs->statusp = resp->status = NFS4ERR_BAD_STATEID;
9246 9536 DTRACE_NFSV4_2(op__locku__done, struct compound_state *, cs,
9247 9537 LOCKU4res *, resp);
9248 9538 return;
9249 9539 }
9250 9540
9251 9541 /* hold off other access to lsp while we tinker */
9252 9542 rfs4_sw_enter(&lsp->rls_sw);
9253 9543
9254 9544 switch (rfs4_check_lo_stateid_seqid(lsp, stateid)) {
9255 9545 case NFS4_CHECK_STATEID_OKAY:
9256 9546 if (rfs4_check_lock_seqid(args->seqid, lsp, resop)
9257 9547 != NFS4_CHKSEQ_OKAY) {
9258 9548 *cs->statusp = resp->status = NFS4ERR_BAD_SEQID;
9259 9549 goto end;
9260 9550 }
9261 9551 break;
9262 9552 case NFS4_CHECK_STATEID_OLD:
9263 9553 *cs->statusp = resp->status = NFS4ERR_OLD_STATEID;
9264 9554 goto end;
9265 9555 case NFS4_CHECK_STATEID_BAD:
9266 9556 *cs->statusp = resp->status = NFS4ERR_BAD_STATEID;
9267 9557 goto end;
9268 9558 case NFS4_CHECK_STATEID_EXPIRED:
9269 9559 *cs->statusp = resp->status = NFS4ERR_EXPIRED;
9270 9560 goto end;
9271 9561 case NFS4_CHECK_STATEID_CLOSED:
9272 9562 *cs->statusp = resp->status = NFS4ERR_OLD_STATEID;
9273 9563 goto end;
9274 9564 case NFS4_CHECK_STATEID_REPLAY:
9275 9565 switch (rfs4_check_lock_seqid(args->seqid, lsp, resop)) {
9276 9566 case NFS4_CHKSEQ_OKAY:
9277 9567 /*
9278 9568 * This is a replayed stateid; if
9279 9569 * seqid matches the next expected,
9280 9570 * then client is using wrong seqid.
9281 9571 */
9282 9572 case NFS4_CHKSEQ_BAD:
9283 9573 *cs->statusp = resp->status = NFS4ERR_BAD_SEQID;
9284 9574 goto end;
9285 9575 case NFS4_CHKSEQ_REPLAY:
9286 9576 rfs4_update_lease(lsp->rls_locker->rl_client);
9287 9577 *cs->statusp = status = resp->status;
9288 9578 goto end;
9289 9579 }
9290 9580 break;
9291 9581 default:
9292 9582 ASSERT(FALSE);
9293 9583 break;
9294 9584 }
9295 9585
9296 9586 rfs4_update_lock_sequence(lsp);
9297 9587 rfs4_update_lease(lsp->rls_locker->rl_client);
9298 9588
9299 9589 /*
9300 9590 * NFS4 only allows locking on regular files, so
9301 9591 * verify type of object.
9302 9592 */
9303 9593 if (cs->vp->v_type != VREG) {
9304 9594 if (cs->vp->v_type == VDIR)
9305 9595 status = NFS4ERR_ISDIR;
9306 9596 else
9307 9597 status = NFS4ERR_INVAL;
9308 9598 goto out;
9309 9599 }
9310 9600
9311 9601 if (rfs4_clnt_in_grace(lsp->rls_state->rs_owner->ro_client)) {
9312 9602 status = NFS4ERR_GRACE;
9313 9603 goto out;
9314 9604 }
9315 9605
9316 9606 status = rfs4_do_lock(lsp, args->locktype,
9317 9607 args->offset, args->length, cs->cr, resop);
9318 9608
9319 9609 out:
9320 9610 *cs->statusp = resp->status = status;
9321 9611
9322 9612 if (status == NFS4_OK)
9323 9613 resp->lock_stateid = lsp->rls_lockid.stateid;
9324 9614
9325 9615 rfs4_update_lock_resp(lsp, resop);
9326 9616
9327 9617 end:
9328 9618 rfs4_sw_exit(&lsp->rls_sw);
9329 9619 rfs4_lo_state_rele(lsp, TRUE);
9330 9620
9331 9621 DTRACE_NFSV4_2(op__locku__done, struct compound_state *, cs,
9332 9622 LOCKU4res *, resp);
9333 9623 }
9334 9624
9335 9625 /*
9336 9626 * LOCKT is a best effort routine, the client can not be guaranteed that
9337 9627 * the status return is still in effect by the time the reply is received.
9338 9628 * They are numerous race conditions in this routine, but we are not required
9339 9629 * and can not be accurate.
9340 9630 */
9341 9631 /*ARGSUSED*/
9342 9632 void
9343 9633 rfs4_op_lockt(nfs_argop4 *argop, nfs_resop4 *resop,
9344 9634 struct svc_req *req, struct compound_state *cs)
9345 9635 {
9346 9636 LOCKT4args *args = &argop->nfs_argop4_u.oplockt;
9347 9637 LOCKT4res *resp = &resop->nfs_resop4_u.oplockt;
9348 9638 rfs4_lockowner_t *lo;
9349 9639 rfs4_client_t *cp;
9350 9640 bool_t create = FALSE;
9351 9641 struct flock64 flk;
9352 9642 int error;
9353 9643 int flag = FREAD | FWRITE;
9354 9644 int ltype;
9355 9645 length4 posix_length;
9356 9646 sysid_t sysid;
9357 9647 pid_t pid;
9358 9648
9359 9649 DTRACE_NFSV4_2(op__lockt__start, struct compound_state *, cs,
9360 9650 LOCKT4args *, args);
9361 9651
9362 9652 if (cs->vp == NULL) {
9363 9653 *cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
9364 9654 goto out;
9365 9655 }
9366 9656
9367 9657 /*
9368 9658 * NFS4 only allows locking on regular files, so
9369 9659 * verify type of object.
9370 9660 */
9371 9661 if (cs->vp->v_type != VREG) {
9372 9662 if (cs->vp->v_type == VDIR)
9373 9663 *cs->statusp = resp->status = NFS4ERR_ISDIR;
9374 9664 else
9375 9665 *cs->statusp = resp->status = NFS4ERR_INVAL;
9376 9666 goto out;
9377 9667 }
9378 9668
9379 9669 /*
9380 9670 * Check out the clientid to ensure the server knows about it
9381 9671 * so that we correctly inform the client of a server reboot.
9382 9672 */
9383 9673 if ((cp = rfs4_findclient_by_id(args->owner.clientid, FALSE))
9384 9674 == NULL) {
9385 9675 *cs->statusp = resp->status =
9386 9676 rfs4_check_clientid(&args->owner.clientid, 0);
9387 9677 goto out;
9388 9678 }
9389 9679 if (rfs4_lease_expired(cp)) {
9390 9680 rfs4_client_close(cp);
9391 9681 /*
9392 9682 * Protocol doesn't allow returning NFS4ERR_STALE as
9393 9683 * other operations do on this check so STALE_CLIENTID
9394 9684 * is returned instead
9395 9685 */
9396 9686 *cs->statusp = resp->status = NFS4ERR_STALE_CLIENTID;
9397 9687 goto out;
9398 9688 }
9399 9689
9400 9690 if (rfs4_clnt_in_grace(cp) && !(cp->rc_can_reclaim)) {
9401 9691 *cs->statusp = resp->status = NFS4ERR_GRACE;
9402 9692 rfs4_client_rele(cp);
9403 9693 goto out;
9404 9694 }
9405 9695 rfs4_client_rele(cp);
9406 9696
9407 9697 resp->status = NFS4_OK;
9408 9698
9409 9699 switch (args->locktype) {
9410 9700 case READ_LT:
9411 9701 case READW_LT:
9412 9702 ltype = F_RDLCK;
9413 9703 break;
9414 9704 case WRITE_LT:
9415 9705 case WRITEW_LT:
9416 9706 ltype = F_WRLCK;
9417 9707 break;
9418 9708 }
9419 9709
9420 9710 posix_length = args->length;
9421 9711 /* Check for zero length. To lock to end of file use all ones for V4 */
9422 9712 if (posix_length == 0) {
9423 9713 *cs->statusp = resp->status = NFS4ERR_INVAL;
9424 9714 goto out;
9425 9715 } else if (posix_length == (length4)(~0)) {
9426 9716 posix_length = 0; /* Posix to end of file */
9427 9717 }
9428 9718
9429 9719 /* Find or create a lockowner */
9430 9720 lo = rfs4_findlockowner(&args->owner, &create);
9431 9721
9432 9722 if (lo) {
9433 9723 pid = lo->rl_pid;
9434 9724 if ((resp->status =
9435 9725 rfs4_client_sysid(lo->rl_client, &sysid)) != NFS4_OK)
9436 9726 goto err;
9437 9727 } else {
9438 9728 pid = 0;
9439 9729 sysid = lockt_sysid;
9440 9730 }
9441 9731 retry:
9442 9732 flk.l_type = ltype;
9443 9733 flk.l_whence = 0; /* SEEK_SET */
9444 9734 flk.l_start = args->offset;
9445 9735 flk.l_len = posix_length;
9446 9736 flk.l_sysid = sysid;
9447 9737 flk.l_pid = pid;
9448 9738 flag |= F_REMOTELOCK;
9449 9739
9450 9740 LOCK_PRINT(rfs4_debug, "rfs4_op_lockt", F_GETLK, &flk);
9451 9741
9452 9742 /* Note that length4 is uint64_t but l_len and l_start are off64_t */
9453 9743 if (flk.l_len < 0 || flk.l_start < 0) {
9454 9744 resp->status = NFS4ERR_INVAL;
9455 9745 goto err;
9456 9746 }
9457 9747 error = VOP_FRLOCK(cs->vp, F_GETLK, &flk, flag, (u_offset_t)0,
9458 9748 NULL, cs->cr, NULL);
9459 9749
9460 9750 /*
9461 9751 * N.B. We map error values to nfsv4 errors. This is differrent
9462 9752 * than puterrno4 routine.
9463 9753 */
9464 9754 switch (error) {
9465 9755 case 0:
9466 9756 if (flk.l_type == F_UNLCK)
9467 9757 resp->status = NFS4_OK;
9468 9758 else {
9469 9759 if (lock_denied(&resp->denied, &flk) == NFS4ERR_EXPIRED)
9470 9760 goto retry;
9471 9761 resp->status = NFS4ERR_DENIED;
9472 9762 }
9473 9763 break;
9474 9764 case EOVERFLOW:
9475 9765 resp->status = NFS4ERR_INVAL;
9476 9766 break;
9477 9767 case EINVAL:
9478 9768 resp->status = NFS4ERR_NOTSUPP;
9479 9769 break;
9480 9770 default:
9481 9771 cmn_err(CE_WARN, "rfs4_op_lockt: unexpected errno (%d)",
9482 9772 error);
9483 9773 resp->status = NFS4ERR_SERVERFAULT;
9484 9774 break;
9485 9775 }
9486 9776
9487 9777 err:
9488 9778 if (lo)
9489 9779 rfs4_lockowner_rele(lo);
9490 9780 *cs->statusp = resp->status;
9491 9781 out:
9492 9782 DTRACE_NFSV4_2(op__lockt__done, struct compound_state *, cs,
9493 9783 LOCKT4res *, resp);
9494 9784 }
9495 9785
9496 9786 int
9497 9787 rfs4_share(rfs4_state_t *sp, uint32_t access, uint32_t deny)
9498 9788 {
9499 9789 int err;
9500 9790 int cmd;
9501 9791 vnode_t *vp;
9502 9792 struct shrlock shr;
9503 9793 struct shr_locowner shr_loco;
9504 9794 int fflags = 0;
9505 9795
9506 9796 ASSERT(rfs4_dbe_islocked(sp->rs_dbe));
9507 9797 ASSERT(sp->rs_owner->ro_client->rc_sysidt != LM_NOSYSID);
9508 9798
9509 9799 if (sp->rs_closed)
9510 9800 return (NFS4ERR_OLD_STATEID);
9511 9801
9512 9802 vp = sp->rs_finfo->rf_vp;
9513 9803 ASSERT(vp);
9514 9804
9515 9805 shr.s_access = shr.s_deny = 0;
9516 9806
9517 9807 if (access & OPEN4_SHARE_ACCESS_READ) {
9518 9808 fflags |= FREAD;
9519 9809 shr.s_access |= F_RDACC;
9520 9810 }
9521 9811 if (access & OPEN4_SHARE_ACCESS_WRITE) {
9522 9812 fflags |= FWRITE;
9523 9813 shr.s_access |= F_WRACC;
9524 9814 }
9525 9815 ASSERT(shr.s_access);
9526 9816
9527 9817 if (deny & OPEN4_SHARE_DENY_READ)
9528 9818 shr.s_deny |= F_RDDNY;
9529 9819 if (deny & OPEN4_SHARE_DENY_WRITE)
9530 9820 shr.s_deny |= F_WRDNY;
9531 9821
9532 9822 shr.s_pid = rfs4_dbe_getid(sp->rs_owner->ro_dbe);
9533 9823 shr.s_sysid = sp->rs_owner->ro_client->rc_sysidt;
9534 9824 shr_loco.sl_pid = shr.s_pid;
9535 9825 shr_loco.sl_id = shr.s_sysid;
9536 9826 shr.s_owner = (caddr_t)&shr_loco;
9537 9827 shr.s_own_len = sizeof (shr_loco);
9538 9828
9539 9829 cmd = nbl_need_check(vp) ? F_SHARE_NBMAND : F_SHARE;
9540 9830
9541 9831 err = VOP_SHRLOCK(vp, cmd, &shr, fflags, CRED(), NULL);
9542 9832 if (err != 0) {
9543 9833 if (err == EAGAIN)
9544 9834 err = NFS4ERR_SHARE_DENIED;
9545 9835 else
9546 9836 err = puterrno4(err);
9547 9837 return (err);
9548 9838 }
9549 9839
9550 9840 sp->rs_share_access |= access;
9551 9841 sp->rs_share_deny |= deny;
9552 9842
9553 9843 return (0);
9554 9844 }
9555 9845
9556 9846 int
9557 9847 rfs4_unshare(rfs4_state_t *sp)
9558 9848 {
9559 9849 int err;
9560 9850 struct shrlock shr;
9561 9851 struct shr_locowner shr_loco;
9562 9852
9563 9853 ASSERT(rfs4_dbe_islocked(sp->rs_dbe));
9564 9854
9565 9855 if (sp->rs_closed || sp->rs_share_access == 0)
9566 9856 return (0);
9567 9857
9568 9858 ASSERT(sp->rs_owner->ro_client->rc_sysidt != LM_NOSYSID);
9569 9859 ASSERT(sp->rs_finfo->rf_vp);
9570 9860
9571 9861 shr.s_access = shr.s_deny = 0;
9572 9862 shr.s_pid = rfs4_dbe_getid(sp->rs_owner->ro_dbe);
9573 9863 shr.s_sysid = sp->rs_owner->ro_client->rc_sysidt;
9574 9864 shr_loco.sl_pid = shr.s_pid;
9575 9865 shr_loco.sl_id = shr.s_sysid;
9576 9866 shr.s_owner = (caddr_t)&shr_loco;
9577 9867 shr.s_own_len = sizeof (shr_loco);
9578 9868
9579 9869 err = VOP_SHRLOCK(sp->rs_finfo->rf_vp, F_UNSHARE, &shr, 0, CRED(),
9580 9870 NULL);
9581 9871 if (err != 0) {
9582 9872 err = puterrno4(err);
9583 9873 return (err);
9584 9874 }
9585 9875
9586 9876 sp->rs_share_access = 0;
9587 9877 sp->rs_share_deny = 0;
9588 9878
9589 9879 return (0);
9590 9880
9591 9881 }
9592 9882
9593 9883 static int
9594 9884 rdma_setup_read_data4(READ4args *args, READ4res *rok)
9595 9885 {
9596 9886 struct clist *wcl;
9597 9887 count4 count = rok->data_len;
9598 9888 int wlist_len;
9599 9889
9600 9890 wcl = args->wlist;
9601 9891 if (rdma_setup_read_chunks(wcl, count, &wlist_len) == FALSE) {
9602 9892 return (FALSE);
9603 9893 }
9604 9894 wcl = args->wlist;
9605 9895 rok->wlist_len = wlist_len;
9606 9896 rok->wlist = wcl;
9607 9897 return (TRUE);
9608 9898 }
9609 9899
9610 9900 /* tunable to disable server referrals */
9611 9901 int rfs4_no_referrals = 0;
9612 9902
9613 9903 /*
9614 9904 * Find an NFS record in reparse point data.
9615 9905 * Returns 0 for success and <0 or an errno value on failure.
9616 9906 */
9617 9907 int
9618 9908 vn_find_nfs_record(vnode_t *vp, nvlist_t **nvlp, char **svcp, char **datap)
9619 9909 {
9620 9910 int err;
9621 9911 char *stype, *val;
9622 9912 nvlist_t *nvl;
9623 9913 nvpair_t *curr;
9624 9914
9625 9915 if ((nvl = reparse_init()) == NULL)
9626 9916 return (-1);
9627 9917
9628 9918 if ((err = reparse_vnode_parse(vp, nvl)) != 0) {
9629 9919 reparse_free(nvl);
9630 9920 return (err);
9631 9921 }
9632 9922
9633 9923 curr = NULL;
9634 9924 while ((curr = nvlist_next_nvpair(nvl, curr)) != NULL) {
9635 9925 if ((stype = nvpair_name(curr)) == NULL) {
9636 9926 reparse_free(nvl);
9637 9927 return (-2);
9638 9928 }
9639 9929 if (strncasecmp(stype, "NFS", 3) == 0)
9640 9930 break;
9641 9931 }
9642 9932
9643 9933 if ((curr == NULL) ||
9644 9934 (nvpair_value_string(curr, &val))) {
9645 9935 reparse_free(nvl);
9646 9936 return (-3);
9647 9937 }
9648 9938 *nvlp = nvl;
9649 9939 *svcp = stype;
9650 9940 *datap = val;
9651 9941 return (0);
9652 9942 }
9653 9943
9654 9944 int
9655 9945 vn_is_nfs_reparse(vnode_t *vp, cred_t *cr)
9656 9946 {
9657 9947 nvlist_t *nvl;
9658 9948 char *s, *d;
9659 9949
9660 9950 if (rfs4_no_referrals != 0)
9661 9951 return (B_FALSE);
9662 9952
9663 9953 if (vn_is_reparse(vp, cr, NULL) == B_FALSE)
9664 9954 return (B_FALSE);
9665 9955
9666 9956 if (vn_find_nfs_record(vp, &nvl, &s, &d) != 0)
9667 9957 return (B_FALSE);
9668 9958
9669 9959 reparse_free(nvl);
9670 9960
9671 9961 return (B_TRUE);
9672 9962 }
9673 9963
9674 9964 /*
9675 9965 * There is a user-level copy of this routine in ref_subr.c.
9676 9966 * Changes should be kept in sync.
9677 9967 */
9678 9968 static int
9679 9969 nfs4_create_components(char *path, component4 *comp4)
9680 9970 {
9681 9971 int slen, plen, ncomp;
9682 9972 char *ori_path, *nxtc, buf[MAXNAMELEN];
9683 9973
9684 9974 if (path == NULL)
9685 9975 return (0);
9686 9976
9687 9977 plen = strlen(path) + 1; /* include the terminator */
9688 9978 ori_path = path;
9689 9979 ncomp = 0;
9690 9980
9691 9981 /* count number of components in the path */
9692 9982 for (nxtc = path; nxtc < ori_path + plen; nxtc++) {
9693 9983 if (*nxtc == '/' || *nxtc == '\0' || *nxtc == '\n') {
9694 9984 if ((slen = nxtc - path) == 0) {
9695 9985 path = nxtc + 1;
9696 9986 continue;
9697 9987 }
9698 9988
9699 9989 if (comp4 != NULL) {
9700 9990 bcopy(path, buf, slen);
9701 9991 buf[slen] = '\0';
9702 9992 (void) str_to_utf8(buf, &comp4[ncomp]);
9703 9993 }
9704 9994
9705 9995 ncomp++; /* 1 valid component */
9706 9996 path = nxtc + 1;
9707 9997 }
9708 9998 if (*nxtc == '\0' || *nxtc == '\n')
9709 9999 break;
9710 10000 }
9711 10001
9712 10002 return (ncomp);
9713 10003 }
9714 10004
9715 10005 /*
9716 10006 * There is a user-level copy of this routine in ref_subr.c.
9717 10007 * Changes should be kept in sync.
9718 10008 */
9719 10009 static int
9720 10010 make_pathname4(char *path, pathname4 *pathname)
9721 10011 {
9722 10012 int ncomp;
9723 10013 component4 *comp4;
9724 10014
9725 10015 if (pathname == NULL)
9726 10016 return (0);
9727 10017
9728 10018 if (path == NULL) {
9729 10019 pathname->pathname4_val = NULL;
9730 10020 pathname->pathname4_len = 0;
9731 10021 return (0);
9732 10022 }
9733 10023
9734 10024 /* count number of components to alloc buffer */
9735 10025 if ((ncomp = nfs4_create_components(path, NULL)) == 0) {
9736 10026 pathname->pathname4_val = NULL;
9737 10027 pathname->pathname4_len = 0;
9738 10028 return (0);
9739 10029 }
9740 10030 comp4 = kmem_zalloc(ncomp * sizeof (component4), KM_SLEEP);
9741 10031
9742 10032 /* copy components into allocated buffer */
9743 10033 ncomp = nfs4_create_components(path, comp4);
9744 10034
9745 10035 pathname->pathname4_val = comp4;
9746 10036 pathname->pathname4_len = ncomp;
9747 10037
9748 10038 return (ncomp);
9749 10039 }
9750 10040
9751 10041 #define xdr_fs_locations4 xdr_fattr4_fs_locations
9752 10042
9753 10043 fs_locations4 *
9754 10044 fetch_referral(vnode_t *vp, cred_t *cr)
9755 10045 {
9756 10046 nvlist_t *nvl;
9757 10047 char *stype, *sdata;
9758 10048 fs_locations4 *result;
9759 10049 char buf[1024];
9760 10050 size_t bufsize;
9761 10051 XDR xdr;
9762 10052 int err;
9763 10053
9764 10054 /*
9765 10055 * Check attrs to ensure it's a reparse point
9766 10056 */
9767 10057 if (vn_is_reparse(vp, cr, NULL) == B_FALSE)
9768 10058 return (NULL);
9769 10059
9770 10060 /*
9771 10061 * Look for an NFS record and get the type and data
9772 10062 */
9773 10063 if (vn_find_nfs_record(vp, &nvl, &stype, &sdata) != 0)
9774 10064 return (NULL);
9775 10065
9776 10066 /*
9777 10067 * With the type and data, upcall to get the referral
9778 10068 */
9779 10069 bufsize = sizeof (buf);
9780 10070 bzero(buf, sizeof (buf));
9781 10071 err = reparse_kderef((const char *)stype, (const char *)sdata,
9782 10072 buf, &bufsize);
9783 10073 reparse_free(nvl);
9784 10074
9785 10075 DTRACE_PROBE4(nfs4serv__func__referral__upcall,
9786 10076 char *, stype, char *, sdata, char *, buf, int, err);
9787 10077 if (err) {
9788 10078 cmn_err(CE_NOTE,
9789 10079 "reparsed daemon not running: unable to get referral (%d)",
9790 10080 err);
9791 10081 return (NULL);
9792 10082 }
9793 10083
9794 10084 /*
9795 10085 * We get an XDR'ed record back from the kderef call
9796 10086 */
9797 10087 xdrmem_create(&xdr, buf, bufsize, XDR_DECODE);
9798 10088 result = kmem_alloc(sizeof (fs_locations4), KM_SLEEP);
9799 10089 err = xdr_fs_locations4(&xdr, result);
9800 10090 XDR_DESTROY(&xdr);
9801 10091 if (err != TRUE) {
9802 10092 DTRACE_PROBE1(nfs4serv__func__referral__upcall__xdrfail,
9803 10093 int, err);
9804 10094 return (NULL);
9805 10095 }
9806 10096
9807 10097 /*
9808 10098 * Look at path to recover fs_root, ignoring the leading '/'
9809 10099 */
9810 10100 (void) make_pathname4(vp->v_path, &result->fs_root);
9811 10101
9812 10102 return (result);
9813 10103 }
9814 10104
9815 10105 char *
9816 10106 build_symlink(vnode_t *vp, cred_t *cr, size_t *strsz)
9817 10107 {
9818 10108 fs_locations4 *fsl;
9819 10109 fs_location4 *fs;
9820 10110 char *server, *path, *symbuf;
9821 10111 static char *prefix = "/net/";
9822 10112 int i, size, npaths;
9823 10113 uint_t len;
9824 10114
9825 10115 /* Get the referral */
9826 10116 if ((fsl = fetch_referral(vp, cr)) == NULL)
9827 10117 return (NULL);
9828 10118
9829 10119 /* Deal with only the first location and first server */
9830 10120 fs = &fsl->locations_val[0];
9831 10121 server = utf8_to_str(&fs->server_val[0], &len, NULL);
9832 10122 if (server == NULL) {
9833 10123 rfs4_free_fs_locations4(fsl);
9834 10124 kmem_free(fsl, sizeof (fs_locations4));
9835 10125 return (NULL);
9836 10126 }
9837 10127
9838 10128 /* Figure out size for "/net/" + host + /path/path/path + NULL */
9839 10129 size = strlen(prefix) + len;
9840 10130 for (i = 0; i < fs->rootpath.pathname4_len; i++)
9841 10131 size += fs->rootpath.pathname4_val[i].utf8string_len + 1;
9842 10132
9843 10133 /* Allocate the symlink buffer and fill it */
9844 10134 symbuf = kmem_zalloc(size, KM_SLEEP);
9845 10135 (void) strcat(symbuf, prefix);
9846 10136 (void) strcat(symbuf, server);
9847 10137 kmem_free(server, len);
9848 10138
9849 10139 npaths = 0;
9850 10140 for (i = 0; i < fs->rootpath.pathname4_len; i++) {
9851 10141 path = utf8_to_str(&fs->rootpath.pathname4_val[i], &len, NULL);
9852 10142 if (path == NULL)
9853 10143 continue;
9854 10144 (void) strcat(symbuf, "/");
9855 10145 (void) strcat(symbuf, path);
9856 10146 npaths++;
9857 10147 kmem_free(path, len);
9858 10148 }
9859 10149
9860 10150 rfs4_free_fs_locations4(fsl);
9861 10151 kmem_free(fsl, sizeof (fs_locations4));
9862 10152
9863 10153 if (strsz != NULL)
9864 10154 *strsz = size;
9865 10155 return (symbuf);
9866 10156 }
9867 10157
9868 10158 /*
9869 10159 * Check to see if we have a downrev Solaris client, so that we
9870 10160 * can send it a symlink instead of a referral.
9871 10161 */
9872 10162 int
9873 10163 client_is_downrev(struct svc_req *req)
9874 10164 {
9875 10165 struct sockaddr *ca;
9876 10166 rfs4_clntip_t *ci;
9877 10167 bool_t create = FALSE;
|
↓ open down ↓ |
1623 lines elided |
↑ open up ↑ |
9878 10168 int is_downrev;
9879 10169
9880 10170 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
9881 10171 ASSERT(ca);
9882 10172 ci = rfs4_find_clntip(ca, &create);
9883 10173 if (ci == NULL)
9884 10174 return (0);
9885 10175 is_downrev = ci->ri_no_referrals;
9886 10176 rfs4_dbe_rele(ci->ri_dbe);
9887 10177 return (is_downrev);
10178 +}
10179 +
10180 +/*
10181 + * Do the main work of handling HA-NFSv4 Resource Group failover on
10182 + * Sun Cluster.
10183 + * We need to detect whether any RG admin paths have been added or removed,
10184 + * and adjust resources accordingly.
10185 + * Currently we're using a very inefficient algorithm, ~ 2 * O(n**2). In
10186 + * order to scale, the list and array of paths need to be held in more
10187 + * suitable data structures.
10188 + */
10189 +static void
10190 +hanfsv4_failover(nfs4_srv_t *nsrv4)
10191 +{
10192 + int i, start_grace, numadded_paths = 0;
10193 + char **added_paths = NULL;
10194 + rfs4_dss_path_t *dss_path;
10195 +
10196 + /*
10197 + * Note: currently, dss_pathlist cannot be NULL, since
10198 + * it will always include an entry for NFS4_DSS_VAR_DIR. If we
10199 + * make the latter dynamically specified too, the following will
10200 + * need to be adjusted.
10201 + */
10202 +
10203 + /*
10204 + * First, look for removed paths: RGs that have been failed-over
10205 + * away from this node.
10206 + * Walk the "currently-serving" dss_pathlist and, for each
10207 + * path, check if it is on the "passed-in" rfs4_dss_newpaths array
10208 + * from nfsd. If not, that RG path has been removed.
10209 + *
10210 + * Note that nfsd has sorted rfs4_dss_newpaths for us, and removed
10211 + * any duplicates.
10212 + */
10213 + dss_path = nsrv4->dss_pathlist;
10214 + do {
10215 + int found = 0;
10216 + char *path = dss_path->path;
10217 +
10218 + /* used only for non-HA so may not be removed */
10219 + if (strcmp(path, NFS4_DSS_VAR_DIR) == 0) {
10220 + dss_path = dss_path->next;
10221 + continue;
10222 + }
10223 +
10224 + for (i = 0; i < rfs4_dss_numnewpaths; i++) {
10225 + int cmpret;
10226 + char *newpath = rfs4_dss_newpaths[i];
10227 +
10228 + /*
10229 + * Since nfsd has sorted rfs4_dss_newpaths for us,
10230 + * once the return from strcmp is negative we know
10231 + * we've passed the point where "path" should be,
10232 + * and can stop searching: "path" has been removed.
10233 + */
10234 + cmpret = strcmp(path, newpath);
10235 + if (cmpret < 0)
10236 + break;
10237 + if (cmpret == 0) {
10238 + found = 1;
10239 + break;
10240 + }
10241 + }
10242 +
10243 + if (found == 0) {
10244 + unsigned index = dss_path->index;
10245 + rfs4_servinst_t *sip = dss_path->sip;
10246 + rfs4_dss_path_t *path_next = dss_path->next;
10247 +
10248 + /*
10249 + * This path has been removed.
10250 + * We must clear out the servinst reference to
10251 + * it, since it's now owned by another
10252 + * node: we should not attempt to touch it.
10253 + */
10254 + ASSERT(dss_path == sip->dss_paths[index]);
10255 + sip->dss_paths[index] = NULL;
10256 +
10257 + /* remove from "currently-serving" list, and destroy */
10258 + remque(dss_path);
10259 + /* allow for NUL */
10260 + kmem_free(dss_path->path, strlen(dss_path->path) + 1);
10261 + kmem_free(dss_path, sizeof (rfs4_dss_path_t));
10262 +
10263 + dss_path = path_next;
10264 + } else {
10265 + /* path was found; not removed */
10266 + dss_path = dss_path->next;
10267 + }
10268 + } while (dss_path != nsrv4->dss_pathlist);
10269 +
10270 + /*
10271 + * Now, look for added paths: RGs that have been failed-over
10272 + * to this node.
10273 + * Walk the "passed-in" rfs4_dss_newpaths array from nfsd and,
10274 + * for each path, check if it is on the "currently-serving"
10275 + * dss_pathlist. If not, that RG path has been added.
10276 + *
10277 + * Note: we don't do duplicate detection here; nfsd does that for us.
10278 + *
10279 + * Note: numadded_paths <= rfs4_dss_numnewpaths, which gives us
10280 + * an upper bound for the size needed for added_paths[numadded_paths].
10281 + */
10282 +
10283 + /* probably more space than we need, but guaranteed to be enough */
10284 + if (rfs4_dss_numnewpaths > 0) {
10285 + size_t sz = rfs4_dss_numnewpaths * sizeof (char *);
10286 + added_paths = kmem_zalloc(sz, KM_SLEEP);
10287 + }
10288 +
10289 + /* walk the "passed-in" rfs4_dss_newpaths array from nfsd */
10290 + for (i = 0; i < rfs4_dss_numnewpaths; i++) {
10291 + int found = 0;
10292 + char *newpath = rfs4_dss_newpaths[i];
10293 +
10294 + dss_path = nsrv4->dss_pathlist;
10295 + do {
10296 + char *path = dss_path->path;
10297 +
10298 + /* used only for non-HA */
10299 + if (strcmp(path, NFS4_DSS_VAR_DIR) == 0) {
10300 + dss_path = dss_path->next;
10301 + continue;
10302 + }
10303 +
10304 + if (strncmp(path, newpath, strlen(path)) == 0) {
10305 + found = 1;
10306 + break;
10307 + }
10308 +
10309 + dss_path = dss_path->next;
10310 + } while (dss_path != nsrv4->dss_pathlist);
10311 +
10312 + if (found == 0) {
10313 + added_paths[numadded_paths] = newpath;
10314 + numadded_paths++;
10315 + }
10316 + }
10317 +
10318 + /* did we find any added paths? */
10319 + if (numadded_paths > 0) {
10320 +
10321 + /* create a new server instance, and start its grace period */
10322 + start_grace = 1;
10323 + /* CSTYLED */
10324 + rfs4_servinst_create(nsrv4, start_grace, numadded_paths, added_paths);
10325 +
10326 + /* read in the stable storage state from these paths */
10327 + rfs4_dss_readstate(nsrv4, numadded_paths, added_paths);
10328 +
10329 + /*
10330 + * Multiple failovers during a grace period will cause
10331 + * clients of the same resource group to be partitioned
10332 + * into different server instances, with different
10333 + * grace periods. Since clients of the same resource
10334 + * group must be subject to the same grace period,
10335 + * we need to reset all currently active grace periods.
10336 + */
10337 + rfs4_grace_reset_all(nsrv4);
10338 + }
10339 +
10340 + if (rfs4_dss_numnewpaths > 0)
10341 + kmem_free(added_paths, rfs4_dss_numnewpaths * sizeof (char *));
9888 10342 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX