4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
28 #pragma ident "%Z%%M% %I% %E% SMI"
30 #include <rpc/types.h>
32 #include <sys/t_lock.h>
34 #include <sys/fcntl.h>
37 #include <sys/promif.h>
41 #include <sys/bootvfs.h>
42 #include <sys/bootdebug.h>
43 #include <sys/salib.h>
44 #include <sys/sacache.h>
47 #include <rpcsvc/nfs_prot.h>
49 #define dprintf if (boothowto & RB_DEBUG) printf
52 * NFS Version 3 specific functions
56 nfs3read(struct nfs_file
*filep
, char *buf
, size_t size
)
60 enum clnt_stat read_stat
;
61 uint_t readcnt
= 0; /* # bytes read by nfs */
62 uint_t count
= 0; /* # bytes transferred to buf */
63 int done
= FALSE
; /* last block has come in */
64 int framing_errs
= 0; /* stack errors */
65 char *buf_offset
; /* current buffer offset */
66 struct timeval timeout
;
67 static uint_t pos
; /* progress indicator counter */
68 static char ind
[] = "|/-\\"; /* progress indicator */
71 read_args
.file
.data
.data_len
= filep
->fh
.fh3
.len
;
72 read_args
.file
.data
.data_val
= filep
->fh
.fh3
.data
;
73 read_args
.offset
= filep
->offset
;
75 bzero(&read_res
, sizeof (read_res
));
79 /* Optimize for reads of less than one block size */
81 if (nfs_readsize
== 0)
82 nfs_readsize
= READ3_SIZE
;
84 if (size
< nfs_readsize
)
85 read_args
.count
= size
;
87 read_args
.count
= nfs_readsize
;
90 /* use the user's buffer to stuff the data into. */
91 read_res
.READ3res_u
.resok
.data
.data_val
= buf_offset
;
94 * Handle the case where the file does not end
95 * on a block boundary.
97 if ((count
+ read_args
.count
) > size
)
98 read_args
.count
= size
- count
;
100 timeout
.tv_sec
= NFS_REXMIT_MIN
; /* Total wait for call */
103 read_stat
= CLNT_CALL(root_CLIENT
, NFSPROC3_READ
,
104 xdr_READ3args
, (caddr_t
)&read_args
,
105 xdr_READ3res
, (caddr_t
)&read_res
, timeout
);
107 if (read_stat
== RPC_TIMEDOUT
) {
108 dprintf("NFS read(%d) timed out. Retrying...\n",
111 * If the remote is there and trying to respond,
112 * but our stack is having trouble reassembling
113 * the reply, reduce the read size in an
114 * attempt to compensate. Reset the
115 * transmission and reply wait timers.
117 if (errno
== ETIMEDOUT
)
120 if (framing_errs
> NFS_MAX_FERRS
&&
121 read_args
.count
> NFS_READ_DECR
) {
122 read_args
.count
/= 2;
124 dprintf("NFS Read size now %d.\n",
126 timeout
.tv_sec
= NFS_REXMIT_MIN
;
129 if (timeout
.tv_sec
< NFS_REXMIT_MAX
)
136 } while (read_stat
== RPC_TIMEDOUT
);
138 if (read_stat
!= RPC_SUCCESS
)
141 if (read_res
.status
!= NFS3_OK
)
144 readcnt
= read_res
.READ3res_u
.resok
.data
.data_len
;
146 * If we are at EOF, update counts and exit
148 if (read_res
.READ3res_u
.resok
.eof
== TRUE
)
152 * Handle the case where the file is smaller than
153 * the size of the read request, thus the request
154 * couldn't be completely filled.
156 if (readcnt
< read_args
.count
) {
158 if ((boothowto
& DBFLAGS
) == DBFLAGS
)
159 printf("nfs3read(): partial read %d"
161 readcnt
, read_args
.count
);
163 done
= TRUE
; /* update the counts and exit */
166 /* update various offsets */
168 filep
->offset
+= readcnt
;
169 buf_offset
+= readcnt
;
170 read_args
.offset
+= readcnt
;
172 * round and round she goes (though not on every block..
173 * - OBP's take a fair bit of time to actually print stuff)
175 if ((blks_read
++ & 0x3) == 0)
176 printf("%c\b", ind
[pos
++ & 3]);
177 } while (count
< size
&& !done
);
183 nfs3getattr(struct nfs_file
*nfp
, struct vattr
*vap
)
185 enum clnt_stat getattr_stat
;
186 GETATTR3args getattr_args
;
187 GETATTR3res getattr_res
;
189 struct timeval timeout
= {0, 0}; /* default */
190 vtype_t nf3_to_vt
[] =
191 { VBAD
, VREG
, VDIR
, VBLK
, VCHR
, VLNK
, VSOCK
, VFIFO
};
194 bzero(&getattr_args
, sizeof (getattr_args
));
195 getattr_args
.object
.data
.data_len
= nfp
->fh
.fh3
.len
;
196 getattr_args
.object
.data
.data_val
= nfp
->fh
.fh3
.data
;
198 bzero(&getattr_res
, sizeof (getattr_res
));
200 getattr_stat
= CLNT_CALL(root_CLIENT
, NFSPROC3_GETATTR
,
201 xdr_GETATTR3args
, (caddr_t
)&getattr_args
,
202 xdr_GETATTR3res
, (caddr_t
)&getattr_res
, timeout
);
204 if (getattr_stat
!= RPC_SUCCESS
) {
205 dprintf("nfs_getattr: RPC error %d\n", getattr_stat
);
208 if (getattr_res
.status
!= NFS3_OK
) {
209 nfs3_error(getattr_res
.status
);
210 return (getattr_res
.status
);
213 na
= &getattr_res
.GETATTR3res_u
.resok
.obj_attributes
;
214 if (vap
->va_mask
& AT_TYPE
) {
215 if (na
->type
< NF3REG
|| na
->type
> NF3FIFO
)
218 vap
->va_type
= nf3_to_vt
[na
->type
];
220 if (vap
->va_mask
& AT_MODE
)
221 vap
->va_mode
= (mode_t
)na
->mode
;
222 if (vap
->va_mask
& AT_SIZE
)
223 vap
->va_size
= (u_offset_t
)na
->size
;
224 if (vap
->va_mask
& AT_NODEID
)
225 vap
->va_nodeid
= (u_longlong_t
)na
->fileid
;
226 if (vap
->va_mask
& AT_ATIME
) {
227 vap
->va_atime
.tv_sec
= na
->atime
.seconds
;
228 vap
->va_atime
.tv_nsec
= na
->atime
.nseconds
;
230 if (vap
->va_mask
& AT_CTIME
) {
231 vap
->va_ctime
.tv_sec
= na
->ctime
.seconds
;
232 vap
->va_ctime
.tv_nsec
= na
->ctime
.nseconds
;
234 if (vap
->va_mask
& AT_MTIME
) {
235 vap
->va_mtime
.tv_sec
= na
->mtime
.seconds
;
236 vap
->va_mtime
.tv_nsec
= na
->mtime
.nseconds
;
243 * Display nfs error messages.
247 nfs3_error(enum nfsstat3 status
)
249 if (!(boothowto
& RB_DEBUG
))
254 printf("NFS: No error.\n");
257 printf("NFS: Not owner.\n");
261 printf("NFS: No such file or directory.\n");
262 #endif /* NFS_OPS_DEBUG */
265 printf("NFS: IO ERROR occurred on NFS server.\n");
268 printf("NFS: No such device or address.\n");
271 printf("NFS: Permission denied.\n");
274 printf("NFS: File exists.\n");
277 printf("NFS: Cross device hard link.\n");
280 printf("NFS: No such device.\n");
283 printf("NFS: Not a directory.\n");
286 printf("NFS: Is a directory.\n");
289 printf("NFS: Invalid argument.\n");
292 printf("NFS: File too large.\n");
295 printf("NFS: No space left on device.\n");
298 printf("NFS: Read-only filesystem.\n");
301 printf("NFS: Too many hard links.\n");
303 case NFS3ERR_NAMETOOLONG
:
304 printf("NFS: File name too long.\n");
306 case NFS3ERR_NOTEMPTY
:
307 printf("NFS: Directory not empty.\n");
310 printf("NFS: Disk quota exceeded.\n");
313 printf("NFS: Stale file handle.\n");
316 printf("NFS: Remote file in path.\n");
318 case NFS3ERR_BADHANDLE
:
319 printf("NFS: Illegal NFS file handle.\n");
321 case NFS3ERR_NOT_SYNC
:
322 printf("NFS: Synchronization mismatch.\n");
324 case NFS3ERR_BAD_COOKIE
:
325 printf("NFS: Stale Cookie.\n");
327 case NFS3ERR_NOTSUPP
:
328 printf("NFS: Operation is not supported.\n");
330 case NFS3ERR_TOOSMALL
:
331 printf("NFS: Buffer too small.\n");
333 case NFS3ERR_SERVERFAULT
:
334 printf("NFS: Server fault.\n");
336 case NFS3ERR_BADTYPE
:
337 printf("NFS: Unsupported object type.\n");
339 case NFS3ERR_JUKEBOX
:
340 printf("NFS: Resource temporarily unavailable.\n");
343 printf("NFS: unknown error.\n");
349 nfs3lookup(struct nfs_file
*dir
, char *name
, int *nstat
)
351 struct timeval zero_timeout
= {0, 0}; /* default */
352 static struct nfs_file cd
;
354 LOOKUP3res res_lookup
;
355 enum clnt_stat status
;
357 *nstat
= (int)NFS3_OK
;
359 bzero((caddr_t
)&dirop
, sizeof (LOOKUP3args
));
360 bzero((caddr_t
)&res_lookup
, sizeof (LOOKUP3res
));
362 dirop
.what
.dir
.data
.data_len
= dir
->fh
.fh3
.len
;
363 dirop
.what
.dir
.data
.data_val
= dir
->fh
.fh3
.data
;
364 dirop
.what
.name
= name
;
366 status
= CLNT_CALL(root_CLIENT
, NFSPROC3_LOOKUP
, xdr_LOOKUP3args
,
367 (caddr_t
)&dirop
, xdr_LOOKUP3res
, (caddr_t
)&res_lookup
,
369 if (status
!= RPC_SUCCESS
) {
370 dprintf("lookup: RPC error.\n");
373 if (res_lookup
.status
!= NFS3_OK
) {
374 nfs3_error(res_lookup
.status
);
375 *nstat
= (int)res_lookup
.status
;
376 (void) CLNT_FREERES(root_CLIENT
,
377 xdr_LOOKUP3res
, (caddr_t
)&res_lookup
);
381 bzero((caddr_t
)&cd
, sizeof (struct nfs_file
));
384 * Server must supply post_op_attr's
386 if (res_lookup
.LOOKUP3res_u
.resok
.obj_attributes
.attributes_follow
==
388 printf("nfs3lookup: server fails to return post_op_attr\n");
389 (void) CLNT_FREERES(root_CLIENT
,
390 xdr_LOOKUP3res
, (caddr_t
)&res_lookup
);
394 cd
.ftype
.type3
= res_lookup
.LOOKUP3res_u
.resok
.obj_attributes
395 .post_op_attr_u
.attributes
.type
;
396 cd
.fh
.fh3
.len
= res_lookup
.LOOKUP3res_u
.resok
.object
.data
.data_len
;
397 bcopy(res_lookup
.LOOKUP3res_u
.resok
.object
.data
.data_val
,
398 cd
.fh
.fh3
.data
, cd
.fh
.fh3
.len
);
399 (void) CLNT_FREERES(root_CLIENT
, xdr_LOOKUP3res
, (caddr_t
)&res_lookup
);
404 * Gets symbolic link into pathname.
407 nfs3getsymlink(struct nfs_file
*cfile
, char **path
)
409 struct timeval zero_timeout
= {0, 0}; /* default */
410 enum clnt_stat status
;
411 struct READLINK3res linkres
;
412 struct READLINK3args linkargs
;
413 static char symlink_path
[NFS_MAXPATHLEN
];
415 bzero(&linkargs
, sizeof (linkargs
));
416 linkargs
.symlink
.data
.data_len
= cfile
->fh
.fh3
.len
;
417 linkargs
.symlink
.data
.data_val
= cfile
->fh
.fh3
.data
;
420 * linkres needs a zeroed buffer to place path data into:
422 bzero(&linkres
, sizeof (linkres
));
423 bzero(symlink_path
, NFS_MAXPATHLEN
);
424 linkres
.READLINK3res_u
.resok
.data
= symlink_path
;
426 status
= CLNT_CALL(root_CLIENT
, NFSPROC3_READLINK
,
427 xdr_READLINK3args
, (caddr_t
)&linkargs
,
428 xdr_READLINK3res
, (caddr_t
)&linkres
, zero_timeout
);
429 if (status
!= RPC_SUCCESS
) {
430 dprintf("nfs3getsymlink: RPC call failed.\n");
433 if (linkres
.status
!= NFS3_OK
) {
434 nfs3_error(linkres
.status
);
435 return (linkres
.status
);
438 *path
= symlink_path
;