Home | History | Annotate | Download | only in smbsrv
      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 2009 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 #include <smbsrv/smb_kproto.h>
     27 #include <smbsrv/smb_fsops.h>
     28 
     29 
     30 /*
     31  * The maximum number of bytes to return from SMB Core
     32  * SmbRead or SmbLockAndRead.
     33  */
     34 #define	SMB_CORE_READ_MAX	4432
     35 
     36 /*
     37  * The limit in bytes for SmbReadX.
     38  */
     39 #define	SMB_READX_MAX		0x10000
     40 
     41 int smb_common_read(smb_request_t *, smb_rw_param_t *);
     42 
     43 /*
     44  * Read bytes from a file or named pipe (SMB Core).
     45  *
     46  * The requested count specifies the number of bytes desired.  Offset
     47  * is limited to 32 bits, so this client request is inappropriate for
     48  * files with 64 bit offsets.
     49  *
     50  * On return, count is the number of bytes actually being returned, which
     51  * may be less than the count requested only if a read specifies bytes
     52  * beyond the current file size.  In this case only the bytes that exist
     53  * are returned.  A read completely beyond the end of file results in a
     54  * response of length zero.  This is the only circumstance when a zero
     55  * length response is generated.  A count returned which is less than the
     56  * count requested is the end of file indicator.
     57  */
     58 smb_sdrc_t
     59 smb_pre_read(smb_request_t *sr)
     60 {
     61 	smb_rw_param_t *param;
     62 	uint32_t off_low;
     63 	uint16_t count;
     64 	uint16_t remcnt;
     65 	int rc;
     66 
     67 	param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
     68 	sr->arg.rw = param;
     69 
     70 	rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid,
     71 	    &count, &off_low, &remcnt);
     72 
     73 	param->rw_offset = (uint64_t)off_low;
     74 	param->rw_count = (uint32_t)count;
     75 	param->rw_mincnt = 0;
     76 
     77 	DTRACE_SMB_2(op__Read__start, smb_request_t *, sr,
     78 	    smb_rw_param_t *, param);
     79 
     80 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
     81 }
     82 
     83 void
     84 smb_post_read(smb_request_t *sr)
     85 {
     86 	DTRACE_SMB_2(op__Read__done, smb_request_t *, sr,
     87 	    smb_rw_param_t *, sr->arg.rw);
     88 
     89 	kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
     90 }
     91 
     92 smb_sdrc_t
     93 smb_com_read(smb_request_t *sr)
     94 {
     95 	smb_rw_param_t *param = sr->arg.rw;
     96 	uint16_t count;
     97 	int rc;
     98 
     99 	smbsr_lookup_file(sr);
    100 	if (sr->fid_ofile == NULL) {
    101 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
    102 		return (SDRC_ERROR);
    103 	}
    104 
    105 	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
    106 
    107 	if (param->rw_count > SMB_CORE_READ_MAX)
    108 		param->rw_count = SMB_CORE_READ_MAX;
    109 
    110 	if ((rc = smb_common_read(sr, param)) != 0) {
    111 		smbsr_errno(sr, rc);
    112 		return (SDRC_ERROR);
    113 	}
    114 
    115 	count = (uint16_t)param->rw_count;
    116 	rc = smbsr_encode_result(sr, 5, VAR_BCC, "bw8.wbwC",
    117 	    5, count, VAR_BCC, 0x01, count, &sr->raw_data);
    118 
    119 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
    120 }
    121 
    122 /*
    123  * Lock and read bytes from a file (SMB Core Plus).  The SmbLockAndRead/
    124  * SmbLockAndWrite sub-dialect is only valid on disk files: reject any
    125  * attempt to use it on non-disk shares.
    126  *
    127  * The requested count specifies the number of bytes desired.  Offset
    128  * specifies the offset in the file of the first byte to be locked then
    129  * read. Note that offset is limited to 32 bits, so this client request
    130  * is inappropriate for files with 64 bit offsets.
    131  *
    132  * As with SMB_LOCK_BYTE_RANGE request, if the lock cannot be granted
    133  * immediately an error should be returned to the client.  If an error
    134  * occurs on the lock, the bytes should not be read.
    135  *
    136  * On return, count is the number of bytes actually being returned, which
    137  * may be less than the count requested only if a read specifies bytes
    138  * beyond the current file size.  In this case only the bytes that exist
    139  * are returned.  A read completely beyond the end of file results in a
    140  * response of length zero.  This is the only circumstance when a zero
    141  * length response is generated.  A count returned which is less than the
    142  * count requested is the end of file indicator.
    143  */
    144 smb_sdrc_t
    145 smb_pre_lock_and_read(smb_request_t *sr)
    146 {
    147 	smb_rw_param_t *param;
    148 	uint32_t off_low;
    149 	uint16_t count;
    150 	uint16_t remcnt;
    151 	int rc;
    152 
    153 	param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
    154 	sr->arg.rw = param;
    155 
    156 	rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid,
    157 	    &count, &off_low, &remcnt);
    158 
    159 	param->rw_offset = (uint64_t)off_low;
    160 	param->rw_count = (uint32_t)count;
    161 	param->rw_mincnt = 0;
    162 
    163 	DTRACE_SMB_2(op__LockAndRead__start, smb_request_t *, sr,
    164 	    smb_rw_param_t *, param);
    165 
    166 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
    167 }
    168 
    169 void
    170 smb_post_lock_and_read(smb_request_t *sr)
    171 {
    172 	DTRACE_SMB_2(op__LockAndRead__done, smb_request_t *, sr,
    173 	    smb_rw_param_t *, sr->arg.rw);
    174 
    175 	kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
    176 }
    177 
    178 smb_sdrc_t
    179 smb_com_lock_and_read(smb_request_t *sr)
    180 {
    181 	smb_rw_param_t *param = sr->arg.rw;
    182 	DWORD status;
    183 	uint16_t count;
    184 	int rc;
    185 
    186 	if (STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) {
    187 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS, ERRnoaccess);
    188 		return (SDRC_ERROR);
    189 	}
    190 
    191 	smbsr_lookup_file(sr);
    192 	if (sr->fid_ofile == NULL) {
    193 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
    194 		return (SDRC_ERROR);
    195 	}
    196 
    197 	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
    198 
    199 	status = smb_lock_range(sr, param->rw_offset, (uint64_t)param->rw_count,
    200 	    0, SMB_LOCK_TYPE_READWRITE);
    201 
    202 	if (status != NT_STATUS_SUCCESS) {
    203 		smb_lock_range_error(sr, status);
    204 		return (SDRC_ERROR);
    205 	}
    206 
    207 	if (param->rw_count > SMB_CORE_READ_MAX)
    208 		param->rw_count = SMB_CORE_READ_MAX;
    209 
    210 	if ((rc = smb_common_read(sr, param)) != 0) {
    211 		smbsr_errno(sr, rc);
    212 		return (SDRC_ERROR);
    213 	}
    214 
    215 	count = (uint16_t)param->rw_count;
    216 	rc = smbsr_encode_result(sr, 5, VAR_BCC, "bw8.wbwC",
    217 	    5, count, VAR_BCC, 0x1, count, &sr->raw_data);
    218 
    219 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
    220 }
    221 
    222 /*
    223  * The SMB_COM_READ_RAW protocol is a negotiated option introduced in
    224  * SMB Core Plus to maximize performance when reading a large block
    225  * of data from a server.  This request was extended in LM 0.12 to
    226  * support 64-bit offsets; the server can indicate support by setting
    227  * CAP_LARGE_FILES in the negotiated capabilities.
    228  *
    229  * The client must guarantee that there is (and will be) no other request
    230  * to the server for the duration of the SMB_COM_READ_RAW, since the
    231  * server response has no header or trailer. To help ensure that there
    232  * are no interruptions, we block all I/O for the session during read raw.
    233  *
    234  * If this is the first SMB request received since we sent an oplock break
    235  * to this client, we don't know if it's safe to send the raw data because
    236  * the requests may have crossed on the wire and the client may have
    237  * interpreted the oplock break as part of the raw data. To avoid problems,
    238  * we send a zero length session packet, which will force the client to
    239  * retry the read.
    240  *
    241  * Do not return errors from SmbReadRaw.
    242  * Read errors are handled by sending a zero length response.
    243  */
    244 smb_sdrc_t
    245 smb_pre_read_raw(smb_request_t *sr)
    246 {
    247 	smb_rw_param_t *param;
    248 	uint32_t off_low;
    249 	uint32_t off_high;
    250 	uint32_t timeout;
    251 	uint16_t count;
    252 	int rc;
    253 
    254 	param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
    255 	sr->arg.rw = param;
    256 
    257 	if (sr->smb_wct == 8) {
    258 		rc = smbsr_decode_vwv(sr, "wlwwl2.", &sr->smb_fid,
    259 		    &off_low, &count, &param->rw_mincnt, &timeout);
    260 		if (rc == 0) {
    261 			param->rw_offset = (uint64_t)off_low;
    262 			param->rw_count = (uint32_t)count;
    263 		}
    264 	} else {
    265 		rc = smbsr_decode_vwv(sr, "wlwwl2.l", &sr->smb_fid,
    266 		    &off_low, &count, &param->rw_mincnt, &timeout, &off_high);
    267 		if (rc == 0) {
    268 			param->rw_offset = ((uint64_t)off_high << 32) | off_low;
    269 			param->rw_count = (uint32_t)count;
    270 		}
    271 	}
    272 
    273 	DTRACE_SMB_2(op__ReadRaw__start, smb_request_t *, sr,
    274 	    smb_rw_param_t *, param);
    275 
    276 	smb_rwx_rwenter(&sr->session->s_lock, RW_WRITER);
    277 	return (SDRC_SUCCESS);
    278 }
    279 
    280 void
    281 smb_post_read_raw(smb_request_t *sr)
    282 {
    283 	mbuf_chain_t	*mbc;
    284 
    285 	if (sr->session->s_state == SMB_SESSION_STATE_READ_RAW_ACTIVE) {
    286 		sr->session->s_state = SMB_SESSION_STATE_NEGOTIATED;
    287 
    288 		while ((mbc = list_head(&sr->session->s_oplock_brkreqs)) !=
    289 		    NULL) {
    290 			SMB_MBC_VALID(mbc);
    291 			list_remove(&sr->session->s_oplock_brkreqs, mbc);
    292 			(void) smb_session_send(sr->session, 0, mbc);
    293 			smb_mbc_free(mbc);
    294 		}
    295 	}
    296 
    297 	DTRACE_SMB_2(op__ReadRaw__done, smb_request_t *, sr,
    298 	    smb_rw_param_t *, sr->arg.rw);
    299 
    300 	smb_rwx_rwexit(&sr->session->s_lock);
    301 	kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
    302 }
    303 
    304 smb_sdrc_t
    305 smb_com_read_raw(smb_request_t *sr)
    306 {
    307 	smb_rw_param_t *param = sr->arg.rw;
    308 
    309 	switch (sr->session->s_state) {
    310 	case SMB_SESSION_STATE_NEGOTIATED:
    311 		sr->session->s_state = SMB_SESSION_STATE_READ_RAW_ACTIVE;
    312 		break;
    313 
    314 	case SMB_SESSION_STATE_OPLOCK_BREAKING:
    315 		(void) smb_session_send(sr->session, 0, NULL);
    316 		return (SDRC_NO_REPLY);
    317 
    318 	case SMB_SESSION_STATE_TERMINATED:
    319 	case SMB_SESSION_STATE_DISCONNECTED:
    320 		return (SDRC_NO_REPLY);
    321 
    322 	case SMB_SESSION_STATE_READ_RAW_ACTIVE:
    323 		sr->session->s_state = SMB_SESSION_STATE_NEGOTIATED;
    324 		return (SDRC_DROP_VC);
    325 
    326 	case SMB_SESSION_STATE_WRITE_RAW_ACTIVE:
    327 	case SMB_SESSION_STATE_CONNECTED:
    328 	case SMB_SESSION_STATE_ESTABLISHED:
    329 	default:
    330 		return (SDRC_DROP_VC);
    331 	}
    332 
    333 	smbsr_lookup_file(sr);
    334 	if (sr->fid_ofile == NULL) {
    335 		(void) smb_session_send(sr->session, 0, NULL);
    336 		return (SDRC_NO_REPLY);
    337 	}
    338 
    339 	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
    340 
    341 	if (param->rw_mincnt > param->rw_count)
    342 		param->rw_mincnt = 0;
    343 
    344 	if (smb_common_read(sr, param) != 0) {
    345 		(void) smb_session_send(sr->session, 0, NULL);
    346 		m_freem(sr->raw_data.chain);
    347 		sr->raw_data.chain = NULL;
    348 	} else {
    349 		(void) smb_session_send(sr->session, 0, &sr->raw_data);
    350 	}
    351 
    352 	return (SDRC_NO_REPLY);
    353 }
    354 
    355 /*
    356  * Read bytes from a file (SMB Core).  This request was extended in
    357  * LM 0.12 to support 64-bit offsets, indicated by sending a wct of
    358  * 12 and including additional offset information.
    359  *
    360  * MS-SMB 3.3.5.7 update to LM 0.12 4.2.4:
    361  * If wct is 12 and CAP_LARGE_READX is set, the count may be larger
    362  * than the negotiated buffer size.  If maxcnt_high is 0xFF, it must
    363  * be ignored.  Otherwise, maxcnt_high represents the upper 16 bits
    364  * of rw_count.
    365  */
    366 smb_sdrc_t
    367 smb_pre_read_andx(smb_request_t *sr)
    368 {
    369 	smb_rw_param_t *param;
    370 	uint32_t off_low;
    371 	uint32_t off_high;
    372 	uint32_t maxcnt_high;
    373 	uint16_t maxcnt_low;
    374 	uint16_t mincnt;
    375 	uint16_t remcnt;
    376 	int rc;
    377 
    378 	param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
    379 	sr->arg.rw = param;
    380 
    381 	if (sr->smb_wct == 12) {
    382 		rc = smbsr_decode_vwv(sr, "b3.wlwwlwl", &param->rw_andx,
    383 		    &sr->smb_fid, &off_low, &maxcnt_low, &mincnt, &maxcnt_high,
    384 		    &remcnt, &off_high);
    385 
    386 		param->rw_offset = ((uint64_t)off_high << 32) |
    387 		    (uint64_t)off_low;
    388 
    389 		param->rw_count = (uint32_t)maxcnt_low;
    390 
    391 		if ((sr->session->capabilities & CAP_LARGE_READX) &&
    392 		    (maxcnt_high < 0xFF))
    393 			param->rw_count |= maxcnt_high << 16;
    394 	} else {
    395 		rc = smbsr_decode_vwv(sr, "b3.wlwwlw", &param->rw_andx,
    396 		    &sr->smb_fid, &off_low, &maxcnt_low, &mincnt, &maxcnt_high,
    397 		    &remcnt);
    398 
    399 		param->rw_offset = (uint64_t)off_low;
    400 		param->rw_count = (uint32_t)maxcnt_low;
    401 	}
    402 
    403 	param->rw_mincnt = 0;
    404 
    405 	DTRACE_SMB_2(op__ReadX__start, smb_request_t *, sr,
    406 	    smb_rw_param_t *, param);
    407 
    408 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
    409 }
    410 
    411 void
    412 smb_post_read_andx(smb_request_t *sr)
    413 {
    414 	DTRACE_SMB_2(op__ReadX__done, smb_request_t *, sr,
    415 	    smb_rw_param_t *, sr->arg.rw);
    416 
    417 	kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
    418 }
    419 
    420 smb_sdrc_t
    421 smb_com_read_andx(smb_request_t *sr)
    422 {
    423 	smb_rw_param_t *param = sr->arg.rw;
    424 	uint16_t datalen_high;
    425 	uint16_t datalen_low;
    426 	uint16_t data_offset;
    427 	uint16_t offset2;
    428 	int rc;
    429 
    430 	smbsr_lookup_file(sr);
    431 	if (sr->fid_ofile == NULL) {
    432 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
    433 		return (SDRC_ERROR);
    434 	}
    435 
    436 	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
    437 
    438 	if (param->rw_count >= SMB_READX_MAX)
    439 		param->rw_count = 0;
    440 
    441 	if ((rc = smb_common_read(sr, param)) != 0) {
    442 		smbsr_errno(sr, rc);
    443 		return (SDRC_ERROR);
    444 	}
    445 
    446 	datalen_low = param->rw_count & 0xFFFF;
    447 	datalen_high = (param->rw_count >> 16) & 0xFF;
    448 
    449 	/*
    450 	 * If this is a secondary command, the data offset
    451 	 * includes the previous wct + sizeof(wct).
    452 	 */
    453 	data_offset = (sr->andx_prev_wct == 0) ? 0 : sr->andx_prev_wct + 1;
    454 
    455 	if (STYPE_ISIPC(sr->tid_tree->t_res_type)) {
    456 		data_offset += 60;
    457 		offset2 = (param->rw_andx == 0xFF) ? 0 : param->rw_count + 60;
    458 
    459 		rc = smbsr_encode_result(sr, 12, VAR_BCC, "bb1.ww4.www8.wbC",
    460 		    12,			/* wct */
    461 		    param->rw_andx,	/* secondary andx command */
    462 		    offset2,		/* offset to next command */
    463 		    0,			/* set to 0 for named pipes */
    464 		    datalen_low,	/* data byte count */
    465 		    data_offset,	/* offset from start to data */
    466 		    datalen_high,	/* data byte count */
    467 		    VAR_BCC,		/* BCC marker */
    468 		    0x00,		/* padding */
    469 		    &sr->raw_data);
    470 	} else {
    471 		data_offset += 59;
    472 		offset2 = (param->rw_andx == 0xFF) ? 0 : param->rw_count + 59;
    473 
    474 		rc = smbsr_encode_result(sr, 12, VAR_BCC, "bb1.ww4.www8.wC",
    475 		    12,			/* wct */
    476 		    param->rw_andx,	/* secondary andx command */
    477 		    offset2,		/* offset to next command */
    478 		    -1,			/* must be -1 for regular files */
    479 		    datalen_low,	/* data byte count */
    480 		    data_offset,	/* offset from start to data */
    481 		    datalen_high,	/* data byte count */
    482 		    VAR_BCC,		/* BCC marker */
    483 		    &sr->raw_data);
    484 	}
    485 
    486 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
    487 }
    488 
    489 /*
    490  * Common function for reading files or IPC/MSRPC named pipes.  All
    491  * protocol read functions should lookup the fid before calling this
    492  * function.  We can't move the fid lookup here because lock-and-read
    493  * requires the fid to do locking before attempting the read.
    494  *
    495  * Returns errno values.
    496  */
    497 int
    498 smb_common_read(smb_request_t *sr, smb_rw_param_t *param)
    499 {
    500 	smb_ofile_t *ofile = sr->fid_ofile;
    501 	smb_node_t *node;
    502 	smb_vdb_t *vdb = &param->rw_vdb;
    503 	struct mbuf *top;
    504 	int rc;
    505 
    506 	vdb->vdb_tag = 0;
    507 	vdb->vdb_uio.uio_iov = &vdb->vdb_iovec[0];
    508 	vdb->vdb_uio.uio_iovcnt = MAX_IOVEC;
    509 	vdb->vdb_uio.uio_resid = param->rw_count;
    510 	vdb->vdb_uio.uio_loffset = (offset_t)param->rw_offset;
    511 	vdb->vdb_uio.uio_segflg = UIO_SYSSPACE;
    512 
    513 	switch (sr->tid_tree->t_res_type & STYPE_MASK) {
    514 	case STYPE_DISKTREE:
    515 		node = ofile->f_node;
    516 
    517 		if (!smb_node_is_dir(node)) {
    518 			rc = smb_lock_range_access(sr, node, param->rw_offset,
    519 			    param->rw_count, B_FALSE);
    520 			if (rc != NT_STATUS_SUCCESS) {
    521 				rc = ERANGE;
    522 				break;
    523 			}
    524 		}
    525 
    526 		if ((ofile->f_flags & SMB_OFLAGS_EXECONLY) &&
    527 		    !(sr->smb_flg2 & SMB_FLAGS2_PAGING_IO)) {
    528 			/*
    529 			 * SMB_FLAGS2_PAGING_IO: permit execute-only reads.
    530 			 *
    531 			 * Reject request if the file has been opened
    532 			 * execute-only and SMB_FLAGS2_PAGING_IO is not set.
    533 			 */
    534 			rc = EACCES;
    535 			break;
    536 		}
    537 
    538 		sr->raw_data.max_bytes = vdb->vdb_uio.uio_resid;
    539 		top = smb_mbuf_allocate(&vdb->vdb_uio);
    540 
    541 		rc = smb_fsop_read(sr, sr->user_cr, node, &vdb->vdb_uio);
    542 
    543 		sr->raw_data.max_bytes -= vdb->vdb_uio.uio_resid;
    544 		smb_mbuf_trim(top, sr->raw_data.max_bytes);
    545 		MBC_ATTACH_MBUF(&sr->raw_data, top);
    546 		break;
    547 
    548 	case STYPE_IPC:
    549 		rc = smb_opipe_read(sr, &vdb->vdb_uio);
    550 		break;
    551 
    552 	default:
    553 		rc = EACCES;
    554 		break;
    555 	}
    556 
    557 	param->rw_count -= vdb->vdb_uio.uio_resid;
    558 
    559 	if (rc != 0)
    560 		return (rc);
    561 
    562 	if (param->rw_mincnt != 0 && param->rw_count < param->rw_mincnt) {
    563 		/*
    564 		 * mincnt is only used by read-raw and is typically
    565 		 * zero.  If mincnt is greater than zero and the
    566 		 * number of bytes read is less than mincnt, tell
    567 		 * the client that we read nothing.
    568 		 */
    569 		param->rw_count = 0;
    570 	}
    571 
    572 	param->rw_offset += param->rw_count;
    573 	mutex_enter(&sr->fid_ofile->f_mutex);
    574 	ofile->f_seek_pos = param->rw_offset;
    575 	mutex_exit(&sr->fid_ofile->f_mutex);
    576 	return (rc);
    577 }
    578