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