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
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.
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]
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * nfs log - read buffer file and return structs in usable form
39 #include <sys/types.h>
40 #include <sys/param.h>
42 #include <sys/utsname.h>
55 #include <netconfig.h>
57 #include <nfs/nfs_sec.h>
58 #include <nfs/export.h>
64 #include <nfs/nfs_log.h>
67 #define MAX_LRS_READ_AHEAD 2048
68 #define MAX_RECS_TO_DELAY 32768
70 static int nfslog_init_buf(char *, struct nfslog_buf
*, int *);
71 static void nfslog_free_buf(struct nfslog_buf
*, int);
72 static struct nfslog_lr
*nfslog_read_buffer(struct nfslog_buf
*);
73 static void free_lrp(struct nfslog_lr
*);
74 static struct nfslog_lr
*remove_lrp_from_lb(struct nfslog_buf
*,
76 static void insert_lrp_to_lb(struct nfslog_buf
*,
78 static void nfslog_rewrite_bufheader(struct nfslog_buf
*);
81 * Treat the provided path name as an NFS log buffer file.
82 * Allocate a data structure for its handling and initialize it.
83 * *error contains the previous error condition encountered for
84 * this object. This value can be used to avoid printing the last
86 * It will set *error appropriately after processing.
89 nfslog_open_buf(char *bufpath
, int *error
)
91 struct nfslog_buf
*lbp
= NULL
;
93 if (bufpath
== NULL
) {
98 if ((lbp
= malloc(sizeof (struct nfslog_buf
))) == NULL
) {
102 bzero(lbp
, sizeof (struct nfslog_buf
));
104 if (nfslog_init_buf(bufpath
, lbp
, error
)) {
112 * Free the log buffer struct with all of its baggage and free the data struct
115 nfslog_close_buf(struct nfslog_buf
*lbp
, int close_quick
)
117 nfslog_free_buf(lbp
, close_quick
);
122 * Set up the log buffer struct; simple things are opening and locking
123 * the buffer file and then on to mmap()ing it for later use by the
124 * XDR decode path. Make sure to read the buffer header before
125 * returning so that we will be at the first true log record.
127 * *error contains the last error encountered on this object. It can
128 * be used to avoid reporting the same error endlessly. It is reset
129 * to the current error code on return.
132 nfslog_init_buf(char *bufpath
, struct nfslog_buf
*lbp
, int *error
)
135 int preverror
= *error
;
140 * set these values so that the free routine will know what to do
142 lbp
->mmap_addr
= (intptr_t)MAP_FAILED
;
143 lbp
->last_rec_id
= MAXINT
- 1;
144 lbp
->bh
.bh_length
= 0;
148 lbp
->last_record_offset
= 0;
150 lbp
->num_pr_queued
= 0;
152 lbp
->bufpath
= strdup(bufpath
);
153 if (lbp
->bufpath
== NULL
) {
155 if (preverror
!= *error
) {
156 syslog(LOG_ERR
, gettext("Cannot strdup '%s': %s"),
157 bufpath
, strerror(*error
));
159 nfslog_free_buf(lbp
, FALSE
);
163 if ((lbp
->fd
= open(bufpath
, O_RDWR
)) < 0) {
165 if (preverror
!= *error
) {
166 syslog(LOG_ERR
, gettext("Cannot open '%s': %s"),
167 bufpath
, strerror(*error
));
169 nfslog_free_buf(lbp
, FALSE
);
174 * Lock the entire buffer file to prevent conflicting access.
175 * We get a write lock because we want only 1 process to be
176 * generating records from it.
178 lbp
->fl
.l_type
= F_WRLCK
;
179 lbp
->fl
.l_whence
= SEEK_SET
; /* beginning of file */
180 lbp
->fl
.l_start
= (offset_t
)0;
181 lbp
->fl
.l_len
= 0; /* entire file */
184 if (fcntl(lbp
->fd
, F_SETLKW
, &lbp
->fl
) == -1) {
186 if (preverror
!= *error
) {
187 syslog(LOG_ERR
, gettext("Cannot lock (%s): %s"),
188 bufpath
, strerror(*error
));
190 nfslog_free_buf(lbp
, FALSE
);
194 if (fstat(lbp
->fd
, &sb
)) {
196 if (preverror
!= *error
) {
197 syslog(LOG_ERR
, gettext("Cannot stat (%s): %s"),
198 bufpath
, strerror(*error
));
200 nfslog_free_buf(lbp
, FALSE
);
203 lbp
->filesize
= sb
.st_size
;
205 lbp
->mmap_addr
= (intptr_t)mmap(NULL
, lbp
->filesize
, PROT_READ
|PROT_WRITE
,
206 MAP_SHARED
|MAP_NORESERVE
, lbp
->fd
, 0);
208 /* This is part of the duality of the use of either mmap()|read() */
209 if (lbp
->mmap_addr
== (intptr_t)MAP_FAILED
) {
212 lbp
->next_rec
= lbp
->mmap_addr
;
215 /* Read the header */
216 if ((lbp
->bh_lrp
= nfslog_read_buffer(lbp
)) == NULL
) {
218 if (preverror
!= *error
) {
219 syslog(LOG_ERR
, gettext(
220 "error in reading file '%s': %s"),
221 bufpath
, strerror(EIO
));
223 nfslog_free_buf(lbp
, FALSE
);
227 if (!xdr_nfslog_buffer_header(&lbp
->bh_lrp
->xdrs
, &lbp
->bh
)) {
229 if (preverror
!= *error
) {
230 syslog(LOG_ERR
, gettext(
231 "error in reading file '%s': %s"),
232 bufpath
, strerror(*error
));
234 nfslog_free_buf(lbp
, FALSE
);
239 * Set the pointer to the next record based on the buffer header.
240 * 'lbp->bh.bh_offset' contains the offset of where to begin
241 * processing relative to the buffer header.
243 lbp
->next_rec
+= lbp
->bh
.bh_offset
;
246 * If we are going to be using read() for file data, then we may
247 * have to adjust the current file pointer to take into account
248 * a starting point other than the beginning of the file.
249 * If mmap is being used, this is taken care of as a side effect of
250 * setting up the value of next_rec.
252 if (lbp
->mmap_addr
== (intptr_t)MAP_FAILED
&& lbp
->next_rec
!= 0) {
253 (void) lseek(lbp
->fd
, lbp
->next_rec
, SEEK_SET
);
254 /* This is a special case of setting the last_record_offset */
255 lbp
->last_record_offset
= lbp
->next_rec
;
257 lbp
->last_record_offset
= lbp
->next_rec
- lbp
->mmap_addr
;
264 * Free the nfslog buffer and its associated allocations
267 nfslog_free_buf(struct nfslog_buf
*lbp
, int close_quick
)
272 struct nfslog_lr
*lrp
, *lrp_next
;
273 struct processed_records
*prp
, *tprp
;
275 /* work to free the offset records and rewrite header */
277 if (lbp
->last_record_offset
== lbp
->prp
->start_offset
) {
279 /* adjust the offset for the entire buffer */
280 lbp
->last_record_offset
=
281 lbp
->prp
->start_offset
+ lbp
->prp
->len
;
283 nfslog_rewrite_bufheader(lbp
);
292 } while (lbp
->prp
!= prp
);
298 /* Take care of the queue log records first */
299 if (lbp
->lrps
!= NULL
) {
302 lrp_next
= lrp
->next
;
303 nfslog_free_logrecord(lrp
, FALSE
);
305 } while (lrp
!= lbp
->lrps
);
309 /* The buffer header was decoded and needs to be freed */
310 if (lbp
->bh
.bh_length
!= 0) {
311 buffer
= (lbp
->bh_lrp
->buffer
!= NULL
?
312 lbp
->bh_lrp
->buffer
: (caddr_t
)lbp
->mmap_addr
);
313 xdrmem_create(&xdrs
, buffer
, lbp
->bh_lrp
->recsize
, XDR_FREE
);
314 (void) xdr_nfslog_buffer_header(&xdrs
, &lbp
->bh
);
315 lbp
->bh
.bh_length
= 0;
318 /* get rid of the bufheader lrp */
319 if (lbp
->bh_lrp
!= NULL
) {
320 free_lrp(lbp
->bh_lrp
);
324 /* Clean up for mmap() usage */
325 if (lbp
->mmap_addr
!= (intptr_t)MAP_FAILED
) {
326 if (munmap((void *)lbp
->mmap_addr
, lbp
->filesize
)) {
328 syslog(LOG_ERR
, gettext("munmap failed: %s: %s"),
329 (lbp
->bufpath
!= NULL
? lbp
->bufpath
: ""),
332 lbp
->mmap_addr
= (intptr_t)MAP_FAILED
;
335 /* Finally close the buffer file */
337 lbp
->fl
.l_type
= F_UNLCK
;
338 if (fcntl(lbp
->fd
, F_SETLK
, &lbp
->fl
) == -1) {
341 gettext("Cannot unlock file %s: %s"),
342 (lbp
->bufpath
!= NULL
? lbp
->bufpath
: ""),
345 (void) close(lbp
->fd
);
352 * We are reading a record from the log buffer file. Since we are reading
353 * an XDR stream, we first have to read the first integer to determine
354 * how much to read in whole for this record. Our preference is to use
355 * mmap() but if failed initially we will be using read(). Need to be
356 * careful about proper initialization of the log record both from a field
357 * perspective and for XDR decoding.
359 static struct nfslog_lr
*
360 nfslog_read_buffer(struct nfslog_buf
*lbp
)
363 unsigned int record_size
;
364 struct nfslog_lr
*lrp
;
365 char *sizebuf
, tbuf
[16];
369 lrp
= (struct nfslog_lr
*)malloc(sizeof (*lrp
));
370 bzero(lrp
, sizeof (*lrp
));
372 /* Check to see if mmap worked */
373 if (lbp
->mmap_addr
== (intptr_t)MAP_FAILED
) {
375 * EOF or other failure; we don't try to recover, just return
377 if (read(lbp
->fd
, tbuf
, BYTES_PER_XDR_UNIT
) <= 0) {
383 /* EOF check for the mmap() case */
384 if (lbp
->filesize
<= lbp
->next_rec
- lbp
->mmap_addr
) {
388 sizebuf
= (char *)(uintptr_t)lbp
->next_rec
;
391 /* We have to XDR the first int so we know how much is in this record */
392 xdrmem_create(&xdrs
, sizebuf
, sizeof (unsigned int), XDR_DECODE
);
394 if (!xdr_u_int(&xdrs
, &record_size
)) {
399 lrp
->recsize
= record_size
;
400 next_rec
= lbp
->next_rec
+ lrp
->recsize
;
402 if (lbp
->mmap_addr
== (intptr_t)MAP_FAILED
) {
404 * Read() case - shouldn't be used very much.
405 * Note: The 'buffer' field is used later on
406 * to determine which method is being used mmap()|read()
408 if (lbp
->filesize
< next_rec
) {
409 /* partial record from buffer */
410 syslog(LOG_ERR
, gettext(
411 "Last partial record in work buffer %s "
412 "discarded\n"), lbp
->bufpath
);
417 if ((lrp
->buffer
= malloc(lrp
->recsize
)) == NULL
) {
421 bcopy(sizebuf
, lrp
->buffer
, BYTES_PER_XDR_UNIT
);
422 if (read(lbp
->fd
, &lrp
->buffer
[BYTES_PER_XDR_UNIT
],
423 lrp
->recsize
- BYTES_PER_XDR_UNIT
) <= 0) {
427 } else if (lbp
->filesize
< next_rec
- lbp
->mmap_addr
) {
428 /* partial record from buffer */
429 syslog(LOG_ERR
, gettext(
430 "Last partial record in work buffer %s "
431 "discarded\n"), lbp
->bufpath
);
437 /* other initializations */
438 lrp
->next
= lrp
->prev
= lrp
;
439 /* Keep track of the offset at which this record was read */
440 if (lbp
->mmap_addr
== (intptr_t)MAP_FAILED
)
441 lrp
->f_offset
= lbp
->next_rec
;
443 lrp
->f_offset
= lbp
->next_rec
- lbp
->mmap_addr
;
444 /* This is the true address of the record */
445 lrp
->record
= lbp
->next_rec
;
446 lrp
->xdrargs
= lrp
->xdrres
= NULL
;
449 /* Here is the logic for mmap() vs. read() */
450 buffer
= (lrp
->buffer
!= NULL
? lrp
->buffer
: (caddr_t
)lrp
->record
);
452 /* Setup for the 'real' XDR decode of the entire record */
453 xdrmem_create(&lrp
->xdrs
, buffer
, lrp
->recsize
, XDR_DECODE
);
455 /* calculate the offset for the next record */
456 lbp
->next_rec
= next_rec
;
462 * Simple removal of the log record from the log buffer queue.
463 * Make sure to manage the count of records queued.
465 static struct nfslog_lr
*
466 remove_lrp_from_lb(struct nfslog_buf
*lbp
, struct nfslog_lr
*lrp
)
468 if (lbp
->lrps
== lrp
) {
469 if (lbp
->lrps
== lbp
->lrps
->next
) {
472 lbp
->lrps
= lrp
->next
;
483 * Insert a log record struct on the log buffer struct. The log buffer
484 * has a pointer to the head of a queue of log records that have been
485 * read from the buffer file but have not been processed yet because
486 * the record id did not match the sequence desired for processing.
487 * The insertion must be in the 'correct'/sorted order which adds
488 * to the complexity of this function.
491 insert_lrp_to_lb(struct nfslog_buf
*lbp
, struct nfslog_lr
*lrp
)
493 int ins_rec_id
= lrp
->log_record
.re_header
.rh_rec_id
;
494 struct nfslog_lr
*curlrp
;
496 if (lbp
->lrps
== NULL
) {
501 * Does this lrp go before the first on the list?
502 * If so, do the insertion by hand since insque is not
503 * as flexible when queueing an element to the head of
506 if (ins_rec_id
< lbp
->lrps
->log_record
.re_header
.rh_rec_id
) {
507 lrp
->next
= lbp
->lrps
;
508 lrp
->prev
= lbp
->lrps
->prev
;
509 lbp
->lrps
->prev
->next
= lrp
;
510 lbp
->lrps
->prev
= lrp
;
514 * Search the queue for the correct insertion point.
515 * Be careful about the insque so that the record
516 * ends up in the right place.
521 curlrp
->next
->log_record
.re_header
.rh_rec_id
)
523 curlrp
= curlrp
->next
;
524 } while (curlrp
!= lbp
->lrps
);
525 if (curlrp
== lbp
->lrps
)
526 insque(lrp
, lbp
->lrps
->prev
);
531 /* always keep track of how many we have */
536 * We are rewriting the buffer header at the start of the log buffer
537 * for the sole purpose of resetting the bh_offset field. This is
538 * supposed to represent the progress that the nfslogd daemon has made
539 * in its processing of the log buffer file.
540 * 'lbp->last_record_offset' contains the absolute offset of the end
541 * of the last element processed. The on-disk buffer offset is relative
542 * to the buffer header, therefore we subtract the length of the buffer
543 * header from the absolute offset.
546 nfslog_rewrite_bufheader(struct nfslog_buf
*lbp
)
549 nfslog_buffer_header bh
;
550 /* size big enough for buffer header encode */
552 char buffer
[XBUFSIZE
];
556 * if version 1 buffer is large and the current offset cannot be
557 * represented, then don't update the offset in the buffer.
559 if (lbp
->bh
.bh_flags
& NFSLOG_BH_OFFSET_OVERFLOW
) {
560 /* No need to update the header - offset too big */
564 * build the buffer header from the original that was saved
565 * on initialization; note that the offset is taken from the
566 * last record processed (the last offset that represents
567 * all records processed without any holes in the processing)
572 * if version 1 buffer is large and the current offset cannot be
573 * represented in 32 bits, then save only the last valid offset
574 * in the buffer and mark the flags to indicate that.
576 if ((bh
.bh_version
> 1) ||
577 (lbp
->last_record_offset
- bh
.bh_length
< UINT32_MAX
)) {
578 bh
.bh_offset
= lbp
->last_record_offset
- bh
.bh_length
;
580 /* don't update the offset in the buffer */
581 bh
.bh_flags
|= NFSLOG_BH_OFFSET_OVERFLOW
;
582 lbp
->bh
.bh_flags
= bh
.bh_flags
;
583 syslog(LOG_ERR
, gettext(
584 "nfslog_rewrite_bufheader: %s: offset does not fit "
585 "in a 32 bit field\n"), lbp
->bufpath
);
588 xdrmem_create(&xdrs
, buffer
, XBUFSIZE
, XDR_ENCODE
);
590 if (!xdr_nfslog_buffer_header(&xdrs
, &bh
)) {
591 syslog(LOG_ERR
, gettext(
592 "error in re-writing buffer file %s header\n"),
597 wsize
= xdr_getpos(&xdrs
);
599 if (lbp
->mmap_addr
== (intptr_t)MAP_FAILED
) {
600 /* go to the beginning of the file */
601 (void) lseek(lbp
->fd
, 0, SEEK_SET
);
602 (void) write(lbp
->fd
, buffer
, wsize
);
603 (void) lseek(lbp
->fd
, lbp
->next_rec
, SEEK_SET
);
604 (void) fsync(lbp
->fd
);
606 bcopy(buffer
, (void *)lbp
->mmap_addr
, wsize
);
607 (void) msync((void *)lbp
->mmap_addr
, wsize
, MS_SYNC
);
612 * With the provided lrp, we will take and 'insert' the range that the
613 * record covered in the buffer file into a list of processed ranges
614 * for the buffer file. These ranges represent the records processed
615 * but not 'marked' in the buffer header as being processed.
616 * This insertion process is being done for two reasons. The first is that
617 * we do not want to pay the performance penalty of re-writing the buffer header
618 * for each record that we process. The second reason is that the records
619 * may be processed out of order because of the unique ids. This will occur
620 * if the kernel has written the records to the buffer file out of order.
621 * The read routine will 'sort' them as the records are read.
623 * We do not want to re-write the buffer header such that a record is
624 * represented and being processed when it has not been. In the case
625 * that the nfslogd daemon restarts processing and the buffer header
626 * has been re-written improperly, some records could be skipped.
627 * We will be taking the conservative approach and only writing buffer
628 * header offsets when the entire offset range has been processed.
631 nfslog_ins_last_rec_processed(struct nfslog_lr
*lrp
)
633 struct processed_records
*prp
, *tp
;
635 /* init the data struct as if it were the only one */
636 prp
= malloc(sizeof (*prp
));
637 prp
->next
= prp
->prev
= prp
;
638 prp
->start_offset
= lrp
->f_offset
;
639 prp
->len
= lrp
->recsize
;
642 /* always add since we know we are going to insert */
643 lrp
->lbp
->num_pr_queued
++;
645 /* Is this the first one? If so, take the easy way out */
646 if (lrp
->lbp
->prp
== NULL
) {
649 /* sort on insertion... */
652 if (prp
->start_offset
< tp
->start_offset
)
655 } while (tp
!= lrp
->lbp
->prp
);
656 /* insert where appropriate (before the one we found */
657 insque(prp
, tp
->prev
);
659 * special case where the insertion was done at the
662 if (tp
== lrp
->lbp
->prp
&& prp
->start_offset
< tp
->start_offset
)
666 * now that the entry is in place, we need to see if it can
667 * be combined with the previous or following entries.
668 * combination is done by adding to the length.
670 if (prp
->start_offset
==
671 (prp
->prev
->start_offset
+ prp
->prev
->len
)) {
675 tp
->num_recs
+= prp
->num_recs
;
679 if (prp
->next
->start_offset
==
680 (prp
->start_offset
+ prp
->len
)) {
681 prp
->len
+= prp
->next
->len
;
682 prp
->num_recs
+= prp
->next
->num_recs
;
689 if (lrp
->lbp
->num_pr_queued
> MAX_RECS_TO_DELAY
) {
691 if (lrp
->lbp
->last_record_offset
==
694 /* adjust the offset for the entire buffer */
695 lrp
->lbp
->last_record_offset
=
696 prp
->start_offset
+ prp
->len
;
698 nfslog_rewrite_bufheader(lrp
->lbp
);
706 lrp
->lbp
->num_pr_queued
-= prp
->num_recs
;
713 * nfslog_get_logrecord is responsible for retrieving the next log record
714 * from the buffer file. This would normally be very straightforward but there
715 * is the added complexity of attempting to order the requests coming out of
716 * the buffer file. The fundamental problems is that the kernel nfs logging
717 * functionality does not guarantee that the records were written to the file
718 * in the order that the NFS server processed them. This can cause a problem
719 * in the fh -> pathname mapping in the case were a lookup for a file comes
720 * later in the buffer file than other operations on the lookup's target.
721 * The fh mapping database will not have an entry and will therefore not
722 * be able to map the fh to a name.
724 * So to solve this problem, the kernel nfs logging code tags each record
725 * with a monotonically increasing id and is guaranteed to be allocated
726 * in the order that the requests were processed. Realize however that
727 * this processing guarantee is essentially for one thread on one client.
728 * This id mechanism does not order all requests since it is only the
729 * single client/single thread case that is most concerning to us here.
731 * This function will do the 'sorting' of the requests as they are
732 * read from the buffer file. The sorting needs to take into account
733 * that some ids may be missing (operations not logged but ids allocated)
734 * and that the id field will eventually wrap over MAXINT.
736 * Complexity to solve the fh -> pathname mapping issue.
739 nfslog_get_logrecord(struct nfslog_buf
*lbp
)
741 /* figure out what the next should be if the world were perfect */
742 unsigned int next_rec_id
= lbp
->last_rec_id
+ 1;
743 struct nfslog_lr
*lrp
= NULL
;
746 * First we check the queued records on the log buffer struct
747 * to see if the one we want is there. The records are sorted
748 * on the record id during the insertions to the queue so that
749 * this check is easy.
751 if (lbp
->lrps
!= NULL
) {
752 /* Does the first record match ? */
753 if (lbp
->lrps
->log_record
.re_header
.rh_rec_id
== next_rec_id
) {
754 lrp
= remove_lrp_from_lb(lbp
, lbp
->lrps
);
755 lbp
->last_rec_id
= lrp
->log_record
.re_header
.rh_rec_id
;
758 * Here we are checking for wrap of the record id
759 * since it is an unsigned in. The idea is that
760 * if there is a huge span between what we expect
761 * and what is queued then we need to flush/empty
762 * the queued records first.
765 lbp
->lrps
->log_record
.re_header
.rh_rec_id
&&
766 ((lbp
->lrps
->log_record
.re_header
.rh_rec_id
-
767 next_rec_id
) > (MAXINT
/ 2))) {
769 lrp
= remove_lrp_from_lb(lbp
, lbp
->lrps
);
771 lrp
->log_record
.re_header
.rh_rec_id
;
776 * So the first queued record didn't match (or there were no queued
777 * records to look at). Now we go to the buffer file looking for
778 * the expected log record based on its id. We loop looking for
779 * a matching records and save/queue the records that don't match.
780 * Note that we will queue a maximum number to handle the case
781 * of a missing record id or a queue that is very confused. We don't
782 * want to consume too much memory.
784 while (lrp
== NULL
) {
785 /* Have we queued too many for this buffer? */
786 if (lbp
->num_lrps
>= MAX_LRS_READ_AHEAD
) {
787 lrp
= remove_lrp_from_lb(lbp
, lbp
->lrps
);
788 lbp
->last_rec_id
= lrp
->log_record
.re_header
.rh_rec_id
;
792 * Get a record from the buffer file. If none are available,
793 * this is probably and EOF condition (could be a read error
794 * as well but that is masked. :-(). No records in the
795 * file means that we need to pull any queued records
796 * so that we don't miss any in the processing.
798 if ((lrp
= nfslog_read_buffer(lbp
)) == NULL
) {
799 if (lbp
->lrps
!= NULL
) {
800 lrp
= remove_lrp_from_lb(lbp
, lbp
->lrps
);
802 lrp
->log_record
.re_header
.rh_rec_id
;
804 return (NULL
); /* it was really and EOF */
808 * Just read a record from the buffer file and now we
809 * need to XDR the record header so that we can take
810 * a look at the record id.
812 if (!xdr_nfslog_request_record(&lrp
->xdrs
,
814 /* Free and return EOF/NULL on error */
815 nfslog_free_logrecord(lrp
, FALSE
);
819 * If the new record is less than or matches the
820 * expected record id, then we return this record
822 if (lrp
->log_record
.re_header
.rh_rec_id
<=
826 lrp
->log_record
.re_header
.rh_rec_id
;
829 * This is not the one we were looking
830 * for; queue it for later processing
831 * (queueing sorts on record id)
833 insert_lrp_to_lb(lbp
, lrp
);
842 * Free the log record provided.
843 * This is complex because the associated XDR streams also need to be freed
844 * since allocation could have occured during the DECODE phase. The record
845 * header, args and results need to be XDR_FREEd. The xdr funtions will
846 * be provided if a free needs to be done.
848 * Note that caller tells us if the record being freed was processed.
849 * If so, then the buffer header should be updated. Updating the buffer
850 * header keeps track of where the nfslogd daemon left off in its processing
851 * if it is unable to complete the entire file.
854 nfslog_free_logrecord(struct nfslog_lr
*lrp
, bool_t processing_complete
)
857 nfslog_request_record
*reqrec
;
859 if (processing_complete
) {
860 nfslog_ins_last_rec_processed(lrp
);
863 reqrec
= &lrp
->log_record
;
865 buffer
= (lrp
->buffer
!= NULL
? lrp
->buffer
: (caddr_t
)lrp
->record
);
867 xdrmem_create(&lrp
->xdrs
, buffer
, lrp
->recsize
, XDR_FREE
);
869 (void) xdr_nfslog_request_record(&lrp
->xdrs
, reqrec
);
871 if (lrp
->xdrargs
!= NULL
&& reqrec
->re_rpc_arg
)
872 (*lrp
->xdrargs
)(&lrp
->xdrs
, reqrec
->re_rpc_arg
);
874 free(reqrec
->re_rpc_arg
);
876 if (lrp
->xdrres
!= NULL
&& reqrec
->re_rpc_res
)
877 (*lrp
->xdrres
)(&lrp
->xdrs
, reqrec
->re_rpc_res
);
879 free(reqrec
->re_rpc_res
);
885 free_lrp(struct nfslog_lr
*lrp
)
892 * Utility function used elsewhere
895 nfslog_opaque_print_buf(void *buf
, int len
, char *outbuf
, int *outbufoffsetp
,
900 uchar_t
*u_buf
= (uchar_t
*)buf
;
901 int outbufoffset
= *outbufoffsetp
;
903 outbufoffset
+= sprintf(&outbuf
[outbufoffset
], " \"");
904 if (len
<= sizeof (int)) {
905 for (j
= 0; (j
< len
) && (outbufoffset
< maxoffset
);
907 outbufoffset
+= sprintf(&outbuf
[outbufoffset
],
911 /* More than 4 bytes, print with spaces in integer offsets */
912 j
= (int)((uintptr_t)buf
% sizeof (int));
915 i
= sizeof (int) - j
;
916 for (; (j
< sizeof (int)) && (outbufoffset
< maxoffset
);
918 outbufoffset
+= sprintf(&outbuf
[outbufoffset
],
922 ip
= (uint_t
*)u_buf
;
923 for (; ((i
+ sizeof (int)) <= len
) && (outbufoffset
< maxoffset
);
924 i
+= sizeof (int), ip
++) {
925 outbufoffset
+= sprintf(&outbuf
[outbufoffset
], " %08x", *ip
);
928 /* Last element not int */
929 u_buf
= (uchar_t
*)ip
;
930 if (i
> j
) /* not first element */
931 outbufoffset
+= sprintf(&outbuf
[outbufoffset
], " ");
932 for (; (i
< len
) && (outbufoffset
< maxoffset
); i
++, u_buf
++) {
933 outbufoffset
+= sprintf(&outbuf
[outbufoffset
],
937 if (outbufoffset
< maxoffset
)
938 outbufoffset
+= sprintf(&outbuf
[outbufoffset
], "\"");
939 *outbufoffsetp
= outbufoffset
;