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 ops - open, close, read, and lseek. 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 static struct timeval zero_timeout = {0, 0}; /* default */ 52 53 /* 54 * NFS Version 2 specific functions 55 */ 56 57 ssize_t 58 nfsread(struct nfs_file *filep, char *buf, size_t size) 59 { 60 readargs read_args; 61 readres read_res; 62 enum clnt_stat read_stat; 63 uint_t readcnt = 0; /* # bytes read by nfs */ 64 uint_t count = 0; /* # bytes transferred to buf */ 65 int done = FALSE; /* last block has come in */ 66 int framing_errs = 0; /* stack errors */ 67 char *buf_offset; /* current buffer offset */ 68 struct timeval timeout; 69 static uint_t pos; /* progress indicator counter */ 70 static char ind[] = "|/-\\"; /* progress indicator */ 71 static int blks_read; 72 73 read_args.file = filep->fh.fh2; /* structure copy */ 74 read_args.offset = filep->offset; 75 buf_offset = buf; 76 77 /* Optimize for reads of less than one block size */ 78 79 if (nfs_readsize == 0) 80 nfs_readsize = READ_SIZE; 81 82 if (size < nfs_readsize) 83 read_args.count = size; 84 else 85 read_args.count = nfs_readsize; 86 87 do { 88 /* use the user's buffer to stuff the data into. */ 89 read_res.readres_u.reply.data.data_val = buf_offset; 90 91 /* 92 * Handle the case where the file does not end 93 * on a block boundary. 94 */ 95 if ((count + read_args.count) > size) 96 read_args.count = size - count; 97 98 timeout.tv_sec = NFS_REXMIT_MIN; /* Total wait for call */ 99 timeout.tv_usec = 0; 100 do { 101 read_stat = CLNT_CALL(root_CLIENT, NFSPROC_READ, 102 xdr_readargs, (caddr_t)&read_args, 103 xdr_readres, (caddr_t)&read_res, timeout); 104 105 if (read_stat == RPC_TIMEDOUT) { 106 dprintf("NFS read(%d) timed out. Retrying...\n", 107 read_args.count); 108 /* 109 * If the remote is there and trying to respond, 110 * but our stack is having trouble reassembling 111 * the reply, reduce the read size in an 112 * attempt to compensate. Reset the 113 * transmission and reply wait timers. 114 */ 115 if (errno == ETIMEDOUT) 116 framing_errs++; 117 118 if (framing_errs > NFS_MAX_FERRS && 119 read_args.count > NFS_READ_DECR) { 120 read_args.count -= NFS_READ_DECR; 121 nfs_readsize -= NFS_READ_DECR; 122 dprintf("NFS Read size now %d.\n", 123 nfs_readsize); 124 timeout.tv_sec = NFS_REXMIT_MIN; 125 framing_errs = 0; 126 } else { 127 if (timeout.tv_sec < NFS_REXMIT_MAX) 128 timeout.tv_sec++; 129 else 130 timeout.tv_sec = 0; 131 /* default RPC */ 132 } 133 } 134 } while (read_stat == RPC_TIMEDOUT); 135 136 if (read_stat != RPC_SUCCESS) 137 return (-1); 138 139 readcnt = read_res.readres_u.reply.data.data_len; 140 /* 141 * Handle the case where the file is simply empty, and 142 * nothing could be read. 143 */ 144 if (readcnt == 0) 145 break; /* eof */ 146 147 /* 148 * Handle the case where the file is smaller than 149 * the size of the read request, thus the request 150 * couldn't be completely filled. 151 */ 152 if (readcnt < read_args.count) { 153 #ifdef NFS_OPS_DEBUG 154 if ((boothowto & DBFLAGS) == DBFLAGS) 155 printf("nfsread(): partial read %d" 156 " instead of %d\n", 157 readcnt, read_args.count); 158 #endif 159 done = TRUE; /* update the counts and exit */ 160 } 161 162 /* update various offsets */ 163 count += readcnt; 164 filep->offset += readcnt; 165 buf_offset += readcnt; 166 read_args.offset += readcnt; 167 /* 168 * round and round she goes (though not on every block.. 169 * - OBP's take a fair bit of time to actually print stuff) 170 */ 171 if ((blks_read++ & 0x3) == 0) 172 printf("%c\b", ind[pos++ & 3]); 173 } while (count < size && !done); 174 175 return (count); 176 } 177 178 static vtype_t nf_to_vt[] = { 179 VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK 180 }; 181 182 int 183 nfsgetattr(struct nfs_file *nfp, struct vattr *vap) 184 { 185 enum clnt_stat getattr_stat; 186 attrstat getattr_res; 187 fattr *na; 188 struct timeval timeout = {0, 0}; /* default */ 189 190 getattr_stat = CLNT_CALL(root_CLIENT, NFSPROC_GETATTR, 191 xdr_nfs_fh, (caddr_t)&(nfp->fh.fh2), 192 xdr_attrstat, (caddr_t)&getattr_res, timeout); 193 194 if (getattr_stat != RPC_SUCCESS) { 195 dprintf("nfs_getattr: RPC error %d\n", getattr_stat); 196 return (-1); 197 } 198 if (getattr_res.status != NFS_OK) { 199 nfs_error(getattr_res.status); 200 return (getattr_res.status); 201 } 202 203 /* adapted from nattr_to_vattr() in nfs_client.c */ 204 205 na = &getattr_res.attrstat_u.attributes; 206 if (vap->va_mask & AT_TYPE) { 207 if (na->type < NFNON || na->type > NFSOCK) 208 vap->va_type = VBAD; 209 else 210 vap->va_type = nf_to_vt[na->type]; 211 } 212 if (vap->va_mask & AT_MODE) 213 vap->va_mode = na->mode; 214 if (vap->va_mask & AT_SIZE) 215 vap->va_size = na->size; 216 if (vap->va_mask & AT_NODEID) 217 vap->va_nodeid = na->fileid; 218 if (vap->va_mask & AT_ATIME) { 219 vap->va_atime.tv_sec = na->atime.seconds; 220 vap->va_atime.tv_nsec = na->atime.useconds * 1000; 221 } 222 if (vap->va_mask & AT_CTIME) { 223 vap->va_ctime.tv_sec = na->ctime.seconds; 224 vap->va_ctime.tv_nsec = na->ctime.useconds * 1000; 225 } 226 if (vap->va_mask & AT_MTIME) { 227 vap->va_mtime.tv_sec = na->mtime.seconds; 228 vap->va_mtime.tv_nsec = na->mtime.useconds * 1000; 229 } 230 231 #ifdef NFS_OPS_DEBUG 232 if ((boothowto & DBFLAGS) == DBFLAGS) 233 printf("nfs_getattr(): done.\n"); 234 #endif 235 return (getattr_res.status); 236 } 237 238 /* 239 * Display nfs error messages. 240 */ 241 /*ARGSUSED*/ 242 void 243 nfs_error(enum nfsstat status) 244 { 245 if (!(boothowto & RB_DEBUG)) 246 return; 247 248 switch (status) { 249 case NFSERR_PERM: 250 printf("NFS: Not owner.\n"); 251 break; 252 case NFSERR_NOENT: 253 #ifdef NFS_OPS_DEBUG 254 printf("NFS: No such file or directory.\n"); 255 #endif /* NFS_OPS_DEBUG */ 256 break; 257 case NFSERR_IO: 258 printf("NFS: IO ERROR occurred on NFS server.\n"); 259 break; 260 case NFSERR_NXIO: 261 printf("NFS: No such device or address.\n"); 262 break; 263 case NFSERR_ACCES: 264 printf("NFS: Permission denied.\n"); 265 break; 266 case NFSERR_EXIST: 267 printf("NFS: File exists.\n"); 268 break; 269 case NFSERR_NODEV: 270 printf("NFS: No such device.\n"); 271 break; 272 case NFSERR_NOTDIR: 273 printf("NFS: Not a directory.\n"); 274 break; 275 case NFSERR_ISDIR: 276 printf("NFS: Is a directory.\n"); 277 break; 278 case NFSERR_FBIG: 279 printf("NFS: File too large.\n"); 280 break; 281 case NFSERR_NOSPC: 282 printf("NFS: No space left on device.\n"); 283 break; 284 case NFSERR_ROFS: 285 printf("NFS: Read-only filesystem.\n"); 286 break; 287 case NFSERR_NAMETOOLONG: 288 printf("NFS: File name too long.\n"); 289 break; 290 case NFSERR_NOTEMPTY: 291 printf("NFS: Directory not empty.\n"); 292 break; 293 case NFSERR_DQUOT: 294 printf("NFS: Disk quota exceeded.\n"); 295 break; 296 case NFSERR_STALE: 297 printf("NFS: Stale file handle.\n"); 298 break; 299 case NFSERR_WFLUSH: 300 printf("NFS: server's write cache has been flushed.\n"); 301 break; 302 default: 303 printf("NFS: unknown error.\n"); 304 break; 305 } 306 } 307 308 struct nfs_file * 309 nfslookup(struct nfs_file *dir, char *name, int *nstat) 310 { 311 static struct nfs_file cd; 312 diropargs dirop; 313 diropres res_lookup; 314 enum clnt_stat status; 315 316 *nstat = (int)NFS_OK; 317 318 bcopy(&dir->fh.fh2, &dirop.dir, NFS_FHSIZE); 319 dirop.name = name; 320 321 status = CLNT_CALL(root_CLIENT, NFSPROC_LOOKUP, xdr_diropargs, 322 (caddr_t)&dirop, xdr_diropres, (caddr_t)&res_lookup, 323 zero_timeout); 324 if (status != RPC_SUCCESS) { 325 dprintf("lookup: RPC error.\n"); 326 return (NULL); 327 } 328 if (res_lookup.status != NFS_OK) { 329 nfs_error(res_lookup.status); 330 *nstat = (int)res_lookup.status; 331 return (NULL); 332 } 333 334 bzero((caddr_t)&cd, sizeof (struct nfs_file)); 335 cd.version = NFS_VERSION; 336 cd.ftype.type2 = res_lookup.diropres_u.diropres.attributes.type; 337 bcopy(&res_lookup.diropres_u.diropres.file, &cd.fh.fh2, NFS_FHSIZE); 338 return (&cd); 339 } 340 341 /* 342 * Gets symbolic link into pathname. 343 */ 344 int 345 nfsgetsymlink(struct nfs_file *cfile, char **path) 346 { 347 enum clnt_stat status; 348 struct readlinkres linkres; 349 static char symlink_path[NFS_MAXPATHLEN]; 350 351 /* 352 * linkres needs a zeroed buffer to place path data into: 353 */ 354 bzero(symlink_path, NFS_MAXPATHLEN); 355 linkres.readlinkres_u.data = &symlink_path[0]; 356 357 status = CLNT_CALL(root_CLIENT, NFSPROC_READLINK, 358 xdr_nfs_fh, (caddr_t)&cfile->fh.fh2, 359 xdr_readlinkres, (caddr_t)&linkres, zero_timeout); 360 if (status != RPC_SUCCESS) { 361 dprintf("nfsgetsymlink: RPC call failed.\n"); 362 return (-1); 363 } 364 if (linkres.status != NFS_OK) { 365 nfs_error(linkres.status); 366 return (linkres.status); 367 } 368 369 *path = linkres.readlinkres_u.data; 370 371 return (NFS_OK); 372 } 373