1 /* 2 * CDDL HEADER START 3 * 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. 7 * 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. 12 * 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] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 * 25 * Simple nfs V3 ops 26 */ 27 28 #pragma ident "%Z%%M% %I% %E% SMI" 29 30 #include <rpc/types.h> 31 #include <rpc/auth.h> 32 #include <sys/t_lock.h> 33 #include "clnt.h" 34 #include <sys/fcntl.h> 35 #include <sys/vfs.h> 36 #include <errno.h> 37 #include <sys/promif.h> 38 #include <rpc/xdr.h> 39 #include "nfs_inet.h" 40 #include <sys/stat.h> 41 #include <sys/bootvfs.h> 42 #include <sys/bootdebug.h> 43 #include <sys/salib.h> 44 #include <sys/sacache.h> 45 #include <rpc/rpc.h> 46 #include "brpc.h" 47 #include <rpcsvc/nfs_prot.h> 48 49 #define dprintf if (boothowto & RB_DEBUG) printf 50 51 /* 52 * NFS Version 3 specific functions 53 */ 54 55 ssize_t 56 nfs3read(struct nfs_file *filep, char *buf, size_t size) 57 { 58 READ3args read_args; 59 READ3res read_res; 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 */ 69 static int blks_read; 70 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; 74 75 bzero(&read_res, sizeof (read_res)); 76 77 buf_offset = buf; 78 79 /* Optimize for reads of less than one block size */ 80 81 if (nfs_readsize == 0) 82 nfs_readsize = READ3_SIZE; 83 84 if (size < nfs_readsize) 85 read_args.count = size; 86 else 87 read_args.count = nfs_readsize; 88 89 do { 90 /* use the user's buffer to stuff the data into. */ 91 read_res.READ3res_u.resok.data.data_val = buf_offset; 92 93 /* 94 * Handle the case where the file does not end 95 * on a block boundary. 96 */ 97 if ((count + read_args.count) > size) 98 read_args.count = size - count; 99 100 timeout.tv_sec = NFS_REXMIT_MIN; /* Total wait for call */ 101 timeout.tv_usec = 0; 102 do { 103 read_stat = CLNT_CALL(root_CLIENT, NFSPROC3_READ, 104 xdr_READ3args, (caddr_t)&read_args, 105 xdr_READ3res, (caddr_t)&read_res, timeout); 106 107 if (read_stat == RPC_TIMEDOUT) { 108 dprintf("NFS read(%d) timed out. Retrying...\n", 109 read_args.count); 110 /* 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. 116 */ 117 if (errno == ETIMEDOUT) 118 framing_errs++; 119 120 if (framing_errs > NFS_MAX_FERRS && 121 read_args.count > NFS_READ_DECR) { 122 read_args.count /= 2; 123 nfs_readsize /= 2; 124 dprintf("NFS Read size now %d.\n", 125 nfs_readsize); 126 timeout.tv_sec = NFS_REXMIT_MIN; 127 framing_errs = 0; 128 } else { 129 if (timeout.tv_sec < NFS_REXMIT_MAX) 130 timeout.tv_sec++; 131 else 132 timeout.tv_sec = 0; 133 /* default RPC */ 134 } 135 } 136 } while (read_stat == RPC_TIMEDOUT); 137 138 if (read_stat != RPC_SUCCESS) 139 return (-1); 140 141 if (read_res.status != NFS3_OK) 142 return (-1); 143 144 readcnt = read_res.READ3res_u.resok.data.data_len; 145 /* 146 * If we are at EOF, update counts and exit 147 */ 148 if (read_res.READ3res_u.resok.eof == TRUE) 149 done = TRUE; 150 151 /* 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. 155 */ 156 if (readcnt < read_args.count) { 157 #ifdef NFS_OPS_DEBUG 158 if ((boothowto & DBFLAGS) == DBFLAGS) 159 printf("nfs3read(): partial read %d" 160 " instead of %d\n", 161 readcnt, read_args.count); 162 #endif 163 done = TRUE; /* update the counts and exit */ 164 } 165 166 /* update various offsets */ 167 count += readcnt; 168 filep->offset += readcnt; 169 buf_offset += readcnt; 170 read_args.offset += readcnt; 171 /* 172 * round and round she goes (though not on every block.. 173 * - OBP's take a fair bit of time to actually print stuff) 174 */ 175 if ((blks_read++ & 0x3) == 0) 176 printf("%c\b", ind[pos++ & 3]); 177 } while (count < size && !done); 178 179 return (count); 180 } 181 182 int 183 nfs3getattr(struct nfs_file *nfp, struct vattr *vap) 184 { 185 enum clnt_stat getattr_stat; 186 GETATTR3args getattr_args; 187 GETATTR3res getattr_res; 188 fattr3 *na; 189 struct timeval timeout = {0, 0}; /* default */ 190 vtype_t nf3_to_vt[] = 191 { VBAD, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO }; 192 193 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; 197 198 bzero(&getattr_res, sizeof (getattr_res)); 199 200 getattr_stat = CLNT_CALL(root_CLIENT, NFSPROC3_GETATTR, 201 xdr_GETATTR3args, (caddr_t)&getattr_args, 202 xdr_GETATTR3res, (caddr_t)&getattr_res, timeout); 203 204 if (getattr_stat != RPC_SUCCESS) { 205 dprintf("nfs_getattr: RPC error %d\n", getattr_stat); 206 return (-1); 207 } 208 if (getattr_res.status != NFS3_OK) { 209 nfs3_error(getattr_res.status); 210 return (getattr_res.status); 211 } 212 213 na = &getattr_res.GETATTR3res_u.resok.obj_attributes; 214 if (vap->va_mask & AT_TYPE) { 215 if (na->type < NF3REG || na->type > NF3FIFO) 216 vap->va_type = VBAD; 217 else 218 vap->va_type = nf3_to_vt[na->type]; 219 } 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; 229 } 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; 233 } 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; 237 } 238 239 return (NFS3_OK); 240 } 241 242 /* 243 * Display nfs error messages. 244 */ 245 /*ARGSUSED*/ 246 void 247 nfs3_error(enum nfsstat3 status) 248 { 249 if (!(boothowto & RB_DEBUG)) 250 return; 251 252 switch (status) { 253 case NFS3_OK: 254 printf("NFS: No error.\n"); 255 break; 256 case NFS3ERR_PERM: 257 printf("NFS: Not owner.\n"); 258 break; 259 case NFS3ERR_NOENT: 260 #ifdef NFS_OPS_DEBUG 261 printf("NFS: No such file or directory.\n"); 262 #endif /* NFS_OPS_DEBUG */ 263 break; 264 case NFS3ERR_IO: 265 printf("NFS: IO ERROR occurred on NFS server.\n"); 266 break; 267 case NFS3ERR_NXIO: 268 printf("NFS: No such device or address.\n"); 269 break; 270 case NFS3ERR_ACCES: 271 printf("NFS: Permission denied.\n"); 272 break; 273 case NFS3ERR_EXIST: 274 printf("NFS: File exists.\n"); 275 break; 276 case NFS3ERR_XDEV: 277 printf("NFS: Cross device hard link.\n"); 278 break; 279 case NFS3ERR_NODEV: 280 printf("NFS: No such device.\n"); 281 break; 282 case NFS3ERR_NOTDIR: 283 printf("NFS: Not a directory.\n"); 284 break; 285 case NFS3ERR_ISDIR: 286 printf("NFS: Is a directory.\n"); 287 break; 288 case NFS3ERR_INVAL: 289 printf("NFS: Invalid argument.\n"); 290 break; 291 case NFS3ERR_FBIG: 292 printf("NFS: File too large.\n"); 293 break; 294 case NFS3ERR_NOSPC: 295 printf("NFS: No space left on device.\n"); 296 break; 297 case NFS3ERR_ROFS: 298 printf("NFS: Read-only filesystem.\n"); 299 break; 300 case NFS3ERR_MLINK: 301 printf("NFS: Too many hard links.\n"); 302 break; 303 case NFS3ERR_NAMETOOLONG: 304 printf("NFS: File name too long.\n"); 305 break; 306 case NFS3ERR_NOTEMPTY: 307 printf("NFS: Directory not empty.\n"); 308 break; 309 case NFS3ERR_DQUOT: 310 printf("NFS: Disk quota exceeded.\n"); 311 break; 312 case NFS3ERR_STALE: 313 printf("NFS: Stale file handle.\n"); 314 break; 315 case NFS3ERR_REMOTE: 316 printf("NFS: Remote file in path.\n"); 317 break; 318 case NFS3ERR_BADHANDLE: 319 printf("NFS: Illegal NFS file handle.\n"); 320 break; 321 case NFS3ERR_NOT_SYNC: 322 printf("NFS: Synchronization mismatch.\n"); 323 break; 324 case NFS3ERR_BAD_COOKIE: 325 printf("NFS: Stale Cookie.\n"); 326 break; 327 case NFS3ERR_NOTSUPP: 328 printf("NFS: Operation is not supported.\n"); 329 break; 330 case NFS3ERR_TOOSMALL: 331 printf("NFS: Buffer too small.\n"); 332 break; 333 case NFS3ERR_SERVERFAULT: 334 printf("NFS: Server fault.\n"); 335 break; 336 case NFS3ERR_BADTYPE: 337 printf("NFS: Unsupported object type.\n"); 338 break; 339 case NFS3ERR_JUKEBOX: 340 printf("NFS: Resource temporarily unavailable.\n"); 341 break; 342 default: 343 printf("NFS: unknown error.\n"); 344 break; 345 } 346 } 347 348 struct nfs_file * 349 nfs3lookup(struct nfs_file *dir, char *name, int *nstat) 350 { 351 struct timeval zero_timeout = {0, 0}; /* default */ 352 static struct nfs_file cd; 353 LOOKUP3args dirop; 354 LOOKUP3res res_lookup; 355 enum clnt_stat status; 356 357 *nstat = (int)NFS3_OK; 358 359 bzero((caddr_t)&dirop, sizeof (LOOKUP3args)); 360 bzero((caddr_t)&res_lookup, sizeof (LOOKUP3res)); 361 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; 365 366 status = CLNT_CALL(root_CLIENT, NFSPROC3_LOOKUP, xdr_LOOKUP3args, 367 (caddr_t)&dirop, xdr_LOOKUP3res, (caddr_t)&res_lookup, 368 zero_timeout); 369 if (status != RPC_SUCCESS) { 370 dprintf("lookup: RPC error.\n"); 371 return (NULL); 372 } 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); 378 return (NULL); 379 } 380 381 bzero((caddr_t)&cd, sizeof (struct nfs_file)); 382 cd.version = NFS_V3; 383 /* 384 * Server must supply post_op_attr's 385 */ 386 if (res_lookup.LOOKUP3res_u.resok.obj_attributes.attributes_follow == 387 FALSE) { 388 printf("nfs3lookup: server fails to return post_op_attr\n"); 389 (void) CLNT_FREERES(root_CLIENT, 390 xdr_LOOKUP3res, (caddr_t)&res_lookup); 391 return (NULL); 392 } 393 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); 400 return (&cd); 401 } 402 403 /* 404 * Gets symbolic link into pathname. 405 */ 406 int 407 nfs3getsymlink(struct nfs_file *cfile, char **path) 408 { 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]; 414 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; 418 419 /* 420 * linkres needs a zeroed buffer to place path data into: 421 */ 422 bzero(&linkres, sizeof (linkres)); 423 bzero(symlink_path, NFS_MAXPATHLEN); 424 linkres.READLINK3res_u.resok.data = symlink_path; 425 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"); 431 return (-1); 432 } 433 if (linkres.status != NFS3_OK) { 434 nfs3_error(linkres.status); 435 return (linkres.status); 436 } 437 438 *path = symlink_path; 439 440 return (NFS3_OK); 441 } 442