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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 * 26 * Simple nfs V3 ops 27 */ 28 29 #pragma ident "%Z%%M% %I% %E% SMI" 30 31 #include <rpc/types.h> 32 #include <rpc/auth.h> 33 #include <sys/t_lock.h> 34 #include "clnt.h" 35 #include <sys/fcntl.h> 36 #include <sys/vfs.h> 37 #include <errno.h> 38 #include <sys/promif.h> 39 #include <rpc/xdr.h> 40 #include "nfs_inet.h" 41 #include <sys/stat.h> 42 #include <sys/bootvfs.h> 43 #include <sys/bootdebug.h> 44 #include <sys/salib.h> 45 #include <sys/sacache.h> 46 #include <rpc/rpc.h> 47 #include "brpc.h" 48 #include <rpcsvc/nfs_prot.h> 49 50 #define dprintf if (boothowto & RB_DEBUG) printf 51 52 /* 53 * NFS Version 3 specific functions 54 */ 55 56 ssize_t 57 nfs3read(struct nfs_file *filep, char *buf, size_t size) 58 { 59 READ3args read_args; 60 READ3res read_res; 61 enum clnt_stat read_stat; 62 uint_t readcnt = 0; /* # bytes read by nfs */ 63 uint_t count = 0; /* # bytes transferred to buf */ 64 int done = FALSE; /* last block has come in */ 65 int framing_errs = 0; /* stack errors */ 66 char *buf_offset; /* current buffer offset */ 67 struct timeval timeout; 68 #ifndef i386 69 static uint_t pos; /* progress indicator counter */ 70 static char ind[] = "|/-\\"; /* progress indicator */ 71 static int blks_read; 72 #endif 73 74 read_args.file.data.data_len = filep->fh.fh3.len; 75 read_args.file.data.data_val = filep->fh.fh3.data; 76 read_args.offset = filep->offset; 77 78 bzero(&read_res, sizeof (read_res)); 79 80 buf_offset = buf; 81 82 /* Optimize for reads of less than one block size */ 83 84 if (nfs_readsize == 0) 85 nfs_readsize = READ3_SIZE; 86 87 if (size < nfs_readsize) 88 read_args.count = size; 89 else 90 read_args.count = nfs_readsize; 91 92 do { 93 /* use the user's buffer to stuff the data into. */ 94 read_res.READ3res_u.resok.data.data_val = buf_offset; 95 96 /* 97 * Handle the case where the file does not end 98 * on a block boundary. 99 */ 100 if ((count + read_args.count) > size) 101 read_args.count = size - count; 102 103 timeout.tv_sec = NFS_REXMIT_MIN; /* Total wait for call */ 104 timeout.tv_usec = 0; 105 do { 106 read_stat = CLNT_CALL(root_CLIENT, NFSPROC3_READ, 107 xdr_READ3args, (caddr_t)&read_args, 108 xdr_READ3res, (caddr_t)&read_res, timeout); 109 110 if (read_stat == RPC_TIMEDOUT) { 111 dprintf("NFS read(%d) timed out. Retrying...\n", 112 read_args.count); 113 /* 114 * If the remote is there and trying to respond, 115 * but our stack is having trouble reassembling 116 * the reply, reduce the read size in an 117 * attempt to compensate. Reset the 118 * transmission and reply wait timers. 119 */ 120 if (errno == ETIMEDOUT) 121 framing_errs++; 122 123 if (framing_errs > NFS_MAX_FERRS && 124 read_args.count > NFS_READ_DECR) { 125 read_args.count /= 2; 126 nfs_readsize /= 2; 127 dprintf("NFS Read size now %d.\n", 128 nfs_readsize); 129 timeout.tv_sec = NFS_REXMIT_MIN; 130 framing_errs = 0; 131 } else { 132 if (timeout.tv_sec < NFS_REXMIT_MAX) 133 timeout.tv_sec++; 134 else 135 timeout.tv_sec = 0; 136 /* default RPC */ 137 } 138 } 139 } while (read_stat == RPC_TIMEDOUT); 140 141 if (read_stat != RPC_SUCCESS) 142 return (-1); 143 144 if (read_res.status != NFS3_OK) 145 return (-1); 146 147 readcnt = read_res.READ3res_u.resok.data.data_len; 148 /* 149 * If we are at EOF, update counts and exit 150 */ 151 if (read_res.READ3res_u.resok.eof == TRUE) 152 done = TRUE; 153 154 /* 155 * Handle the case where the file is smaller than 156 * the size of the read request, thus the request 157 * couldn't be completely filled. 158 */ 159 if (readcnt < read_args.count) { 160 #ifdef NFS_OPS_DEBUG 161 if ((boothowto & DBFLAGS) == DBFLAGS) 162 printf("nfs3read(): partial read %d" 163 " instead of %d\n", 164 readcnt, read_args.count); 165 #endif 166 done = TRUE; /* update the counts and exit */ 167 } 168 169 /* update various offsets */ 170 count += readcnt; 171 filep->offset += readcnt; 172 buf_offset += readcnt; 173 read_args.offset += readcnt; 174 #ifndef i386 175 /* 176 * round and round she goes (though not on every block.. 177 * - OBP's take a fair bit of time to actually print stuff) 178 */ 179 if ((blks_read++ & 0x3) == 0) 180 printf("%c\b", ind[pos++ & 3]); 181 #endif 182 } while (count < size && !done); 183 184 return (count); 185 } 186 187 int 188 nfs3getattr(struct nfs_file *nfp, struct vattr *vap) 189 { 190 enum clnt_stat getattr_stat; 191 GETATTR3args getattr_args; 192 GETATTR3res getattr_res; 193 fattr3 *na; 194 struct timeval timeout = {0, 0}; /* default */ 195 vtype_t nf3_to_vt[] = 196 { VBAD, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO }; 197 198 199 bzero(&getattr_args, sizeof (getattr_args)); 200 getattr_args.object.data.data_len = nfp->fh.fh3.len; 201 getattr_args.object.data.data_val = nfp->fh.fh3.data; 202 203 bzero(&getattr_res, sizeof (getattr_res)); 204 205 getattr_stat = CLNT_CALL(root_CLIENT, NFSPROC3_GETATTR, 206 xdr_GETATTR3args, (caddr_t)&getattr_args, 207 xdr_GETATTR3res, (caddr_t)&getattr_res, timeout); 208 209 if (getattr_stat != RPC_SUCCESS) { 210 dprintf("nfs_getattr: RPC error %d\n", getattr_stat); 211 return (-1); 212 } 213 if (getattr_res.status != NFS3_OK) { 214 nfs3_error(getattr_res.status); 215 return (getattr_res.status); 216 } 217 218 na = &getattr_res.GETATTR3res_u.resok.obj_attributes; 219 if (vap->va_mask & AT_TYPE) { 220 if (na->type < NF3REG || na->type > NF3FIFO) 221 vap->va_type = VBAD; 222 else 223 vap->va_type = nf3_to_vt[na->type]; 224 } 225 if (vap->va_mask & AT_MODE) 226 vap->va_mode = (mode_t)na->mode; 227 if (vap->va_mask & AT_SIZE) 228 vap->va_size = (u_offset_t)na->size; 229 if (vap->va_mask & AT_NODEID) 230 vap->va_nodeid = (u_longlong_t)na->fileid; 231 if (vap->va_mask & AT_ATIME) { 232 vap->va_atime.tv_sec = na->atime.seconds; 233 vap->va_atime.tv_nsec = na->atime.nseconds; 234 } 235 if (vap->va_mask & AT_CTIME) { 236 vap->va_ctime.tv_sec = na->ctime.seconds; 237 vap->va_ctime.tv_nsec = na->ctime.nseconds; 238 } 239 if (vap->va_mask & AT_MTIME) { 240 vap->va_mtime.tv_sec = na->mtime.seconds; 241 vap->va_mtime.tv_nsec = na->mtime.nseconds; 242 } 243 244 return (NFS3_OK); 245 } 246 247 /* 248 * Display nfs error messages. 249 */ 250 /*ARGSUSED*/ 251 void 252 nfs3_error(enum nfsstat3 status) 253 { 254 if (!(boothowto & RB_DEBUG)) 255 return; 256 257 switch (status) { 258 case NFS3_OK: 259 printf("NFS: No error.\n"); 260 break; 261 case NFS3ERR_PERM: 262 printf("NFS: Not owner.\n"); 263 break; 264 case NFS3ERR_NOENT: 265 #ifdef NFS_OPS_DEBUG 266 printf("NFS: No such file or directory.\n"); 267 #endif /* NFS_OPS_DEBUG */ 268 break; 269 case NFS3ERR_IO: 270 printf("NFS: IO ERROR occurred on NFS server.\n"); 271 break; 272 case NFS3ERR_NXIO: 273 printf("NFS: No such device or address.\n"); 274 break; 275 case NFS3ERR_ACCES: 276 printf("NFS: Permission denied.\n"); 277 break; 278 case NFS3ERR_EXIST: 279 printf("NFS: File exists.\n"); 280 break; 281 case NFS3ERR_XDEV: 282 printf("NFS: Cross device hard link.\n"); 283 break; 284 case NFS3ERR_NODEV: 285 printf("NFS: No such device.\n"); 286 break; 287 case NFS3ERR_NOTDIR: 288 printf("NFS: Not a directory.\n"); 289 break; 290 case NFS3ERR_ISDIR: 291 printf("NFS: Is a directory.\n"); 292 break; 293 case NFS3ERR_INVAL: 294 printf("NFS: Invalid argument.\n"); 295 break; 296 case NFS3ERR_FBIG: 297 printf("NFS: File too large.\n"); 298 break; 299 case NFS3ERR_NOSPC: 300 printf("NFS: No space left on device.\n"); 301 break; 302 case NFS3ERR_ROFS: 303 printf("NFS: Read-only filesystem.\n"); 304 break; 305 case NFS3ERR_MLINK: 306 printf("NFS: Too many hard links.\n"); 307 break; 308 case NFS3ERR_NAMETOOLONG: 309 printf("NFS: File name too long.\n"); 310 break; 311 case NFS3ERR_NOTEMPTY: 312 printf("NFS: Directory not empty.\n"); 313 break; 314 case NFS3ERR_DQUOT: 315 printf("NFS: Disk quota exceeded.\n"); 316 break; 317 case NFS3ERR_STALE: 318 printf("NFS: Stale file handle.\n"); 319 break; 320 case NFS3ERR_REMOTE: 321 printf("NFS: Remote file in path.\n"); 322 break; 323 case NFS3ERR_BADHANDLE: 324 printf("NFS: Illegal NFS file handle.\n"); 325 break; 326 case NFS3ERR_NOT_SYNC: 327 printf("NFS: Synchronization mismatch.\n"); 328 break; 329 case NFS3ERR_BAD_COOKIE: 330 printf("NFS: Stale Cookie.\n"); 331 break; 332 case NFS3ERR_NOTSUPP: 333 printf("NFS: Operation is not supported.\n"); 334 break; 335 case NFS3ERR_TOOSMALL: 336 printf("NFS: Buffer too small.\n"); 337 break; 338 case NFS3ERR_SERVERFAULT: 339 printf("NFS: Server fault.\n"); 340 break; 341 case NFS3ERR_BADTYPE: 342 printf("NFS: Unsupported object type.\n"); 343 break; 344 case NFS3ERR_JUKEBOX: 345 printf("NFS: Resource temporarily unavailable.\n"); 346 break; 347 default: 348 printf("NFS: unknown error.\n"); 349 break; 350 } 351 } 352 353 struct nfs_file * 354 nfs3lookup(struct nfs_file *dir, char *name, int *nstat) 355 { 356 struct timeval zero_timeout = {0, 0}; /* default */ 357 static struct nfs_file cd; 358 LOOKUP3args dirop; 359 LOOKUP3res res_lookup; 360 enum clnt_stat status; 361 362 *nstat = (int)NFS3_OK; 363 364 bzero((caddr_t)&dirop, sizeof (LOOKUP3args)); 365 bzero((caddr_t)&res_lookup, sizeof (LOOKUP3res)); 366 367 dirop.what.dir.data.data_len = dir->fh.fh3.len; 368 dirop.what.dir.data.data_val = dir->fh.fh3.data; 369 dirop.what.name = name; 370 371 status = CLNT_CALL(root_CLIENT, NFSPROC3_LOOKUP, xdr_LOOKUP3args, 372 (caddr_t)&dirop, xdr_LOOKUP3res, (caddr_t)&res_lookup, 373 zero_timeout); 374 if (status != RPC_SUCCESS) { 375 dprintf("lookup: RPC error.\n"); 376 return (NULL); 377 } 378 if (res_lookup.status != NFS3_OK) { 379 nfs3_error(res_lookup.status); 380 *nstat = (int)res_lookup.status; 381 (void) CLNT_FREERES(root_CLIENT, 382 xdr_LOOKUP3res, (caddr_t)&res_lookup); 383 return (NULL); 384 } 385 386 bzero((caddr_t)&cd, sizeof (struct nfs_file)); 387 cd.version = NFS_V3; 388 /* 389 * Server must supply post_op_attr's 390 */ 391 if (res_lookup.LOOKUP3res_u.resok.obj_attributes.attributes_follow == 392 FALSE) { 393 printf("nfs3lookup: server fails to return post_op_attr\n"); 394 (void) CLNT_FREERES(root_CLIENT, 395 xdr_LOOKUP3res, (caddr_t)&res_lookup); 396 return (NULL); 397 } 398 399 cd.ftype.type3 = 400 res_lookup.LOOKUP3res_u.resok.obj_attributes.post_op_attr_u.attributes.type; 401 cd.fh.fh3.len = res_lookup.LOOKUP3res_u.resok.object.data.data_len; 402 bcopy(res_lookup.LOOKUP3res_u.resok.object.data.data_val, 403 cd.fh.fh3.data, cd.fh.fh3.len); 404 (void) CLNT_FREERES(root_CLIENT, xdr_LOOKUP3res, (caddr_t)&res_lookup); 405 return (&cd); 406 } 407 408 /* 409 * Gets symbolic link into pathname. 410 */ 411 int 412 nfs3getsymlink(struct nfs_file *cfile, char **path) 413 { 414 struct timeval zero_timeout = {0, 0}; /* default */ 415 enum clnt_stat status; 416 struct READLINK3res linkres; 417 struct READLINK3args linkargs; 418 static char symlink_path[NFS_MAXPATHLEN]; 419 420 bzero(&linkargs, sizeof (linkargs)); 421 linkargs.symlink.data.data_len = cfile->fh.fh3.len; 422 linkargs.symlink.data.data_val = cfile->fh.fh3.data; 423 424 /* 425 * linkres needs a zeroed buffer to place path data into: 426 */ 427 bzero(&linkres, sizeof (linkres)); 428 bzero(symlink_path, NFS_MAXPATHLEN); 429 linkres.READLINK3res_u.resok.data = symlink_path; 430 431 status = CLNT_CALL(root_CLIENT, NFSPROC3_READLINK, 432 xdr_READLINK3args, (caddr_t)&linkargs, 433 xdr_READLINK3res, (caddr_t)&linkres, zero_timeout); 434 if (status != RPC_SUCCESS) { 435 dprintf("nfs3getsymlink: RPC call failed.\n"); 436 return (-1); 437 } 438 if (linkres.status != NFS3_OK) { 439 nfs3_error(linkres.status); 440 return (linkres.status); 441 } 442 443 *path = symlink_path; 444 445 return (NFS3_OK); 446 } 447