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.
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.
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]
22 * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
26 #include <sys/cmn_err.h>
27 #include <sys/debug.h>
28 #include <sys/systm.h>
31 #include <sys/atomic.h>
32 #include <rpc/types.h>
34 #include <nfs/nfssys.h>
35 #include <nfs/export.h>
36 #include <nfs/rnode.h>
41 #include <nfs/nfs_log.h>
43 #define NUM_RECORDS_TO_WRITE 256
44 #define NUM_BYTES_TO_WRITE 65536
46 extern krwlock_t exported_lock
;
48 static int nfslog_num_records_to_write
= NUM_RECORDS_TO_WRITE
;
49 static int nfslog_num_bytes_to_write
= NUM_BYTES_TO_WRITE
;
52 * This struct is used to 'hide' the details of managing the log
53 * records internally to the logging code. Allocation routines
54 * are used to obtain pieces of memory for XDR encoding. This struct
55 * is a 'header' to those areas and a opaque cookie is used to pass
56 * this data structure between the allocating function and the put
60 struct lr_alloc
*next
; /* links for write queuing */
61 struct lr_alloc
*prev
;
62 #define LR_ALLOC_NOFREE 0x1 /* not present, call free */
64 caddr_t log_record
; /* address to XDR encoding */
65 size_t size
; /* final size of encoding */
66 struct kmem_cache
*alloc_cache
; /* keep track of cache ptr */
67 struct exportinfo
*exi
; /* who are we related to? */
68 struct log_buffer
*lb
;
71 struct flush_thread_params
{
72 struct nfsl_flush_args tp_args
;
76 static int log_file_create(caddr_t
, struct log_file
**);
77 static void log_file_rele(struct log_file
*);
78 static struct log_buffer
*log_buffer_create(caddr_t
);
79 static void log_buffer_rele(struct log_buffer
*);
80 static int nfslog_record_append2all(struct lr_alloc
*);
81 static int nfslog_logbuffer_rename(struct log_buffer
*);
82 static void nfslog_logfile_wait(struct log_file
*);
83 static int nfslog_logfile_rename(char *, char *);
84 static void nfslog_do_flush(struct flush_thread_params
*);
85 static void create_buffer_header(caddr_t
*, size_t *, size_t *);
87 static int nfslog_write_logrecords(struct log_file
*, struct lr_alloc
*, int);
88 static void nfslog_free_logrecords(struct lr_alloc
*);
89 static int nfslog_records_flush_to_disk(struct log_buffer
*);
90 static int nfslog_records_flush_to_disk_nolock(struct log_buffer
*);
93 * Read/Write lock that protects 'nfslog_buffer_list'.
94 * This lock must be held when searching or modifying 'nfslog_buffer_list'.
96 static krwlock_t nfslog_buffer_list_lock
;
99 * The list of "log_buffer" structures.
101 struct log_buffer
*nfslog_buffer_list
= NULL
;
104 #define LOG_BUFFER_HOLD(lbp) { \
105 mutex_enter(&(lbp)->lb_lock); \
106 (lbp)->lb_refcnt++; \
107 mutex_exit(&(lbp)->lb_lock); \
110 #define LOG_FILE_HOLD(lfp) { \
111 mutex_enter(&(lfp)->lf_lock); \
112 (lfp)->lf_refcnt++; \
113 mutex_exit(&(lfp)->lf_lock); \
116 #define LOG_FILE_RELE(lfp) { \
117 log_file_rele(lfp); \
121 * These two macros are used to prep a logfile data structure and
122 * associated file for writing data. Note that the lf_lock is
123 * held as a result of the call to the first macro. This is used
124 * for serialization correctness between the logbuffer struct and
125 * the logfile struct.
127 #define LOG_FILE_LOCK_TO_WRITE(lfp) { \
128 mutex_enter(&(lfp)->lf_lock); \
129 (lfp)->lf_refcnt++; \
130 (lfp)->lf_writers++; \
133 #define LOG_FILE_UNLOCK_FROM_WRITE(lfp) { \
134 (lfp)->lf_writers--; \
135 if ((lfp)->lf_writers == 0 && ((lfp)->lf_flags & L_WAITING)) { \
136 (lfp)->lf_flags &= ~L_WAITING; \
137 cv_broadcast(&(lfp)->lf_cv_waiters); \
139 mutex_exit(&(lfp)->lf_lock); \
140 log_file_rele(lfp); \
143 int rfsl_log_buffer
= 0;
144 static int rfsl_log_file
= 0;
146 /* This array is used for memory allocation of record encoding spaces */
149 struct kmem_cache
*mem_cache
;
151 } nfslog_mem_alloc
[] = {
153 { NFSLOG_SMALL_RECORD_SIZE
- sizeof (struct lr_alloc
),
154 NULL
, NFSLOG_SMALL_REC_NAME
},
155 #define MEDIUM_INDX 1
156 { NFSLOG_MEDIUM_RECORD_SIZE
- sizeof (struct lr_alloc
),
157 NULL
, NFSLOG_MEDIUM_REC_NAME
},
159 { NFSLOG_LARGE_RECORD_SIZE
- sizeof (struct lr_alloc
),
160 NULL
, NFSLOG_LARGE_REC_NAME
},
164 /* Used to calculate the 'real' allocation size */
165 #define ALLOC_SIZE(index) \
166 (nfslog_mem_alloc[index].size + sizeof (struct lr_alloc))
169 * Initialize logging data buffer cache
176 rw_init(&nfslog_buffer_list_lock
, NULL
, RW_DEFAULT
, NULL
);
179 * Initialize the kmem caches for encoding
181 for (indx
= 0; nfslog_mem_alloc
[indx
].size
!= (-1); indx
++) {
182 nfslog_mem_alloc
[indx
].mem_cache
=
183 kmem_cache_create(nfslog_mem_alloc
[indx
].cache_name
,
184 ALLOC_SIZE(indx
), 0, NULL
, NULL
, NULL
, NULL
, NULL
, 0);
189 * Sets up the necessary log file and related buffers to enable logging
190 * on the given export point.
191 * Returns 0 on success, non-zero on failure.
194 nfslog_setup(struct exportinfo
*exi
)
196 struct exportdata
*kex
;
197 struct log_buffer
*lbp
;
198 struct log_buffer
*nlbp
;
200 kex
= &exi
->exi_export
;
201 ASSERT(kex
->ex_flags
& EX_LOG
);
204 * Logging is enabled for the new export point, check
205 * the existing log_buffer structures to see if the
206 * desired buffer has already been opened. If so, point
207 * the new exportinfo's exi_logbuffer to the existing
210 rw_enter(&nfslog_buffer_list_lock
, RW_READER
);
211 for (lbp
= nfslog_buffer_list
; lbp
!= NULL
; lbp
= lbp
->lb_next
) {
213 "searching for buffer... found log_buffer '%s'\n",
215 if (strcmp(lbp
->lb_path
, kex
->ex_log_buffer
) == 0) {
216 /* Found our match. Ref it and return */
217 LOG_BUFFER_HOLD(lbp
);
218 exi
->exi_logbuffer
= lbp
;
219 LOGGING_DPRINT((10, "\tfound log_buffer for '%s'\n",
220 kex
->ex_log_buffer
));
221 rw_exit(&nfslog_buffer_list_lock
);
225 rw_exit(&nfslog_buffer_list_lock
);
228 * New buffer needed, allocate it.
229 * The buffer list lock has been dropped so we will need to search
230 * the list again to ensure that another thread has not added
233 if ((nlbp
= log_buffer_create(kex
->ex_log_buffer
)) == NULL
) {
235 * Failed the buffer creation for some reason so we
236 * will need to return.
241 rw_enter(&nfslog_buffer_list_lock
, RW_WRITER
);
242 for (lbp
= nfslog_buffer_list
; lbp
!= NULL
;
243 lbp
= lbp
->lb_next
) {
244 if (strcmp(lbp
->lb_path
, kex
->ex_log_buffer
) == 0) {
246 * A log_buffer already exists for the
247 * indicated buffer, use it instead.
249 LOG_BUFFER_HOLD(lbp
);
251 exi
->exi_logbuffer
= lbp
;
253 LOGGING_DPRINT((10, "found log_buffer for '%s' "
254 "after allocation\n", kex
->ex_log_buffer
));
256 rw_exit(&nfslog_buffer_list_lock
);
258 log_buffer_rele(nlbp
);
264 * Didn't find an existing log_buffer for this buffer,
265 * use the the newly created one, and add to list. We
266 * increment the reference count because the node is
267 * entered into the global list.
269 LOGGING_DPRINT((10, "exportfs: adding nlbp=%p to list\n",
272 nlbp
->lb_next
= nfslog_buffer_list
;
273 nfslog_buffer_list
= nlbp
;
275 LOG_BUFFER_HOLD(nlbp
); /* hold is for export entry */
276 exi
->exi_logbuffer
= nlbp
;
278 rw_exit(&nfslog_buffer_list_lock
);
284 * Disables logging for the given export point.
287 nfslog_disable(struct exportinfo
*exi
)
289 log_buffer_rele(exi
->exi_logbuffer
);
293 * Creates the corresponding log_buffer and log_file structures
294 * for the the buffer named 'name'.
295 * Returns a pointer to the log_buffer structure with reference one.
297 static struct log_buffer
*
298 log_buffer_create(caddr_t name
)
300 struct log_buffer
*buffer
;
301 struct log_file
*logfile
;
302 int namelen
= strlen(name
);
304 LOGGING_DPRINT((10, "log_buffer_create: %s\n", name
));
305 if (log_file_create(name
, &logfile
))
308 buffer
= kmem_alloc(sizeof (*buffer
), KM_SLEEP
);
309 buffer
->lb_refcnt
= 1;
310 buffer
->lb_rec_id
= 0;
311 buffer
->lb_path
= kmem_alloc(namelen
+ 1, KM_SLEEP
);
312 bcopy(name
, buffer
->lb_path
, namelen
+ 1);
313 buffer
->lb_logfile
= logfile
;
314 buffer
->lb_records
= NULL
;
315 buffer
->lb_num_recs
= 0;
316 buffer
->lb_size_queued
= 0;
317 mutex_init(&buffer
->lb_lock
, NULL
, MUTEX_DEFAULT
, NULL
);
324 * Release a log_buffer structure
327 log_buffer_rele(struct log_buffer
*lbp
)
331 mutex_enter(&lbp
->lb_lock
);
332 if (--lbp
->lb_refcnt
> 1) {
333 mutex_exit(&lbp
->lb_lock
);
337 if (lbp
->lb_refcnt
< 0) {
338 panic("log_rele: log_buffer refcnt < 0");
343 * Need to drop the lb_lock before acquiring the
344 * nfslog_buffer_list_lock. To avoid double free we need
345 * to hold an additional reference to the log buffer.
346 * This will ensure that no two threads will simultaneously
347 * be trying to free the same log buffer.
350 if (lbp
->lb_refcnt
== 1) {
353 * If the ref count is 1, then the last
354 * unshare/reference has been given up and we need to
355 * clean up the buffer and remove it from the buffer
359 "log_buffer_rele lbp=%p disconnecting\n", (void *)lbp
));
361 * Hold additional reference before dropping the lb_lock
365 mutex_exit(&lbp
->lb_lock
);
368 * Make sure that all of the buffered records are written.
369 * Don't bother checking the write return value since there
370 * isn't much we can do at this point.
372 (void) nfslog_records_flush_to_disk(lbp
);
374 rw_enter(&nfslog_buffer_list_lock
, RW_WRITER
);
375 mutex_enter(&lbp
->lb_lock
);
377 * Drop the reference count held above.
378 * If the ref count is still > 1 then someone has
379 * stepped in to use this log buffer. unlock and return.
381 if (--lbp
->lb_refcnt
> 1) {
382 mutex_exit(&lbp
->lb_lock
);
383 rw_exit(&nfslog_buffer_list_lock
);
387 if (lbp
== nfslog_buffer_list
) {
388 nfslog_buffer_list
= lbp
->lb_next
;
390 struct log_buffer
*tlbp
;
392 /* Drop the log_buffer from the master list */
393 for (tlbp
= nfslog_buffer_list
; tlbp
->lb_next
!= NULL
;
394 tlbp
= tlbp
->lb_next
) {
395 if (tlbp
->lb_next
== lbp
) {
396 tlbp
->lb_next
= lbp
->lb_next
;
402 mutex_exit(&lbp
->lb_lock
);
403 rw_exit(&nfslog_buffer_list_lock
);
406 * ref count zero; finish clean up.
408 LOGGING_DPRINT((10, "log_buffer_rele lbp=%p freeing\n", (void *)lbp
));
410 log_file_rele(lbp
->lb_logfile
);
411 len
= strlen(lbp
->lb_path
) + 1;
412 kmem_free(lbp
->lb_path
, len
);
413 kmem_free(lbp
, sizeof (*lbp
));
418 * Creates the corresponding log_file structure for the buffer
419 * named 'log_file_name'.
420 * 'log_file_name' is created by concatenating 'origname' and LOG_INPROG_STRING.
421 * 'logfile' is set to be the log_file structure with reference one.
424 log_file_create(caddr_t origname
, struct log_file
**lfpp
)
430 struct log_file
*logfile
= NULL
;
432 caddr_t loghdr
= NULL
;
433 size_t loghdr_len
= 0;
434 size_t loghdr_free
= 0;
436 namelen
= strlen(origname
) + strlen(LOG_INPROG_STRING
);
437 name
= kmem_alloc(namelen
+ 1, KM_SLEEP
);
438 (void) sprintf(name
, "%s%s", origname
, LOG_INPROG_STRING
);
440 LOGGING_DPRINT((3, "log_file_create: %s\n", name
));
441 if (error
= vn_open(name
, UIO_SYSSPACE
, FCREAT
|FWRITE
|FOFFMAX
,
442 LOG_MODE
, &vp
, CRCREAT
, 0)) {
443 nfs_cmn_err(error
, CE_WARN
,
444 "log_file_create: Can not open %s - error %m", name
);
447 LOGGING_DPRINT((3, "log_file_create: %s vp=%p v_count=%d\n",
448 name
, (void *)vp
, vp
->v_count
));
450 logfile
= kmem_zalloc(sizeof (*logfile
), KM_SLEEP
);
451 logfile
->lf_path
= name
;
453 * No need to bump the vnode reference count since it is set
454 * to one by vn_open().
457 logfile
->lf_refcnt
= 1;
458 mutex_init(&logfile
->lf_lock
, NULL
, MUTEX_DEFAULT
, NULL
);
461 va
.va_mask
= AT_SIZE
;
462 error
= fop_getattr(vp
, &va
, 0, CRED(), NULL
);
464 nfs_cmn_err(error
, CE_WARN
,
465 "log_file_create: Can not stat %s - error = %m", name
);
469 if (va
.va_size
== 0) {
475 create_buffer_header(&loghdr
, &loghdr_len
, &loghdr_free
);
477 * Dummy up a lr_alloc struct for the write
479 lr
.next
= lr
.prev
= &lr
;
481 lr
.log_record
= loghdr
;
482 lr
.size
= loghdr_len
;
483 lr
.alloc_cache
= NULL
;
487 mutex_enter(&logfile
->lf_lock
);
489 error
= nfslog_write_logrecords(logfile
, &lr
, 1);
491 mutex_exit(&logfile
->lf_lock
);
494 nfs_cmn_err(error
, CE_WARN
,
495 "log_file_create: Can not write header "
496 "on %s - error = %m", name
);
503 kmem_free(loghdr
, loghdr_free
);
510 error1
= fop_close(vp
, FCREAT
|FWRITE
|FOFFMAX
, 1, (offset_t
)0,
513 nfs_cmn_err(error1
, CE_WARN
,
514 "log_file_create: Can not close %s - "
520 kmem_free(name
, namelen
+ 1);
521 if (logfile
!= NULL
) {
522 mutex_destroy(&logfile
->lf_lock
);
523 kmem_free(logfile
, sizeof (*logfile
));
527 kmem_free(loghdr
, loghdr_free
);
533 * Release a log_file structure
536 log_file_rele(struct log_file
*lfp
)
541 mutex_enter(&lfp
->lf_lock
);
542 if (--lfp
->lf_refcnt
> 0) {
544 "log_file_rele lfp=%p decremented refcnt to %d\n",
545 (void *)lfp
, lfp
->lf_refcnt
));
546 mutex_exit(&lfp
->lf_lock
);
549 if (lfp
->lf_refcnt
< 0) {
550 panic("log_file_rele: log_file refcnt < 0");
554 LOGGING_DPRINT((10, "log_file_rele lfp=%p freeing node\n",
557 lfp
->lf_flags
&= ~(L_PRINTED
| L_ERROR
);
559 ASSERT(lfp
->lf_flags
== 0);
560 ASSERT(lfp
->lf_writers
== 0);
562 if (error
= fop_close(lfp
->lf_vp
, FCREAT
|FWRITE
|FOFFMAX
, 1, (offset_t
)0,
564 nfs_cmn_err(error
, CE_WARN
,
565 "NFS: Could not close log buffer %s - error = %m",
570 "log_file_rele: %s has been closed vp=%p v_count=%d\n",
571 lfp
->lf_path
, (void *)lfp
->lf_vp
, lfp
->lf_vp
->v_count
));
576 len
= strlen(lfp
->lf_path
) + 1;
577 kmem_free(lfp
->lf_path
, len
);
578 kmem_free(lfp
, sizeof (*lfp
));
583 * Allocates a record of the size specified.
584 * 'exi' identifies the exportinfo structure being logged.
585 * 'size' indicates how much memory should be allocated
586 * 'cookie' is used to store an opaque value for the caller for later use
587 * 'flags' currently ignored.
589 * Returns a pointer to the beginning of the allocated memory.
590 * 'cookie' is a pointer to the 'lr_alloc' struct; this will be used
591 * to keep track of the encoded record and contains all the info
592 * for enqueuing the record on the log buffer for later writing.
594 * nfslog_record_put() must be used to 'free' this record or allocation.
599 struct exportinfo
*exi
,
604 struct lr_alloc
*lrp
;
606 lrp
= (struct lr_alloc
*)
607 kmem_cache_alloc(nfslog_mem_alloc
[alloc_indx
].mem_cache
,
619 lrp
->log_record
= (caddr_t
)((uintptr_t)lrp
+
620 (uintptr_t)sizeof (struct lr_alloc
));
621 lrp
->size
= nfslog_mem_alloc
[alloc_indx
].size
;
622 lrp
->alloc_cache
= nfslog_mem_alloc
[alloc_indx
].mem_cache
;
625 if (exi
->exi_export
.ex_flags
& EX_LOG
) {
626 LOG_BUFFER_HOLD(exi
->exi_logbuffer
);
627 lrp
->lb
= exi
->exi_logbuffer
;
632 *cookie
= (void *)lrp
;
635 "nfslog_record_alloc(log_buffer=%p mem=%p size=%lu)\n",
636 (void *)exi
->exi_logbuffer
, (void *)lrp
->log_record
, lrp
->size
));
637 return (lrp
->log_record
);
641 * After the above nfslog_record_alloc() has been called and a record
642 * encoded into the buffer that was returned, this function is called
643 * to handle appropriate disposition of the newly created record.
644 * The cookie value is the one that was returned from nfslog_record_alloc().
645 * Size is the actual size of the record that was encoded. This is
646 * passed in because the size used for the alloc was just an approximation.
647 * The sync parameter is used to tell us if we need to force this record
648 * to disk and if not it will be queued for later writing.
650 * Note that if the size parameter has a value of 0, then the record is
651 * not written to the log and the associated data structures are released.
654 nfslog_record_put(void *cookie
, size_t size
, bool_t sync
,
655 unsigned int which_buffers
)
657 struct lr_alloc
*lrp
= (struct lr_alloc
*)cookie
;
658 struct log_buffer
*lbp
= lrp
->lb
;
661 * If the caller has nothing to write or if there is
662 * an apparent error, rele the buffer and free.
664 if (size
== 0 || size
> lrp
->size
) {
665 nfslog_free_logrecords(lrp
);
670 * Reset the size to what actually needs to be written
671 * This is used later on when the iovec is built for
672 * writing the records to the log file.
676 /* append to all if public exi */
677 if (which_buffers
== NFSLOG_ALL_BUFFERS
) {
678 (void) nfslog_record_append2all(lrp
);
679 nfslog_free_logrecords(lrp
);
683 /* Insert the record on the list to be written */
684 mutex_enter(&lbp
->lb_lock
);
685 if (lbp
->lb_records
== NULL
) {
686 lbp
->lb_records
= (caddr_t
)lrp
;
687 lbp
->lb_num_recs
= 1;
688 lbp
->lb_size_queued
= lrp
->size
;
690 insque(lrp
, ((struct lr_alloc
*)lbp
->lb_records
)->prev
);
692 lbp
->lb_size_queued
+= lrp
->size
;
696 * Determine if the queue for this log buffer should be flushed.
697 * This is done by either the number of records queued, the total
698 * size of all records queued or by the request of the caller
699 * via the sync parameter.
701 if (lbp
->lb_size_queued
>= nfslog_num_bytes_to_write
||
702 lbp
->lb_num_recs
> nfslog_num_records_to_write
|| sync
== TRUE
) {
703 mutex_exit(&lbp
->lb_lock
);
704 (void) nfslog_records_flush_to_disk(lbp
);
706 mutex_exit(&lbp
->lb_lock
);
712 * Examine the log_buffer struct to see if there are queue log records
713 * that need to be written to disk. If some exist, pull them off of
714 * the log buffer and write them to the log file.
717 nfslog_records_flush_to_disk(struct log_buffer
*lbp
)
720 mutex_enter(&lbp
->lb_lock
);
722 if (lbp
->lb_records
== NULL
) {
723 mutex_exit(&lbp
->lb_lock
);
726 return (nfslog_records_flush_to_disk_nolock(lbp
));
730 * Function requires that the caller holds lb_lock.
731 * Function flushes any records in the log buffer to the disk.
732 * Function drops the lb_lock on return.
736 nfslog_records_flush_to_disk_nolock(struct log_buffer
*lbp
)
738 struct log_file
*lfp
= NULL
;
739 struct lr_alloc
*lrp_writers
;
743 ASSERT(MUTEX_HELD(&lbp
->lb_lock
));
745 lfp
= lbp
->lb_logfile
;
747 LOG_FILE_LOCK_TO_WRITE(lfp
);
748 ASSERT(lbp
->lb_records
!= NULL
);
750 lrp_writers
= (struct lr_alloc
*)lbp
->lb_records
;
751 lbp
->lb_records
= NULL
;
752 num_recs
= lbp
->lb_num_recs
;
753 lbp
->lb_num_recs
= 0;
754 lbp
->lb_size_queued
= 0;
755 mutex_exit(&lbp
->lb_lock
);
756 error
= nfslog_write_logrecords(lfp
, lrp_writers
, num_recs
);
758 LOG_FILE_UNLOCK_FROM_WRITE(lfp
);
760 nfslog_free_logrecords(lrp_writers
);
766 * Take care of writing the provided log record(s) to the log file.
767 * We group the log records with an iovec and use fop_write to append
768 * them to the end of the log file.
771 nfslog_write_logrecords(struct log_file
*lfp
,
772 struct lr_alloc
*lrp_writers
, int num_recs
)
779 struct lr_alloc
*lrp
;
782 int ioflag
= FAPPEND
;
785 ASSERT(MUTEX_HELD(&lfp
->lf_lock
));
789 size_iovecs
= sizeof (struct iovec
) * num_recs
;
790 iovp
= kmem_alloc(size_iovecs
, KM_NOSLEEP
);
797 /* Build the iovec based on the list of log records */
802 iovp
[i
].iov_base
= lrp
->log_record
;
803 iovp
[i
].iov_len
= lrp
->size
;
807 } while (lrp
!= lrp_writers
);
809 ASSERT(i
== num_recs
);
812 uio
.uio_iovcnt
= num_recs
;
814 uio
.uio_segflg
= (short)UIO_SYSSPACE
;
816 uio
.uio_llimit
= (rlim64_t
)MAXOFFSET_T
;
817 uio
.uio_fmode
= FWRITE
;
818 uio
.uio_extflg
= UIO_COPY_DEFAULT
;
821 * Save the size. If the write fails, reset the size to avoid
822 * corrupted log buffer files.
824 va
.va_mask
= AT_SIZE
;
826 (void) fop_rwlock(vp
, V_WRITELOCK_TRUE
, NULL
); /* UIO_WRITE */
827 if ((error
= fop_getattr(vp
, &va
, 0, CRED(), NULL
)) == 0) {
828 if ((len
+ va
.va_size
) < (MAXOFF32_T
)) {
829 error
= fop_write(vp
, &uio
, ioflag
, CRED(), NULL
);
830 fop_rwunlock(vp
, V_WRITELOCK_TRUE
, NULL
);
834 (void) fop_setattr(vp
, &va
, 0, CRED(), NULL
);
836 fop_rwunlock(vp
, V_WRITELOCK_TRUE
, NULL
);
837 if (!(lfp
->lf_flags
& L_PRINTED
)) {
839 "NFS Logging: buffer file %s exceeds 2GB; "
840 "stopped writing buffer \n", lfp
->lf_path
);
845 fop_rwunlock(vp
, V_WRITELOCK_TRUE
, NULL
);
848 kmem_free(iovp
, size_iovecs
);
852 if (!(lfp
->lf_flags
& L_PRINTED
)) {
853 nfs_cmn_err(error
, CE_WARN
,
854 "NFS Logging disabled for buffer %s - "
855 "write error = %m\n", lfp
->lf_path
);
856 lfp
->lf_flags
|= L_PRINTED
;
858 } else if (lfp
->lf_flags
& (L_ERROR
| L_PRINTED
)) {
859 lfp
->lf_flags
&= ~(L_ERROR
| L_PRINTED
);
861 "NFS Logging re-enabled for buffer %s\n", lfp
->lf_path
);
868 nfslog_free_logrecords(struct lr_alloc
*lrp_writers
)
870 struct lr_alloc
*lrp
= lrp_writers
;
871 struct lr_alloc
*lrp_free
;
879 * Check to see if we are supposed to free this structure
880 * and relese the log_buffer ref count.
881 * It may be the case that the caller does not want this
882 * structure and its record contents freed just yet.
884 if ((lrp_free
->lr_flags
& LR_ALLOC_NOFREE
) == 0) {
885 if (lrp_free
->lb
!= NULL
)
886 log_buffer_rele(lrp_free
->lb
);
887 if (lrp_free
->alloc_cache
) /* double check */
888 kmem_cache_free(lrp_free
->alloc_cache
,
892 * after being pulled from the list the
893 * pointers need to be reinitialized.
895 lrp_free
->next
= lrp_free
;
896 lrp_free
->prev
= lrp_free
;
899 } while (lrp
!= lrp_writers
);
903 * Rename lbp->lb_logfile to reflect the true name requested by 'share'
906 nfslog_logbuffer_rename(struct log_buffer
*lbp
)
910 struct log_file
*logfile
;
913 * Try our best to get the cache records into the log file
914 * before the rename occurs.
916 (void) nfslog_records_flush_to_disk(lbp
);
919 * Hold lb_lock before retrieving
921 * Hold a reference to the
922 * "lf" structure. this is
923 * same as LOG_FILE_HOLD()
925 mutex_enter(&(lbp
)->lb_lock
);
926 lf
= lbp
->lb_logfile
;
927 mutex_enter(&(lf
)->lf_lock
);
928 mutex_exit(&(lbp
)->lb_lock
);
930 mutex_exit(&(lf
)->lf_lock
);
932 LOGGING_DPRINT((10, "nfslog_logbuffer_rename: renaming %s to %s\n",
933 lf
->lf_path
, lbp
->lb_path
));
936 * rename the current buffer to what the daemon expects
938 if (error
= nfslog_logfile_rename(lf
->lf_path
, lbp
->lb_path
))
942 * Create a new working buffer file and have all new data sent there.
944 if (error
= log_file_create(lbp
->lb_path
, &logfile
)) {
945 /* Attempt to rename to original */
946 (void) nfslog_logfile_rename(lbp
->lb_path
, lf
->lf_path
);
951 * Hold the lb_lock here, this will make
952 * all the threads trying to access lb->logfile block
953 * and get a new logfile structure instead of old one.
955 mutex_enter(&(lbp
)->lb_lock
);
956 lbp
->lb_logfile
= logfile
;
957 mutex_exit(&(lbp
)->lb_lock
);
959 LOG_FILE_RELE(lf
); /* release log_buffer's reference */
962 * Wait for log_file to be in a quiescent state before we
963 * return to our caller to let it proceed with the reading of
966 nfslog_logfile_wait(lf
);
970 * Release our reference on "lf" in two different cases.
971 * 1. Error condition, release only the reference
972 * that we held at the begining of this
973 * routine on "lf" structure.
974 * 2. Fall through condition, no errors but the old
975 * logfile structure "lf" has been replaced with
976 * the new "logfile" structure, so release the
977 * reference that was part of the creation of
978 * "lf" structure to free up the resources.
987 * Renames the 'from' file to 'new'.
990 nfslog_logfile_rename(char *from
, char *new)
994 if (error
= vn_rename(from
, new, UIO_SYSSPACE
)) {
996 "nfslog_logfile_rename: couldn't rename %s to %s\n",
1003 * Wait for the log_file writers to finish before returning
1006 nfslog_logfile_wait(struct log_file
*lf
)
1008 mutex_enter(&lf
->lf_lock
);
1009 while (lf
->lf_writers
> 0) {
1010 lf
->lf_flags
|= L_WAITING
;
1011 (void) cv_wait_sig(&lf
->lf_cv_waiters
, &lf
->lf_lock
);
1013 mutex_exit(&lf
->lf_lock
);
1017 nfslog_record_append2all(struct lr_alloc
*lrp
)
1019 struct log_buffer
*lbp
, *nlbp
;
1020 int error
, ret_error
= 0;
1021 int lr_flags
= lrp
->lr_flags
;
1023 rw_enter(&nfslog_buffer_list_lock
, RW_READER
);
1024 if ((lbp
= nfslog_buffer_list
) != NULL
)
1025 LOG_BUFFER_HOLD(lbp
);
1026 for (nlbp
= NULL
; lbp
!= NULL
; lbp
= nlbp
) {
1027 if ((nlbp
= lbp
->lb_next
) != NULL
) {
1029 * Remember next element in the list
1031 LOG_BUFFER_HOLD(nlbp
);
1033 rw_exit(&nfslog_buffer_list_lock
);
1036 * Insert the record on the buffer's list to be written
1037 * and then flush the records to the log file.
1038 * Make sure to set the no free flag so that the
1039 * record can be used for the next write
1041 lrp
->lr_flags
= LR_ALLOC_NOFREE
;
1043 ASSERT(lbp
!= NULL
);
1044 mutex_enter(&lbp
->lb_lock
);
1045 if (lbp
->lb_records
== NULL
) {
1046 lbp
->lb_records
= (caddr_t
)lrp
;
1047 lbp
->lb_num_recs
= 1;
1048 lbp
->lb_size_queued
= lrp
->size
;
1050 insque(lrp
, ((struct lr_alloc
*)lbp
->lb_records
)->prev
);
1052 lbp
->lb_size_queued
+= lrp
->size
;
1056 * Flush log records to disk.
1057 * Function is called with lb_lock held.
1058 * Function drops the lb_lock on return.
1060 error
= nfslog_records_flush_to_disk_nolock(lbp
);
1064 nfs_cmn_err(error
, CE_WARN
,
1065 "rfsl_log_pubfh: could not append record to "
1066 "\"%s\" error = %m\n", lbp
->lb_path
);
1068 log_buffer_rele(lbp
);
1069 rw_enter(&nfslog_buffer_list_lock
, RW_READER
);
1071 rw_exit(&nfslog_buffer_list_lock
);
1073 lrp
->lr_flags
= lr_flags
;
1079 static int logging_debug
= 0;
1083 * 3) current test software
1087 nfslog_dprint(const int level
, const char *fmt
, ...)
1091 if (logging_debug
== level
||
1092 (logging_debug
> 10 && (logging_debug
- 10) >= level
)) {
1093 va_start(args
, fmt
);
1094 (void) vprintf(fmt
, args
);
1102 * NFS Log Flush system call
1103 * Caller must check privileges.
1107 nfsl_flush(struct nfsl_flush_args
*args
, model_t model
)
1109 struct flush_thread_params
*tparams
;
1110 struct nfsl_flush_args
*nfsl_args
;
1113 STRUCT_HANDLE(nfsl_flush_args
, uap
);
1115 STRUCT_SET_HANDLE(uap
, model
, args
);
1117 tparams
= (struct flush_thread_params
*)
1118 kmem_zalloc(sizeof (*tparams
), KM_SLEEP
);
1120 nfsl_args
= &tparams
->tp_args
;
1121 nfsl_args
->version
= STRUCT_FGET(uap
, version
);
1122 if (nfsl_args
->version
!= NFSL_FLUSH_ARGS_VERS
) {
1123 cmn_err(CE_WARN
, "nfsl_flush: exected version %d, got %d",
1124 NFSL_FLUSH_ARGS_VERS
, nfsl_args
->version
);
1128 nfsl_args
->directive
= STRUCT_FGET(uap
, directive
);
1129 if ((nfsl_args
->directive
& NFSL_ALL
) == 0) {
1131 * Process a specific buffer
1133 nfsl_args
->buff_len
= STRUCT_FGET(uap
, buff_len
);
1135 nfsl_args
->buff
= (char *)
1136 kmem_alloc(nfsl_args
->buff_len
, KM_NOSLEEP
);
1137 if (nfsl_args
->buff
== NULL
)
1140 error
= copyinstr((const char *)STRUCT_FGETP(uap
, buff
),
1141 nfsl_args
->buff
, nfsl_args
->buff_len
, &buffer_len
);
1145 if (nfsl_args
->buff_len
!= buffer_len
)
1149 LOGGING_DPRINT((10, "nfsl_flush: Flushing %s buffer(s)\n",
1150 nfsl_args
->directive
& NFSL_ALL
? "all" : nfsl_args
->buff
));
1152 if (nfsl_args
->directive
& NFSL_SYNC
) {
1154 * Do the work synchronously
1156 nfslog_do_flush(tparams
);
1157 error
= tparams
->tp_error
;
1158 kmem_free(nfsl_args
->buff
, nfsl_args
->buff_len
);
1159 kmem_free(tparams
, sizeof (*tparams
));
1162 * Do the work asynchronously
1164 (void) thread_create(NULL
, 0, nfslog_do_flush
,
1165 tparams
, 0, &p0
, TS_RUN
, minclsyspri
);
1172 * This is where buffer flushing would occur, but there is no buffering
1174 * Possibly rename the log buffer for processing.
1175 * Sets tparams->ta_error equal to the value of the error that occurred,
1177 * Returns ENOENT if the buffer is not found.
1180 nfslog_do_flush(struct flush_thread_params
*tparams
)
1182 struct nfsl_flush_args
*args
;
1183 struct log_buffer
*lbp
, *nlbp
;
1186 char *buf_inprog
; /* name of buff in progress */
1190 * Sanity check on the arguments.
1194 args
= &tparams
->tp_args
;
1198 rw_enter(&nfslog_buffer_list_lock
, RW_READER
);
1199 if ((lbp
= nfslog_buffer_list
) != NULL
) {
1200 LOG_BUFFER_HOLD(lbp
);
1202 for (nlbp
= NULL
; lbp
!= NULL
; lbp
= nlbp
) {
1203 if ((nlbp
= lbp
->lb_next
) != NULL
) {
1204 LOG_BUFFER_HOLD(nlbp
);
1206 rw_exit(&nfslog_buffer_list_lock
);
1207 if (args
->directive
& NFSL_ALL
) {
1208 (void) nfslog_records_flush_to_disk(lbp
);
1210 if ((strcmp(lbp
->lb_path
, args
->buff
) == 0) &&
1211 (args
->directive
& NFSL_RENAME
)) {
1212 error
= nfslog_logbuffer_rename(lbp
);
1215 log_buffer_rele(nlbp
);
1216 log_buffer_rele(lbp
);
1220 log_buffer_rele(lbp
);
1221 rw_enter(&nfslog_buffer_list_lock
, RW_READER
);
1224 rw_exit(&nfslog_buffer_list_lock
);
1226 if (!found
&& ((args
->directive
& NFSL_ALL
) == 0) &&
1227 (args
->directive
& NFSL_RENAME
)) {
1229 * The specified buffer is not currently in use,
1230 * simply rename the file indicated.
1232 buf_inprog_len
= strlen(args
->buff
) +
1233 strlen(LOG_INPROG_STRING
) + 1;
1234 buf_inprog
= kmem_alloc(buf_inprog_len
, KM_SLEEP
);
1235 (void) sprintf(buf_inprog
, "%s%s",
1236 args
->buff
, LOG_INPROG_STRING
);
1238 error
= nfslog_logfile_rename(buf_inprog
, args
->buff
);
1240 kmem_free(buf_inprog
, buf_inprog_len
);
1244 if ((args
->directive
& NFSL_SYNC
) == 0) {
1246 * Work was performed asynchronously, the caller is
1247 * no longer waiting for us.
1248 * Free the thread arguments and exit.
1250 kmem_free(args
->buff
, args
->buff_len
);
1251 kmem_free(tparams
, sizeof (*tparams
));
1256 tparams
->tp_error
= error
;
1260 * Generate buffer_header.
1261 * 'loghdr' points the the buffer_header, and *reclen
1262 * contains the length of the buffer.
1265 create_buffer_header(caddr_t
*loghdr
, size_t *reclen
, size_t *freesize
)
1268 nfslog_buffer_header lh
;
1270 unsigned int final_size
;
1273 /* pick some size that will hold the buffer_header */
1274 *freesize
= NFSLOG_SMALL_RECORD_SIZE
;
1279 lh
.bh_length
= 0; /* don't know yet how large it will be */
1280 lh
.bh_version
= NFSLOG_BUF_VERSION
;
1284 TIMESPEC_TO_TIMESPEC32(&lh
.bh_timestamp
, &now
);
1289 *loghdr
= kmem_alloc(*freesize
, KM_SLEEP
);
1290 xdrmem_create(&xdrs
, *loghdr
, *freesize
, XDR_ENCODE
);
1292 (void) xdr_nfslog_buffer_header(&xdrs
, &lh
);
1295 * Reset with final size of the encoded data
1297 final_size
= xdr_getpos(&xdrs
);
1298 xdr_setpos(&xdrs
, 0);
1299 (void) xdr_u_int(&xdrs
, &final_size
);
1301 *reclen
= (size_t)final_size
;
1305 * ****************************************************************
1306 * RPC dispatch table for logging
1307 * Indexed by program, version, proc
1308 * Based on NFS dispatch table.
1310 struct nfslog_proc_disp
{
1311 bool_t (*xdrargs
)();
1313 bool_t affects_transactions
; /* Operation affects transaction */
1317 struct nfslog_vers_disp
{
1318 int nfslog_dis_nprocs
; /* number of procs */
1319 struct nfslog_proc_disp
*nfslog_dis_proc_table
; /* proc array */
1322 struct nfslog_prog_disp
{
1323 int nfslog_dis_prog
; /* program number */
1324 int nfslog_dis_versmin
; /* Minimum version value */
1325 int nfslog_dis_nvers
; /* Number of version values */
1326 struct nfslog_vers_disp
*nfslog_dis_vers_table
; /* versions array */
1329 static int rfs_log_bad
= 0; /* incremented on bad log attempts */
1330 static int rfs_log_good
= 0; /* incremented on successful log attempts */
1333 * Define the actions taken per prog/vers/proc:
1335 * In some cases, the nl types are the same as the nfs types and a simple
1336 * bcopy should suffice. Rather that define tens of identical procedures,
1337 * simply define these to bcopy. Similarly this takes care of different
1338 * procs that use same parameter struct.
1341 static struct nfslog_proc_disp nfslog_proc_v2
[] = {
1347 {xdr_void
, xdr_void
, FALSE
},
1349 /* RFS_GETATTR = 1 */
1350 {xdr_fhandle
, xdr_nfslog_getattrres
, FALSE
},
1352 /* RFS_SETATTR = 2 */
1353 {xdr_nfslog_setattrargs
, xdr_nfsstat
, TRUE
},
1355 /* RFS_ROOT = 3 *** NO LONGER SUPPORTED *** */
1356 {xdr_void
, xdr_void
, FALSE
},
1358 /* RFS_LOOKUP = 4 */
1359 {xdr_nfslog_diropargs
, xdr_nfslog_diropres
, TRUE
},
1361 /* RFS_READLINK = 5 */
1362 {xdr_fhandle
, xdr_nfslog_rdlnres
, FALSE
},
1365 {xdr_nfslog_nfsreadargs
, xdr_nfslog_rdresult
, TRUE
},
1367 /* RFS_WRITECACHE = 7 *** NO LONGER SUPPORTED *** */
1368 {xdr_void
, xdr_void
, FALSE
},
1371 {xdr_nfslog_writeargs
, xdr_nfslog_writeresult
, TRUE
},
1373 /* RFS_CREATE = 9 */
1374 {xdr_nfslog_createargs
, xdr_nfslog_diropres
, TRUE
},
1376 /* RFS_REMOVE = 10 */
1377 {xdr_nfslog_diropargs
, xdr_nfsstat
, TRUE
},
1379 /* RFS_RENAME = 11 */
1380 {xdr_nfslog_rnmargs
, xdr_nfsstat
, TRUE
},
1383 {xdr_nfslog_linkargs
, xdr_nfsstat
, TRUE
},
1385 /* RFS_SYMLINK = 13 */
1386 {xdr_nfslog_symlinkargs
, xdr_nfsstat
, TRUE
},
1388 /* RFS_MKDIR = 14 */
1389 {xdr_nfslog_createargs
, xdr_nfslog_diropres
, TRUE
},
1391 /* RFS_RMDIR = 15 */
1392 {xdr_nfslog_diropargs
, xdr_nfsstat
, TRUE
},
1394 /* RFS_READDIR = 16 */
1395 {xdr_nfslog_rddirargs
, xdr_nfslog_rddirres
, TRUE
},
1397 /* RFS_STATFS = 17 */
1398 {xdr_fhandle
, xdr_nfslog_statfs
, FALSE
},
1406 static struct nfslog_proc_disp nfslog_proc_v3
[] = {
1408 /* NFSPROC3_NULL = 0 */
1409 {xdr_void
, xdr_void
, FALSE
},
1411 /* NFSPROC3_GETATTR = 1 */
1412 {xdr_nfslog_nfs_fh3
, xdr_nfslog_GETATTR3res
, FALSE
},
1414 /* NFSPROC3_SETATTR = 2 */
1415 {xdr_nfslog_SETATTR3args
, xdr_nfslog_SETATTR3res
, TRUE
},
1417 /* NFSPROC3_LOOKUP = 3 */
1418 {xdr_nfslog_diropargs3
, xdr_nfslog_LOOKUP3res
, TRUE
},
1420 /* NFSPROC3_ACCESS = 4 */
1421 {xdr_nfslog_ACCESS3args
, xdr_nfslog_ACCESS3res
, FALSE
},
1423 /* NFSPROC3_READLINK = 5 */
1424 {xdr_nfslog_nfs_fh3
, xdr_nfslog_READLINK3res
, FALSE
},
1426 /* NFSPROC3_READ = 6 */
1427 {xdr_nfslog_READ3args
, xdr_nfslog_READ3res
, TRUE
},
1429 /* NFSPROC3_WRITE = 7 */
1430 {xdr_nfslog_WRITE3args
, xdr_nfslog_WRITE3res
, TRUE
},
1432 /* NFSPROC3_CREATE = 8 */
1433 {xdr_nfslog_CREATE3args
, xdr_nfslog_CREATE3res
, TRUE
},
1435 /* NFSPROC3_MKDIR = 9 */
1436 {xdr_nfslog_MKDIR3args
, xdr_nfslog_MKDIR3res
, TRUE
},
1438 /* NFSPROC3_SYMLINK = 10 */
1439 {xdr_nfslog_SYMLINK3args
, xdr_nfslog_SYMLINK3res
, TRUE
},
1441 /* NFSPROC3_MKNOD = 11 */
1442 {xdr_nfslog_MKNOD3args
, xdr_nfslog_MKNOD3res
, TRUE
},
1444 /* NFSPROC3_REMOVE = 12 */
1445 {xdr_nfslog_REMOVE3args
, xdr_nfslog_REMOVE3res
, TRUE
},
1447 /* NFSPROC3_RMDIR = 13 */
1448 {xdr_nfslog_RMDIR3args
, xdr_nfslog_RMDIR3res
, TRUE
},
1450 /* NFSPROC3_RENAME = 14 */
1451 {xdr_nfslog_RENAME3args
, xdr_nfslog_RENAME3res
, TRUE
},
1453 /* NFSPROC3_LINK = 15 */
1454 {xdr_nfslog_LINK3args
, xdr_nfslog_LINK3res
, TRUE
},
1456 /* NFSPROC3_READDIR = 16 */
1457 {xdr_nfslog_READDIR3args
, xdr_nfslog_READDIR3res
, TRUE
},
1459 /* NFSPROC3_READDIRPLUS = 17 */
1460 {xdr_nfslog_READDIRPLUS3args
, xdr_nfslog_READDIRPLUS3res
, TRUE
},
1462 /* NFSPROC3_FSSTAT = 18 */
1463 {xdr_nfslog_FSSTAT3args
, xdr_nfslog_FSSTAT3res
, FALSE
},
1465 /* NFSPROC3_FSINFO = 19 */
1466 {xdr_nfslog_FSINFO3args
, xdr_nfslog_FSINFO3res
, FALSE
},
1468 /* NFSPROC3_PATHCONF = 20 */
1469 {xdr_nfslog_PATHCONF3args
, xdr_nfslog_PATHCONF3res
, FALSE
},
1471 /* NFSPROC3_COMMIT = 21 */
1472 {xdr_nfslog_COMMIT3args
, xdr_nfslog_COMMIT3res
, FALSE
},
1475 static struct nfslog_proc_disp nfslog_proc_v1
[] = {
1480 /* NFSLOG_NULL = 0 */
1481 {xdr_void
, xdr_void
, TRUE
},
1483 /* NFSLOG_SHARE = 1 */
1484 {xdr_nfslog_sharefsargs
, xdr_nfslog_sharefsres
, TRUE
},
1486 /* NFSLOG_UNSHARE = 2 */
1487 {xdr_nfslog_sharefsargs
, xdr_nfslog_sharefsres
, TRUE
},
1489 /* NFSLOG_LOOKUP = 3 */
1490 {xdr_nfslog_diropargs3
, xdr_nfslog_LOOKUP3res
, TRUE
},
1492 /* NFSLOG_GETFH = 4 */
1493 {xdr_nfslog_getfhargs
, xdr_nfsstat
, TRUE
},
1496 static struct nfslog_vers_disp nfslog_vers_disptable
[] = {
1497 {sizeof (nfslog_proc_v2
) / sizeof (nfslog_proc_v2
[0]),
1499 {sizeof (nfslog_proc_v3
) / sizeof (nfslog_proc_v3
[0]),
1503 static struct nfslog_vers_disp nfslog_nfslog_vers_disptable
[] = {
1504 {sizeof (nfslog_proc_v1
) / sizeof (nfslog_proc_v1
[0]),
1508 static struct nfslog_prog_disp nfslog_dispatch_table
[] = {
1509 {NFS_PROGRAM
, NFS_VERSMIN
,
1510 (sizeof (nfslog_vers_disptable
) /
1511 sizeof (nfslog_vers_disptable
[0])),
1512 nfslog_vers_disptable
},
1514 {NFSLOG_PROGRAM
, NFSLOG_VERSMIN
,
1515 (sizeof (nfslog_nfslog_vers_disptable
) /
1516 sizeof (nfslog_nfslog_vers_disptable
[0])),
1517 nfslog_nfslog_vers_disptable
},
1520 static int nfslog_dispatch_table_arglen
= sizeof (nfslog_dispatch_table
) /
1521 sizeof (nfslog_dispatch_table
[0]);
1524 * This function will determine the appropriate export info struct to use
1525 * and allocate a record id to be used in the written log buffer.
1526 * Usually this is a straightforward operation but the existence of the
1527 * multicomponent lookup and its semantics of crossing file system
1528 * boundaries add to the complexity. See the comments below...
1532 struct exportinfo
*exi
,
1533 struct svc_req
*req
,
1535 unsigned int *nfslog_rec_id
)
1537 struct log_buffer
*lb
;
1538 struct exportinfo
*exi_ret
= NULL
;
1546 * If the exi is marked for logging, allocate a record id and return
1548 if (exi
->exi_export
.ex_flags
& EX_LOG
) {
1549 lb
= exi
->exi_logbuffer
;
1551 /* obtain the unique record id for the caller */
1552 *nfslog_rec_id
= atomic_add_32_nv(&lb
->lb_rec_id
, (int32_t)1);
1555 * The caller will expect to be able to exi_rele() it,
1556 * so exi->exi_count must be incremented before it can
1557 * be returned, to make it uniform with exi_ret->exi_count
1563 if (exi
!= exi_public
)
1567 * Here we have an exi that is not marked for logging.
1568 * It is possible that this request is a multicomponent lookup
1569 * that was done from the public file handle (not logged) and
1570 * the resulting file handle being returned to the client exists
1571 * in a file system that is being logged. If this is the case
1572 * we need to log this multicomponent lookup to the appropriate
1573 * log buffer. This will allow for the appropriate path name
1574 * mapping to occur at user level.
1576 if (req
->rq_prog
== NFS_PROGRAM
) {
1577 switch (req
->rq_vers
) {
1579 if ((req
->rq_proc
== NFSPROC3_LOOKUP
) &&
1580 (((LOOKUP3res
*)res
)->status
== NFS3_OK
)) {
1581 fh3
= &((LOOKUP3res
*)res
)->res_u
.ok
.object
;
1582 exi_ret
= checkexport(&fh3
->fh3_fsid
,
1588 if ((req
->rq_proc
== RFS_LOOKUP
) &&
1589 (((struct nfsdiropres
*)
1590 res
)->dr_status
== NFS_OK
)) {
1591 fh
= &((struct nfsdiropres
*)res
)->
1592 dr_u
.dr_drok_u
.drok_fhandle
;
1593 exi_ret
= checkexport(&fh
->fh_fsid
,
1594 (fid_t
*)&fh
->fh_xlen
);
1602 if (exi_ret
!= NULL
&& exi_ret
->exi_export
.ex_flags
& EX_LOG
) {
1603 lb
= exi_ret
->exi_logbuffer
;
1604 /* obtain the unique record id for the caller */
1605 *nfslog_rec_id
= atomic_add_32_nv(&lb
->lb_rec_id
, (int32_t)1);
1613 static long long rfslog_records_ignored
= 0;
1617 * nfslog_write_record - Fill in the record buffer for writing out.
1618 * If logrecp is null, log it, otherwise, malloc the record and return it.
1620 * It is the responsibility of the caller to check whether this exportinfo
1621 * has logging enabled.
1622 * Note that nfslog_share_public_record() only needs to check for the
1623 * existence of at least one logbuffer to which the public filehandle record
1624 * needs to be logged.
1627 nfslog_write_record(struct exportinfo
*exi
, struct svc_req
*req
,
1628 caddr_t args
, caddr_t res
, cred_t
*cr
, struct netbuf
*pnb
,
1629 unsigned int record_id
, unsigned int which_buffers
)
1631 struct nfslog_prog_disp
*progtable
; /* prog struct */
1632 struct nfslog_vers_disp
*verstable
; /* version struct */
1633 struct nfslog_proc_disp
*disp
= NULL
; /* proc struct */
1635 void *log_cookie
; /* for logrecord if */
1638 unsigned int final_size
;
1642 ASSERT(exi
!= NULL
); ASSERT(req
!= NULL
); ASSERT(args
!= NULL
);
1643 ASSERT(res
!= NULL
); ASSERT(cr
!= NULL
);
1646 * Find program element
1647 * Search the list since program can not be used as index
1649 for (i
= 0; (i
< nfslog_dispatch_table_arglen
); i
++) {
1650 if (req
->rq_prog
== nfslog_dispatch_table
[i
].nfslog_dis_prog
)
1653 if (i
>= nfslog_dispatch_table_arglen
) { /* program not logged */
1659 * Extract the dispatch functions based on program/version
1661 progtable
= &nfslog_dispatch_table
[i
];
1662 vers
= req
->rq_vers
- progtable
->nfslog_dis_versmin
;
1663 verstable
= &progtable
->nfslog_dis_vers_table
[vers
];
1664 disp
= &verstable
->nfslog_dis_proc_table
[req
->rq_proc
];
1666 if (!(exi
->exi_export
.ex_flags
& EX_LOG_ALLOPS
) &&
1667 !disp
->affects_transactions
) {
1669 * Only interested in logging operations affecting
1670 * transaction generation. This is not one of them.
1673 rfslog_records_ignored
++;
1678 switch (req
->rq_prog
) {
1680 switch (req
->rq_vers
) {
1682 switch (req
->rq_proc
) {
1683 case NFSPROC3_READDIRPLUS
:
1684 alloc_indx
= MEDIUM_INDX
;
1687 alloc_indx
= SMALL_INDX
;
1692 alloc_indx
= SMALL_INDX
;
1696 case NFSLOG_PROGRAM
:
1697 alloc_indx
= MEDIUM_INDX
;
1700 alloc_indx
= SMALL_INDX
;
1707 /* Pick the size to alloc; end of the road - return */
1708 if (nfslog_mem_alloc
[alloc_indx
].size
== (-1)) {
1710 "NFSLOG: unable to encode record - prog=%d "
1711 "proc = %d", req
->rq_prog
, req
->rq_proc
);
1715 buffer
= nfslog_record_alloc(exi
, alloc_indx
, &log_cookie
, 0);
1716 if (buffer
== NULL
) {
1717 /* Error processing - no space alloced */
1719 cmn_err(CE_WARN
, "NFSLOG: can't get record");
1723 xdrmem_create(&xdrs
, buffer
,
1724 nfslog_mem_alloc
[alloc_indx
].size
, XDR_ENCODE
);
1727 * Encode the header, args and results of the record
1729 if (xdr_nfslog_request_record(&xdrs
, exi
, req
, cr
, pnb
,
1730 nfslog_mem_alloc
[alloc_indx
].size
, record_id
) &&
1731 (*disp
->xdrargs
)(&xdrs
, args
) &&
1732 (*disp
->xdrres
)(&xdrs
, res
)) {
1737 * Get the final size of the encoded
1738 * data and insert that length at the
1741 final_size
= xdr_getpos(&xdrs
);
1742 xdr_setpos(&xdrs
, 0);
1743 (void) xdr_u_int(&xdrs
, &final_size
);
1745 /* Oops, the encode failed so we need to free memory */
1746 nfslog_record_put(log_cookie
, 0, FALSE
, which_buffers
);
1750 } while (encode_ok
== FALSE
);
1754 * Take the final log record and put it in the log file.
1755 * This may be queued to the file internally and written
1756 * later unless the last parameter is TRUE.
1757 * If the record_id is 0 then this is most likely a share/unshare
1758 * request and it should be written synchronously to the log file.
1760 nfslog_record_put(log_cookie
,
1761 final_size
, (record_id
== 0), which_buffers
);
1765 get_publicfh_path(int *alloc_length
)
1767 extern struct exportinfo
*exi_public
;
1770 rw_enter(&exported_lock
, RW_READER
);
1772 *alloc_length
= exi_public
->exi_export
.ex_pathlen
+ 1;
1773 pubpath
= kmem_alloc(*alloc_length
, KM_SLEEP
);
1775 (void) strcpy(pubpath
, exi_public
->exi_export
.ex_path
);
1777 rw_exit(&exported_lock
);
1783 log_public_record(struct exportinfo
*exi
, cred_t
*cr
)
1786 struct netbuf nb
= {0, 0, NULL
};
1787 int free_length
= 0;
1791 bzero(&req
, sizeof (req
));
1792 req
.rq_prog
= NFSLOG_PROGRAM
;
1793 req
.rq_vers
= NFSLOG_VERSION
;
1794 req
.rq_proc
= NFSLOG_LOOKUP
;
1795 req
.rq_cred
.oa_flavor
= AUTH_NONE
;
1797 bzero(&args
, sizeof (diropargs3
));
1798 bzero(&res
, sizeof (LOOKUP3res
));
1800 args
.dir
.fh3_length
= 0;
1801 if ((args
.name
= get_publicfh_path(&free_length
)) == NULL
)
1803 args
.dirp
= &args
.dir
;
1805 res
.status
= NFS3_OK
;
1806 res
.res_u
.ok
.object
.fh3_length
= 0;
1809 * Calling this function with the exi_public
1810 * will have the effect of appending the record
1811 * to each of the open log buffers
1813 nfslog_write_record(exi
, &req
,
1814 (caddr_t
)&args
, (caddr_t
)&res
, cr
, &nb
, 0, NFSLOG_ALL_BUFFERS
);
1816 kmem_free(args
.name
, free_length
);
1820 * nfslog_share_record - logs a share request.
1821 * This is not an NFS request, but we pretend here...
1824 nfslog_share_record(struct exportinfo
*exi
, cred_t
*cr
)
1828 struct netbuf nb
= {0, 0, NULL
};
1830 ASSERT(exi
!= NULL
);
1832 if (nfslog_buffer_list
== NULL
)
1835 if (exi
->exi_export
.ex_flags
& EX_LOG
) {
1836 bzero(&req
, sizeof (req
));
1837 req
.rq_prog
= NFSLOG_PROGRAM
;
1838 req
.rq_vers
= NFSLOG_VERSION
;
1839 req
.rq_proc
= NFSLOG_SHARE
;
1840 req
.rq_cred
.oa_flavor
= AUTH_NONE
;
1841 nfslog_write_record(exi
, &req
, (caddr_t
)exi
, (caddr_t
)&res
, cr
,
1842 &nb
, 0, NFSLOG_ONE_BUFFER
);
1845 log_public_record(exi
, cr
);
1849 * nfslog_unshare_record - logs an unshare request.
1850 * This is not an NFS request, but we pretend here...
1853 nfslog_unshare_record(struct exportinfo
*exi
, cred_t
*cr
)
1857 struct netbuf nb
= {0, 0, NULL
};
1859 ASSERT(exi
!= NULL
);
1860 ASSERT(exi
->exi_export
.ex_flags
& EX_LOG
);
1862 bzero(&req
, sizeof (req
));
1863 req
.rq_prog
= NFSLOG_PROGRAM
;
1864 req
.rq_vers
= NFSLOG_VERSION
;
1865 req
.rq_proc
= NFSLOG_UNSHARE
;
1866 req
.rq_cred
.oa_flavor
= AUTH_NONE
;
1867 nfslog_write_record(exi
, &req
,
1868 (caddr_t
)exi
, (caddr_t
)&res
, cr
, &nb
, 0, NFSLOG_ONE_BUFFER
);
1873 nfslog_getfh(struct exportinfo
*exi
,
1881 struct netbuf nb
= {0, 0, NULL
};
1885 nfslog_getfhargs gfh
;
1887 ASSERT(exi
!= NULL
);
1888 ASSERT(exi
->exi_export
.ex_flags
& EX_LOG
);
1890 bzero(&req
, sizeof (req
));
1891 req
.rq_prog
= NFSLOG_PROGRAM
;
1892 req
.rq_vers
= NFSLOG_VERSION
;
1893 req
.rq_proc
= NFSLOG_GETFH
;
1894 req
.rq_cred
.oa_flavor
= AUTH_NONE
;
1896 namebuf
= kmem_alloc(MAXPATHLEN
+ 4, KM_SLEEP
);
1897 if (seg
== UIO_USERSPACE
) {
1898 error
= copyinstr(fname
, namebuf
, MAXPATHLEN
, &len
);
1900 error
= copystr(fname
, namebuf
, MAXPATHLEN
, &len
);
1904 gfh
.gfh_fh_buf
= *fh
;
1905 gfh
.gfh_path
= namebuf
;
1907 nfslog_write_record(exi
, &req
, (caddr_t
)&gfh
, (caddr_t
)&res
,
1908 cr
, &nb
, 0, NFSLOG_ONE_BUFFER
);
1910 kmem_free(namebuf
, MAXPATHLEN
+ 4);