17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 527242a7cSthurlow * Common Development and Distribution License (the "License"). 627242a7cSthurlow * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 223ccecb66SThomas Haynes * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. 237c478bd9Sstevel@tonic-gate */ 247c478bd9Sstevel@tonic-gate 257c478bd9Sstevel@tonic-gate #include <sys/cred.h> 267c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 277c478bd9Sstevel@tonic-gate #include <sys/debug.h> 287c478bd9Sstevel@tonic-gate #include <sys/systm.h> 297c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 307c478bd9Sstevel@tonic-gate #include <sys/disp.h> 317c478bd9Sstevel@tonic-gate #include <sys/atomic.h> 327c478bd9Sstevel@tonic-gate #include <rpc/types.h> 337c478bd9Sstevel@tonic-gate #include <nfs/nfs.h> 347c478bd9Sstevel@tonic-gate #include <nfs/nfssys.h> 357c478bd9Sstevel@tonic-gate #include <nfs/export.h> 367c478bd9Sstevel@tonic-gate #include <nfs/rnode.h> 377c478bd9Sstevel@tonic-gate #include <rpc/auth.h> 387c478bd9Sstevel@tonic-gate #include <rpc/svc.h> 397c478bd9Sstevel@tonic-gate #include <rpc/xdr.h> 407c478bd9Sstevel@tonic-gate #include <rpc/clnt.h> 417c478bd9Sstevel@tonic-gate #include <nfs/nfs_log.h> 427c478bd9Sstevel@tonic-gate 437c478bd9Sstevel@tonic-gate #define NUM_RECORDS_TO_WRITE 256 447c478bd9Sstevel@tonic-gate #define NUM_BYTES_TO_WRITE 65536 457c478bd9Sstevel@tonic-gate 467c478bd9Sstevel@tonic-gate extern krwlock_t exported_lock; 477c478bd9Sstevel@tonic-gate 487c478bd9Sstevel@tonic-gate static int nfslog_num_records_to_write = NUM_RECORDS_TO_WRITE; 497c478bd9Sstevel@tonic-gate static int nfslog_num_bytes_to_write = NUM_BYTES_TO_WRITE; 507c478bd9Sstevel@tonic-gate 517c478bd9Sstevel@tonic-gate /* 527c478bd9Sstevel@tonic-gate * This struct is used to 'hide' the details of managing the log 537c478bd9Sstevel@tonic-gate * records internally to the logging code. Allocation routines 547c478bd9Sstevel@tonic-gate * are used to obtain pieces of memory for XDR encoding. This struct 557c478bd9Sstevel@tonic-gate * is a 'header' to those areas and a opaque cookie is used to pass 567c478bd9Sstevel@tonic-gate * this data structure between the allocating function and the put 577c478bd9Sstevel@tonic-gate * function. 587c478bd9Sstevel@tonic-gate */ 597c478bd9Sstevel@tonic-gate struct lr_alloc { 607c478bd9Sstevel@tonic-gate struct lr_alloc *next; /* links for write queuing */ 617c478bd9Sstevel@tonic-gate struct lr_alloc *prev; 627c478bd9Sstevel@tonic-gate #define LR_ALLOC_NOFREE 0x1 /* not present, call free */ 637c478bd9Sstevel@tonic-gate int lr_flags; 647c478bd9Sstevel@tonic-gate caddr_t log_record; /* address to XDR encoding */ 657c478bd9Sstevel@tonic-gate size_t size; /* final size of encoding */ 667c478bd9Sstevel@tonic-gate struct kmem_cache *alloc_cache; /* keep track of cache ptr */ 677c478bd9Sstevel@tonic-gate struct exportinfo *exi; /* who are we related to? */ 687c478bd9Sstevel@tonic-gate struct log_buffer *lb; 697c478bd9Sstevel@tonic-gate }; 707c478bd9Sstevel@tonic-gate 717c478bd9Sstevel@tonic-gate struct flush_thread_params { 727c478bd9Sstevel@tonic-gate struct nfsl_flush_args tp_args; 737c478bd9Sstevel@tonic-gate int tp_error; 747c478bd9Sstevel@tonic-gate }; 757c478bd9Sstevel@tonic-gate 767c478bd9Sstevel@tonic-gate static int log_file_create(caddr_t, struct log_file **); 777c478bd9Sstevel@tonic-gate static void log_file_rele(struct log_file *); 787c478bd9Sstevel@tonic-gate static struct log_buffer *log_buffer_create(caddr_t); 797c478bd9Sstevel@tonic-gate static void log_buffer_rele(struct log_buffer *); 807c478bd9Sstevel@tonic-gate static int nfslog_record_append2all(struct lr_alloc *); 817c478bd9Sstevel@tonic-gate static int nfslog_logbuffer_rename(struct log_buffer *); 827c478bd9Sstevel@tonic-gate static void nfslog_logfile_wait(struct log_file *); 837c478bd9Sstevel@tonic-gate static int nfslog_logfile_rename(char *, char *); 847c478bd9Sstevel@tonic-gate static void nfslog_do_flush(struct flush_thread_params *); 857c478bd9Sstevel@tonic-gate static void create_buffer_header(caddr_t *, size_t *, size_t *); 867c478bd9Sstevel@tonic-gate 877c478bd9Sstevel@tonic-gate static int nfslog_write_logrecords(struct log_file *, struct lr_alloc *, int); 887c478bd9Sstevel@tonic-gate static void nfslog_free_logrecords(struct lr_alloc *); 897c478bd9Sstevel@tonic-gate static int nfslog_records_flush_to_disk(struct log_buffer *); 907c478bd9Sstevel@tonic-gate static int nfslog_records_flush_to_disk_nolock(struct log_buffer *); 917c478bd9Sstevel@tonic-gate 927c478bd9Sstevel@tonic-gate /* 937c478bd9Sstevel@tonic-gate * Read/Write lock that protects 'nfslog_buffer_list'. 947c478bd9Sstevel@tonic-gate * This lock must be held when searching or modifying 'nfslog_buffer_list'. 957c478bd9Sstevel@tonic-gate */ 967c478bd9Sstevel@tonic-gate static krwlock_t nfslog_buffer_list_lock; 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate /* 997c478bd9Sstevel@tonic-gate * The list of "log_buffer" structures. 1007c478bd9Sstevel@tonic-gate */ 1017c478bd9Sstevel@tonic-gate struct log_buffer *nfslog_buffer_list = NULL; 1027c478bd9Sstevel@tonic-gate 1037c478bd9Sstevel@tonic-gate 1047c478bd9Sstevel@tonic-gate #define LOG_BUFFER_HOLD(lbp) { \ 1057c478bd9Sstevel@tonic-gate mutex_enter(&(lbp)->lb_lock); \ 1067c478bd9Sstevel@tonic-gate (lbp)->lb_refcnt++; \ 1077c478bd9Sstevel@tonic-gate mutex_exit(&(lbp)->lb_lock); \ 1087c478bd9Sstevel@tonic-gate } 1097c478bd9Sstevel@tonic-gate 1107c478bd9Sstevel@tonic-gate #define LOG_FILE_HOLD(lfp) { \ 1117c478bd9Sstevel@tonic-gate mutex_enter(&(lfp)->lf_lock); \ 1127c478bd9Sstevel@tonic-gate (lfp)->lf_refcnt++; \ 1137c478bd9Sstevel@tonic-gate mutex_exit(&(lfp)->lf_lock); \ 1147c478bd9Sstevel@tonic-gate } 1157c478bd9Sstevel@tonic-gate 1167c478bd9Sstevel@tonic-gate #define LOG_FILE_RELE(lfp) { \ 1177c478bd9Sstevel@tonic-gate log_file_rele(lfp); \ 1187c478bd9Sstevel@tonic-gate } 1197c478bd9Sstevel@tonic-gate 1207c478bd9Sstevel@tonic-gate /* 1217c478bd9Sstevel@tonic-gate * These two macros are used to prep a logfile data structure and 1227c478bd9Sstevel@tonic-gate * associated file for writing data. Note that the lf_lock is 1237c478bd9Sstevel@tonic-gate * held as a result of the call to the first macro. This is used 1247c478bd9Sstevel@tonic-gate * for serialization correctness between the logbuffer struct and 1257c478bd9Sstevel@tonic-gate * the logfile struct. 1267c478bd9Sstevel@tonic-gate */ 1277c478bd9Sstevel@tonic-gate #define LOG_FILE_LOCK_TO_WRITE(lfp) { \ 1287c478bd9Sstevel@tonic-gate mutex_enter(&(lfp)->lf_lock); \ 1297c478bd9Sstevel@tonic-gate (lfp)->lf_refcnt++; \ 1307c478bd9Sstevel@tonic-gate (lfp)->lf_writers++; \ 1317c478bd9Sstevel@tonic-gate } 1327c478bd9Sstevel@tonic-gate 1337c478bd9Sstevel@tonic-gate #define LOG_FILE_UNLOCK_FROM_WRITE(lfp) { \ 1347c478bd9Sstevel@tonic-gate (lfp)->lf_writers--; \ 1357c478bd9Sstevel@tonic-gate if ((lfp)->lf_writers == 0 && ((lfp)->lf_flags & L_WAITING)) { \ 1367c478bd9Sstevel@tonic-gate (lfp)->lf_flags &= ~L_WAITING; \ 1377c478bd9Sstevel@tonic-gate cv_broadcast(&(lfp)->lf_cv_waiters); \ 1387c478bd9Sstevel@tonic-gate } \ 1397c478bd9Sstevel@tonic-gate mutex_exit(&(lfp)->lf_lock); \ 1407c478bd9Sstevel@tonic-gate log_file_rele(lfp); \ 1417c478bd9Sstevel@tonic-gate } 1427c478bd9Sstevel@tonic-gate 1437c478bd9Sstevel@tonic-gate int rfsl_log_buffer = 0; 1447c478bd9Sstevel@tonic-gate static int rfsl_log_file = 0; 1457c478bd9Sstevel@tonic-gate 1467c478bd9Sstevel@tonic-gate /* This array is used for memory allocation of record encoding spaces */ 1477c478bd9Sstevel@tonic-gate static struct { 1487c478bd9Sstevel@tonic-gate int size; 1497c478bd9Sstevel@tonic-gate struct kmem_cache *mem_cache; 1507c478bd9Sstevel@tonic-gate char *cache_name; 1517c478bd9Sstevel@tonic-gate } nfslog_mem_alloc[] = { 1527c478bd9Sstevel@tonic-gate #define SMALL_INDX 0 1537c478bd9Sstevel@tonic-gate { NFSLOG_SMALL_RECORD_SIZE - sizeof (struct lr_alloc), 1547c478bd9Sstevel@tonic-gate NULL, NFSLOG_SMALL_REC_NAME }, 1557c478bd9Sstevel@tonic-gate #define MEDIUM_INDX 1 1567c478bd9Sstevel@tonic-gate { NFSLOG_MEDIUM_RECORD_SIZE - sizeof (struct lr_alloc), 1577c478bd9Sstevel@tonic-gate NULL, NFSLOG_MEDIUM_REC_NAME }, 1587c478bd9Sstevel@tonic-gate #define LARGE_INDX 2 1597c478bd9Sstevel@tonic-gate { NFSLOG_LARGE_RECORD_SIZE - sizeof (struct lr_alloc), 1607c478bd9Sstevel@tonic-gate NULL, NFSLOG_LARGE_REC_NAME }, 1617c478bd9Sstevel@tonic-gate { (-1), NULL } 1627c478bd9Sstevel@tonic-gate }; 1637c478bd9Sstevel@tonic-gate 1647c478bd9Sstevel@tonic-gate /* Used to calculate the 'real' allocation size */ 1657c478bd9Sstevel@tonic-gate #define ALLOC_SIZE(index) \ 1667c478bd9Sstevel@tonic-gate (nfslog_mem_alloc[index].size + sizeof (struct lr_alloc)) 1677c478bd9Sstevel@tonic-gate 1687c478bd9Sstevel@tonic-gate /* 1697c478bd9Sstevel@tonic-gate * Initialize logging data buffer cache 1707c478bd9Sstevel@tonic-gate */ 1717c478bd9Sstevel@tonic-gate void 1727c478bd9Sstevel@tonic-gate nfslog_init() 1737c478bd9Sstevel@tonic-gate { 1747c478bd9Sstevel@tonic-gate int indx; 1757c478bd9Sstevel@tonic-gate 1767c478bd9Sstevel@tonic-gate rw_init(&nfslog_buffer_list_lock, NULL, RW_DEFAULT, NULL); 1777c478bd9Sstevel@tonic-gate 1787c478bd9Sstevel@tonic-gate /* 1797c478bd9Sstevel@tonic-gate * Initialize the kmem caches for encoding 1807c478bd9Sstevel@tonic-gate */ 1817c478bd9Sstevel@tonic-gate for (indx = 0; nfslog_mem_alloc[indx].size != (-1); indx++) { 1827c478bd9Sstevel@tonic-gate nfslog_mem_alloc[indx].mem_cache = 1837c478bd9Sstevel@tonic-gate kmem_cache_create(nfslog_mem_alloc[indx].cache_name, 1849d39bb88Sbatschul ALLOC_SIZE(indx), 0, NULL, NULL, NULL, NULL, NULL, 0); 1857c478bd9Sstevel@tonic-gate } 1867c478bd9Sstevel@tonic-gate } 1877c478bd9Sstevel@tonic-gate 1887c478bd9Sstevel@tonic-gate /* 1897c478bd9Sstevel@tonic-gate * Sets up the necessary log file and related buffers to enable logging 1907c478bd9Sstevel@tonic-gate * on the given export point. 1917c478bd9Sstevel@tonic-gate * Returns 0 on success, non-zero on failure. 1927c478bd9Sstevel@tonic-gate */ 1937c478bd9Sstevel@tonic-gate int 1947c478bd9Sstevel@tonic-gate nfslog_setup(struct exportinfo *exi) 1957c478bd9Sstevel@tonic-gate { 1967c478bd9Sstevel@tonic-gate struct exportdata *kex; 1977c478bd9Sstevel@tonic-gate struct log_buffer *lbp; 1987c478bd9Sstevel@tonic-gate struct log_buffer *nlbp; 1997c478bd9Sstevel@tonic-gate 2007c478bd9Sstevel@tonic-gate kex = &exi->exi_export; 2017c478bd9Sstevel@tonic-gate ASSERT(kex->ex_flags & EX_LOG); 2027c478bd9Sstevel@tonic-gate 2037c478bd9Sstevel@tonic-gate /* 2047c478bd9Sstevel@tonic-gate * Logging is enabled for the new export point, check 2057c478bd9Sstevel@tonic-gate * the existing log_buffer structures to see if the 2067c478bd9Sstevel@tonic-gate * desired buffer has already been opened. If so, point 2077c478bd9Sstevel@tonic-gate * the new exportinfo's exi_logbuffer to the existing 2087c478bd9Sstevel@tonic-gate * one. 2097c478bd9Sstevel@tonic-gate */ 2107c478bd9Sstevel@tonic-gate rw_enter(&nfslog_buffer_list_lock, RW_READER); 2117c478bd9Sstevel@tonic-gate for (lbp = nfslog_buffer_list; lbp != NULL; lbp = lbp->lb_next) { 2127c478bd9Sstevel@tonic-gate LOGGING_DPRINT((10, 2137c478bd9Sstevel@tonic-gate "searching for buffer... found log_buffer '%s'\n", 2147c478bd9Sstevel@tonic-gate lbp->lb_path)); 2157c478bd9Sstevel@tonic-gate if (strcmp(lbp->lb_path, kex->ex_log_buffer) == 0) { 2167c478bd9Sstevel@tonic-gate /* Found our match. Ref it and return */ 2177c478bd9Sstevel@tonic-gate LOG_BUFFER_HOLD(lbp); 2187c478bd9Sstevel@tonic-gate exi->exi_logbuffer = lbp; 2197c478bd9Sstevel@tonic-gate LOGGING_DPRINT((10, "\tfound log_buffer for '%s'\n", 2207c478bd9Sstevel@tonic-gate kex->ex_log_buffer)); 2217c478bd9Sstevel@tonic-gate rw_exit(&nfslog_buffer_list_lock); 2227c478bd9Sstevel@tonic-gate return (0); 2237c478bd9Sstevel@tonic-gate } 2247c478bd9Sstevel@tonic-gate } 2257c478bd9Sstevel@tonic-gate rw_exit(&nfslog_buffer_list_lock); 2267c478bd9Sstevel@tonic-gate 2277c478bd9Sstevel@tonic-gate /* 2287c478bd9Sstevel@tonic-gate * New buffer needed, allocate it. 2297c478bd9Sstevel@tonic-gate * The buffer list lock has been dropped so we will need to search 2307c478bd9Sstevel@tonic-gate * the list again to ensure that another thread has not added 2317c478bd9Sstevel@tonic-gate * a matching buffer. 2327c478bd9Sstevel@tonic-gate */ 2337c478bd9Sstevel@tonic-gate if ((nlbp = log_buffer_create(kex->ex_log_buffer)) == NULL) { 2347c478bd9Sstevel@tonic-gate /* 2357c478bd9Sstevel@tonic-gate * Failed the buffer creation for some reason so we 2367c478bd9Sstevel@tonic-gate * will need to return. 2377c478bd9Sstevel@tonic-gate */ 2387c478bd9Sstevel@tonic-gate return (EIO); 2397c478bd9Sstevel@tonic-gate } 2407c478bd9Sstevel@tonic-gate 2417c478bd9Sstevel@tonic-gate rw_enter(&nfslog_buffer_list_lock, RW_WRITER); 2427c478bd9Sstevel@tonic-gate for (lbp = nfslog_buffer_list; lbp != NULL; 2437c478bd9Sstevel@tonic-gate lbp = lbp->lb_next) { 2447c478bd9Sstevel@tonic-gate if (strcmp(lbp->lb_path, kex->ex_log_buffer) == 0) { 2457c478bd9Sstevel@tonic-gate /* 2467c478bd9Sstevel@tonic-gate * A log_buffer already exists for the 2477c478bd9Sstevel@tonic-gate * indicated buffer, use it instead. 2487c478bd9Sstevel@tonic-gate */ 2497c478bd9Sstevel@tonic-gate LOG_BUFFER_HOLD(lbp); 2507c478bd9Sstevel@tonic-gate 2517c478bd9Sstevel@tonic-gate exi->exi_logbuffer = lbp; 2527c478bd9Sstevel@tonic-gate 2539d39bb88Sbatschul LOGGING_DPRINT((10, "found log_buffer for '%s' " 2549d39bb88Sbatschul "after allocation\n", kex->ex_log_buffer)); 2557c478bd9Sstevel@tonic-gate 2567c478bd9Sstevel@tonic-gate rw_exit(&nfslog_buffer_list_lock); 2577c478bd9Sstevel@tonic-gate 2587c478bd9Sstevel@tonic-gate log_buffer_rele(nlbp); 2597c478bd9Sstevel@tonic-gate 2607c478bd9Sstevel@tonic-gate return (0); 2617c478bd9Sstevel@tonic-gate } 2627c478bd9Sstevel@tonic-gate } 2637c478bd9Sstevel@tonic-gate /* 2647c478bd9Sstevel@tonic-gate * Didn't find an existing log_buffer for this buffer, 2657c478bd9Sstevel@tonic-gate * use the the newly created one, and add to list. We 2667c478bd9Sstevel@tonic-gate * increment the reference count because the node is 2677c478bd9Sstevel@tonic-gate * entered into the global list. 2687c478bd9Sstevel@tonic-gate */ 269903a11ebSrh87107 LOGGING_DPRINT((10, "exportfs: adding nlbp=%p to list\n", 270903a11ebSrh87107 (void *)nlbp)); 2717c478bd9Sstevel@tonic-gate 2727c478bd9Sstevel@tonic-gate nlbp->lb_next = nfslog_buffer_list; 2737c478bd9Sstevel@tonic-gate nfslog_buffer_list = nlbp; 2747c478bd9Sstevel@tonic-gate 2757c478bd9Sstevel@tonic-gate LOG_BUFFER_HOLD(nlbp); /* hold is for export entry */ 2767c478bd9Sstevel@tonic-gate exi->exi_logbuffer = nlbp; 2777c478bd9Sstevel@tonic-gate 2787c478bd9Sstevel@tonic-gate rw_exit(&nfslog_buffer_list_lock); 2797c478bd9Sstevel@tonic-gate 2807c478bd9Sstevel@tonic-gate return (0); 2817c478bd9Sstevel@tonic-gate } 2827c478bd9Sstevel@tonic-gate 2837c478bd9Sstevel@tonic-gate /* 2847c478bd9Sstevel@tonic-gate * Disables logging for the given export point. 2857c478bd9Sstevel@tonic-gate */ 2867c478bd9Sstevel@tonic-gate void 2877c478bd9Sstevel@tonic-gate nfslog_disable(struct exportinfo *exi) 2887c478bd9Sstevel@tonic-gate { 2897c478bd9Sstevel@tonic-gate log_buffer_rele(exi->exi_logbuffer); 2907c478bd9Sstevel@tonic-gate } 2917c478bd9Sstevel@tonic-gate 2927c478bd9Sstevel@tonic-gate /* 2937c478bd9Sstevel@tonic-gate * Creates the corresponding log_buffer and log_file structures 2947c478bd9Sstevel@tonic-gate * for the the buffer named 'name'. 2957c478bd9Sstevel@tonic-gate * Returns a pointer to the log_buffer structure with reference one. 2967c478bd9Sstevel@tonic-gate */ 2977c478bd9Sstevel@tonic-gate static struct log_buffer * 2987c478bd9Sstevel@tonic-gate log_buffer_create(caddr_t name) 2997c478bd9Sstevel@tonic-gate { 3007c478bd9Sstevel@tonic-gate struct log_buffer *buffer; 3017c478bd9Sstevel@tonic-gate struct log_file *logfile; 3027c478bd9Sstevel@tonic-gate int namelen = strlen(name); 3037c478bd9Sstevel@tonic-gate 3047c478bd9Sstevel@tonic-gate LOGGING_DPRINT((10, "log_buffer_create: %s\n", name)); 3057c478bd9Sstevel@tonic-gate if (log_file_create(name, &logfile)) 3067c478bd9Sstevel@tonic-gate return (NULL); 3077c478bd9Sstevel@tonic-gate 3087c478bd9Sstevel@tonic-gate buffer = (struct log_buffer *)kmem_alloc(sizeof (*buffer), KM_SLEEP); 3097c478bd9Sstevel@tonic-gate buffer->lb_refcnt = 1; 3107c478bd9Sstevel@tonic-gate buffer->lb_rec_id = 0; 3117c478bd9Sstevel@tonic-gate buffer->lb_path = (caddr_t)kmem_alloc(namelen + 1, KM_SLEEP); 3127c478bd9Sstevel@tonic-gate bcopy(name, buffer->lb_path, namelen + 1); 3137c478bd9Sstevel@tonic-gate buffer->lb_logfile = logfile; 3147c478bd9Sstevel@tonic-gate buffer->lb_records = NULL; 3157c478bd9Sstevel@tonic-gate buffer->lb_num_recs = 0; 3167c478bd9Sstevel@tonic-gate buffer->lb_size_queued = 0; 3177c478bd9Sstevel@tonic-gate mutex_init(&buffer->lb_lock, NULL, MUTEX_DEFAULT, NULL); 3187c478bd9Sstevel@tonic-gate rfsl_log_buffer++; 3197c478bd9Sstevel@tonic-gate 3207c478bd9Sstevel@tonic-gate return (buffer); 3217c478bd9Sstevel@tonic-gate } 3227c478bd9Sstevel@tonic-gate 3237c478bd9Sstevel@tonic-gate /* 3247c478bd9Sstevel@tonic-gate * Release a log_buffer structure 3257c478bd9Sstevel@tonic-gate */ 3267c478bd9Sstevel@tonic-gate static void 3277c478bd9Sstevel@tonic-gate log_buffer_rele(struct log_buffer *lbp) 3287c478bd9Sstevel@tonic-gate { 3297c478bd9Sstevel@tonic-gate int len; 3307c478bd9Sstevel@tonic-gate 3317c478bd9Sstevel@tonic-gate mutex_enter(&lbp->lb_lock); 3327c478bd9Sstevel@tonic-gate if (--lbp->lb_refcnt > 1) { 3337c478bd9Sstevel@tonic-gate mutex_exit(&lbp->lb_lock); 3347c478bd9Sstevel@tonic-gate return; 3357c478bd9Sstevel@tonic-gate } 3367c478bd9Sstevel@tonic-gate 3377c478bd9Sstevel@tonic-gate if (lbp->lb_refcnt < 0) { 3387c478bd9Sstevel@tonic-gate panic("log_rele: log_buffer refcnt < 0"); 3397c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 3407c478bd9Sstevel@tonic-gate } 3417c478bd9Sstevel@tonic-gate 3427c478bd9Sstevel@tonic-gate /* 3437c478bd9Sstevel@tonic-gate * Need to drop the lb_lock before acquiring the 3447c478bd9Sstevel@tonic-gate * nfslog_buffer_list_lock. To avoid double free we need 3457c478bd9Sstevel@tonic-gate * to hold an additional reference to the log buffer. 3467c478bd9Sstevel@tonic-gate * This will ensure that no two threads will simultaneously 3477c478bd9Sstevel@tonic-gate * be trying to free the same log buffer. 3487c478bd9Sstevel@tonic-gate */ 3497c478bd9Sstevel@tonic-gate 3507c478bd9Sstevel@tonic-gate if (lbp->lb_refcnt == 1) { 3517c478bd9Sstevel@tonic-gate 3527c478bd9Sstevel@tonic-gate /* 3537c478bd9Sstevel@tonic-gate * If the ref count is 1, then the last 3547c478bd9Sstevel@tonic-gate * unshare/reference has been given up and we need to 3557c478bd9Sstevel@tonic-gate * clean up the buffer and remove it from the buffer 3567c478bd9Sstevel@tonic-gate * list. 3577c478bd9Sstevel@tonic-gate */ 3587c478bd9Sstevel@tonic-gate LOGGING_DPRINT((10, 359903a11ebSrh87107 "log_buffer_rele lbp=%p disconnecting\n", (void *)lbp)); 3607c478bd9Sstevel@tonic-gate /* 3617c478bd9Sstevel@tonic-gate * Hold additional reference before dropping the lb_lock 3627c478bd9Sstevel@tonic-gate */ 3637c478bd9Sstevel@tonic-gate 3647c478bd9Sstevel@tonic-gate lbp->lb_refcnt++; 3657c478bd9Sstevel@tonic-gate mutex_exit(&lbp->lb_lock); 3667c478bd9Sstevel@tonic-gate 3677c478bd9Sstevel@tonic-gate /* 3687c478bd9Sstevel@tonic-gate * Make sure that all of the buffered records are written. 3697c478bd9Sstevel@tonic-gate * Don't bother checking the write return value since there 3707c478bd9Sstevel@tonic-gate * isn't much we can do at this point. 3717c478bd9Sstevel@tonic-gate */ 3727c478bd9Sstevel@tonic-gate (void) nfslog_records_flush_to_disk(lbp); 3737c478bd9Sstevel@tonic-gate 3747c478bd9Sstevel@tonic-gate rw_enter(&nfslog_buffer_list_lock, RW_WRITER); 3757c478bd9Sstevel@tonic-gate mutex_enter(&lbp->lb_lock); 3767c478bd9Sstevel@tonic-gate /* 3777c478bd9Sstevel@tonic-gate * Drop the reference count held above. 3787c478bd9Sstevel@tonic-gate * If the ref count is still > 1 then someone has 3797c478bd9Sstevel@tonic-gate * stepped in to use this log buffer. unlock and return. 3807c478bd9Sstevel@tonic-gate */ 3817c478bd9Sstevel@tonic-gate if (--lbp->lb_refcnt > 1) { 3827c478bd9Sstevel@tonic-gate mutex_exit(&lbp->lb_lock); 3837c478bd9Sstevel@tonic-gate rw_exit(&nfslog_buffer_list_lock); 3847c478bd9Sstevel@tonic-gate return; 3857c478bd9Sstevel@tonic-gate } 3867c478bd9Sstevel@tonic-gate 3877c478bd9Sstevel@tonic-gate if (lbp == nfslog_buffer_list) { 3887c478bd9Sstevel@tonic-gate nfslog_buffer_list = lbp->lb_next; 3897c478bd9Sstevel@tonic-gate } else { 3907c478bd9Sstevel@tonic-gate struct log_buffer *tlbp; 3917c478bd9Sstevel@tonic-gate 3927c478bd9Sstevel@tonic-gate /* Drop the log_buffer from the master list */ 3937c478bd9Sstevel@tonic-gate for (tlbp = nfslog_buffer_list; tlbp->lb_next != NULL; 3947c478bd9Sstevel@tonic-gate tlbp = tlbp->lb_next) { 3957c478bd9Sstevel@tonic-gate if (tlbp->lb_next == lbp) { 3967c478bd9Sstevel@tonic-gate tlbp->lb_next = lbp->lb_next; 3977c478bd9Sstevel@tonic-gate break; 3987c478bd9Sstevel@tonic-gate } 3997c478bd9Sstevel@tonic-gate } 4007c478bd9Sstevel@tonic-gate } 4017c478bd9Sstevel@tonic-gate 4027c478bd9Sstevel@tonic-gate mutex_exit(&lbp->lb_lock); 4037c478bd9Sstevel@tonic-gate rw_exit(&nfslog_buffer_list_lock); 4047c478bd9Sstevel@tonic-gate } 4057c478bd9Sstevel@tonic-gate /* 4067c478bd9Sstevel@tonic-gate * ref count zero; finish clean up. 4077c478bd9Sstevel@tonic-gate */ 408903a11ebSrh87107 LOGGING_DPRINT((10, "log_buffer_rele lbp=%p freeing\n", (void *)lbp)); 4097c478bd9Sstevel@tonic-gate 4107c478bd9Sstevel@tonic-gate log_file_rele(lbp->lb_logfile); 4117c478bd9Sstevel@tonic-gate len = strlen(lbp->lb_path) + 1; 4127c478bd9Sstevel@tonic-gate kmem_free(lbp->lb_path, len); 4137c478bd9Sstevel@tonic-gate kmem_free(lbp, sizeof (*lbp)); 4147c478bd9Sstevel@tonic-gate rfsl_log_buffer--; 4157c478bd9Sstevel@tonic-gate } 4167c478bd9Sstevel@tonic-gate 4177c478bd9Sstevel@tonic-gate /* 4187c478bd9Sstevel@tonic-gate * Creates the corresponding log_file structure for the buffer 4197c478bd9Sstevel@tonic-gate * named 'log_file_name'. 4207c478bd9Sstevel@tonic-gate * 'log_file_name' is created by concatenating 'origname' and LOG_INPROG_STRING. 4217c478bd9Sstevel@tonic-gate * 'logfile' is set to be the log_file structure with reference one. 4227c478bd9Sstevel@tonic-gate */ 4237c478bd9Sstevel@tonic-gate static int 4247c478bd9Sstevel@tonic-gate log_file_create(caddr_t origname, struct log_file **lfpp) 4257c478bd9Sstevel@tonic-gate { 4267c478bd9Sstevel@tonic-gate vnode_t *vp = NULL; 4277c478bd9Sstevel@tonic-gate char *name; 4287c478bd9Sstevel@tonic-gate int namelen; 4297c478bd9Sstevel@tonic-gate int error; 4307c478bd9Sstevel@tonic-gate struct log_file *logfile = NULL; 4317c478bd9Sstevel@tonic-gate vattr_t va; 4327c478bd9Sstevel@tonic-gate caddr_t loghdr = NULL; 4337c478bd9Sstevel@tonic-gate size_t loghdr_len = 0; 4347c478bd9Sstevel@tonic-gate size_t loghdr_free = 0; 4357c478bd9Sstevel@tonic-gate 4367c478bd9Sstevel@tonic-gate namelen = strlen(origname) + strlen(LOG_INPROG_STRING); 4377c478bd9Sstevel@tonic-gate name = (caddr_t)kmem_alloc(namelen + 1, KM_SLEEP); 4387c478bd9Sstevel@tonic-gate (void) sprintf(name, "%s%s", origname, LOG_INPROG_STRING); 4397c478bd9Sstevel@tonic-gate 4407c478bd9Sstevel@tonic-gate LOGGING_DPRINT((3, "log_file_create: %s\n", name)); 4417c478bd9Sstevel@tonic-gate if (error = vn_open(name, UIO_SYSSPACE, FCREAT|FWRITE|FOFFMAX, 4427c478bd9Sstevel@tonic-gate LOG_MODE, &vp, CRCREAT, 0)) { 4437c478bd9Sstevel@tonic-gate nfs_cmn_err(error, CE_WARN, 4447c478bd9Sstevel@tonic-gate "log_file_create: Can not open %s - error %m", name); 4457c478bd9Sstevel@tonic-gate goto out; 4467c478bd9Sstevel@tonic-gate } 4477c478bd9Sstevel@tonic-gate LOGGING_DPRINT((3, "log_file_create: %s vp=%p v_count=%d\n", 448903a11ebSrh87107 name, (void *)vp, vp->v_count)); 4497c478bd9Sstevel@tonic-gate 4507c478bd9Sstevel@tonic-gate logfile = (struct log_file *)kmem_zalloc(sizeof (*logfile), KM_SLEEP); 4517c478bd9Sstevel@tonic-gate logfile->lf_path = name; 4527c478bd9Sstevel@tonic-gate /* 4537c478bd9Sstevel@tonic-gate * No need to bump the vnode reference count since it is set 4547c478bd9Sstevel@tonic-gate * to one by vn_open(). 4557c478bd9Sstevel@tonic-gate */ 4567c478bd9Sstevel@tonic-gate logfile->lf_vp = vp; 4577c478bd9Sstevel@tonic-gate logfile->lf_refcnt = 1; 4587c478bd9Sstevel@tonic-gate mutex_init(&logfile->lf_lock, NULL, MUTEX_DEFAULT, NULL); 4597c478bd9Sstevel@tonic-gate rfsl_log_file++; 4607c478bd9Sstevel@tonic-gate 4617c478bd9Sstevel@tonic-gate va.va_mask = AT_SIZE; 462da6c28aaSamw error = VOP_GETATTR(vp, &va, 0, CRED(), NULL); 4637c478bd9Sstevel@tonic-gate if (error) { 4647c478bd9Sstevel@tonic-gate nfs_cmn_err(error, CE_WARN, 4659d39bb88Sbatschul "log_file_create: Can not stat %s - error = %m", name); 4667c478bd9Sstevel@tonic-gate goto out; 4677c478bd9Sstevel@tonic-gate } 4687c478bd9Sstevel@tonic-gate 4697c478bd9Sstevel@tonic-gate if (va.va_size == 0) { 4707c478bd9Sstevel@tonic-gate struct lr_alloc lr; 4717c478bd9Sstevel@tonic-gate 4727c478bd9Sstevel@tonic-gate /* 4737c478bd9Sstevel@tonic-gate * Write Header. 4747c478bd9Sstevel@tonic-gate */ 4757c478bd9Sstevel@tonic-gate create_buffer_header(&loghdr, &loghdr_len, &loghdr_free); 4767c478bd9Sstevel@tonic-gate /* 4777c478bd9Sstevel@tonic-gate * Dummy up a lr_alloc struct for the write 4787c478bd9Sstevel@tonic-gate */ 4797c478bd9Sstevel@tonic-gate lr.next = lr.prev = &lr; 4807c478bd9Sstevel@tonic-gate lr.lr_flags = 0; 4817c478bd9Sstevel@tonic-gate lr.log_record = loghdr; 4827c478bd9Sstevel@tonic-gate lr.size = loghdr_len; 4837c478bd9Sstevel@tonic-gate lr.alloc_cache = NULL; 4847c478bd9Sstevel@tonic-gate lr.exi = NULL; 4857c478bd9Sstevel@tonic-gate lr.lb = NULL; 4867c478bd9Sstevel@tonic-gate 4877c478bd9Sstevel@tonic-gate mutex_enter(&logfile->lf_lock); 4887c478bd9Sstevel@tonic-gate 4897c478bd9Sstevel@tonic-gate error = nfslog_write_logrecords(logfile, &lr, 1); 4907c478bd9Sstevel@tonic-gate 4917c478bd9Sstevel@tonic-gate mutex_exit(&logfile->lf_lock); 4927c478bd9Sstevel@tonic-gate 4937c478bd9Sstevel@tonic-gate if (error != 0) { 4947c478bd9Sstevel@tonic-gate nfs_cmn_err(error, CE_WARN, 4957c478bd9Sstevel@tonic-gate "log_file_create: Can not write header " 4967c478bd9Sstevel@tonic-gate "on %s - error = %m", name); 4977c478bd9Sstevel@tonic-gate goto out; 4987c478bd9Sstevel@tonic-gate } 4997c478bd9Sstevel@tonic-gate } 5007c478bd9Sstevel@tonic-gate *lfpp = logfile; 5017c478bd9Sstevel@tonic-gate 5027c478bd9Sstevel@tonic-gate if (loghdr != NULL) 5037c478bd9Sstevel@tonic-gate kmem_free(loghdr, loghdr_free); 5047c478bd9Sstevel@tonic-gate 5057c478bd9Sstevel@tonic-gate return (0); 5067c478bd9Sstevel@tonic-gate 5077c478bd9Sstevel@tonic-gate out: 5087c478bd9Sstevel@tonic-gate if (vp != NULL) { 5097c478bd9Sstevel@tonic-gate int error1; 5107c478bd9Sstevel@tonic-gate error1 = VOP_CLOSE(vp, FCREAT|FWRITE|FOFFMAX, 1, (offset_t)0, 511da6c28aaSamw CRED(), NULL); 5127c478bd9Sstevel@tonic-gate if (error1) { 5137c478bd9Sstevel@tonic-gate nfs_cmn_err(error1, CE_WARN, 5147c478bd9Sstevel@tonic-gate "log_file_create: Can not close %s - " 5157c478bd9Sstevel@tonic-gate "error = %m", name); 5167c478bd9Sstevel@tonic-gate } 5177c478bd9Sstevel@tonic-gate VN_RELE(vp); 5187c478bd9Sstevel@tonic-gate } 5197c478bd9Sstevel@tonic-gate 5207c478bd9Sstevel@tonic-gate kmem_free(name, namelen + 1); 5217c478bd9Sstevel@tonic-gate if (logfile != NULL) { 5227c478bd9Sstevel@tonic-gate mutex_destroy(&logfile->lf_lock); 5237c478bd9Sstevel@tonic-gate kmem_free(logfile, sizeof (*logfile)); 5247c478bd9Sstevel@tonic-gate rfsl_log_file--; 5257c478bd9Sstevel@tonic-gate } 5267c478bd9Sstevel@tonic-gate if (loghdr != NULL) 5277c478bd9Sstevel@tonic-gate kmem_free(loghdr, loghdr_free); 5287c478bd9Sstevel@tonic-gate 5297c478bd9Sstevel@tonic-gate return (error); 5307c478bd9Sstevel@tonic-gate } 5317c478bd9Sstevel@tonic-gate 5327c478bd9Sstevel@tonic-gate /* 5337c478bd9Sstevel@tonic-gate * Release a log_file structure 5347c478bd9Sstevel@tonic-gate */ 5357c478bd9Sstevel@tonic-gate static void 5367c478bd9Sstevel@tonic-gate log_file_rele(struct log_file *lfp) 5377c478bd9Sstevel@tonic-gate { 5387c478bd9Sstevel@tonic-gate int len; 5397c478bd9Sstevel@tonic-gate int error; 5407c478bd9Sstevel@tonic-gate 5417c478bd9Sstevel@tonic-gate mutex_enter(&lfp->lf_lock); 5427c478bd9Sstevel@tonic-gate if (--lfp->lf_refcnt > 0) { 5437c478bd9Sstevel@tonic-gate LOGGING_DPRINT((10, 5447c478bd9Sstevel@tonic-gate "log_file_rele lfp=%p decremented refcnt to %d\n", 545903a11ebSrh87107 (void *)lfp, lfp->lf_refcnt)); 5467c478bd9Sstevel@tonic-gate mutex_exit(&lfp->lf_lock); 5477c478bd9Sstevel@tonic-gate return; 5487c478bd9Sstevel@tonic-gate } 5497c478bd9Sstevel@tonic-gate if (lfp->lf_refcnt < 0) { 5507c478bd9Sstevel@tonic-gate panic("log_file_rele: log_file refcnt < 0"); 5517c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 5527c478bd9Sstevel@tonic-gate } 5537c478bd9Sstevel@tonic-gate 554903a11ebSrh87107 LOGGING_DPRINT((10, "log_file_rele lfp=%p freeing node\n", 555903a11ebSrh87107 (void *)lfp)); 5567c478bd9Sstevel@tonic-gate 5577c478bd9Sstevel@tonic-gate lfp->lf_flags &= ~(L_PRINTED | L_ERROR); 5587c478bd9Sstevel@tonic-gate 5597c478bd9Sstevel@tonic-gate ASSERT(lfp->lf_flags == 0); 5607c478bd9Sstevel@tonic-gate ASSERT(lfp->lf_writers == 0); 5617c478bd9Sstevel@tonic-gate 5627c478bd9Sstevel@tonic-gate if (error = VOP_CLOSE(lfp->lf_vp, FCREAT|FWRITE|FOFFMAX, 1, (offset_t)0, 563da6c28aaSamw CRED(), NULL)) { 5647c478bd9Sstevel@tonic-gate nfs_cmn_err(error, CE_WARN, 5657c478bd9Sstevel@tonic-gate "NFS: Could not close log buffer %s - error = %m", 5667c478bd9Sstevel@tonic-gate lfp->lf_path); 5677c478bd9Sstevel@tonic-gate #ifdef DEBUG 5687c478bd9Sstevel@tonic-gate } else { 5697c478bd9Sstevel@tonic-gate LOGGING_DPRINT((3, 5709d39bb88Sbatschul "log_file_rele: %s has been closed vp=%p v_count=%d\n", 571903a11ebSrh87107 lfp->lf_path, (void *)lfp->lf_vp, lfp->lf_vp->v_count)); 5727c478bd9Sstevel@tonic-gate #endif 5737c478bd9Sstevel@tonic-gate } 5747c478bd9Sstevel@tonic-gate VN_RELE(lfp->lf_vp); 5757c478bd9Sstevel@tonic-gate 5767c478bd9Sstevel@tonic-gate len = strlen(lfp->lf_path) + 1; 5777c478bd9Sstevel@tonic-gate kmem_free(lfp->lf_path, len); 5787c478bd9Sstevel@tonic-gate kmem_free(lfp, sizeof (*lfp)); 5797c478bd9Sstevel@tonic-gate rfsl_log_file--; 5807c478bd9Sstevel@tonic-gate } 5817c478bd9Sstevel@tonic-gate 5827c478bd9Sstevel@tonic-gate /* 5837c478bd9Sstevel@tonic-gate * Allocates a record of the size specified. 5847c478bd9Sstevel@tonic-gate * 'exi' identifies the exportinfo structure being logged. 5857c478bd9Sstevel@tonic-gate * 'size' indicates how much memory should be allocated 5867c478bd9Sstevel@tonic-gate * 'cookie' is used to store an opaque value for the caller for later use 5877c478bd9Sstevel@tonic-gate * 'flags' currently ignored. 5887c478bd9Sstevel@tonic-gate * 5897c478bd9Sstevel@tonic-gate * Returns a pointer to the beginning of the allocated memory. 5907c478bd9Sstevel@tonic-gate * 'cookie' is a pointer to the 'lr_alloc' struct; this will be used 5917c478bd9Sstevel@tonic-gate * to keep track of the encoded record and contains all the info 5927c478bd9Sstevel@tonic-gate * for enqueuing the record on the log buffer for later writing. 5937c478bd9Sstevel@tonic-gate * 5947c478bd9Sstevel@tonic-gate * nfslog_record_put() must be used to 'free' this record or allocation. 5957c478bd9Sstevel@tonic-gate */ 5967c478bd9Sstevel@tonic-gate /* ARGSUSED */ 5977c478bd9Sstevel@tonic-gate void * 5987c478bd9Sstevel@tonic-gate nfslog_record_alloc( 5997c478bd9Sstevel@tonic-gate struct exportinfo *exi, 6007c478bd9Sstevel@tonic-gate int alloc_indx, 6017c478bd9Sstevel@tonic-gate void **cookie, 6027c478bd9Sstevel@tonic-gate int flags) 6037c478bd9Sstevel@tonic-gate { 6047c478bd9Sstevel@tonic-gate struct lr_alloc *lrp; 6057c478bd9Sstevel@tonic-gate 6067c478bd9Sstevel@tonic-gate lrp = (struct lr_alloc *) 6077c478bd9Sstevel@tonic-gate kmem_cache_alloc(nfslog_mem_alloc[alloc_indx].mem_cache, 6087c478bd9Sstevel@tonic-gate KM_NOSLEEP); 6097c478bd9Sstevel@tonic-gate 6107c478bd9Sstevel@tonic-gate if (lrp == NULL) { 6117c478bd9Sstevel@tonic-gate *cookie = NULL; 6127c478bd9Sstevel@tonic-gate return (NULL); 6137c478bd9Sstevel@tonic-gate } 6147c478bd9Sstevel@tonic-gate 6157c478bd9Sstevel@tonic-gate lrp->next = lrp; 6167c478bd9Sstevel@tonic-gate lrp->prev = lrp; 6177c478bd9Sstevel@tonic-gate lrp->lr_flags = 0; 6187c478bd9Sstevel@tonic-gate 6197c478bd9Sstevel@tonic-gate lrp->log_record = (caddr_t)((uintptr_t)lrp + 6207c478bd9Sstevel@tonic-gate (uintptr_t)sizeof (struct lr_alloc)); 6217c478bd9Sstevel@tonic-gate lrp->size = nfslog_mem_alloc[alloc_indx].size; 6227c478bd9Sstevel@tonic-gate lrp->alloc_cache = nfslog_mem_alloc[alloc_indx].mem_cache; 6237c478bd9Sstevel@tonic-gate lrp->exi = exi; 6247c478bd9Sstevel@tonic-gate 6257c478bd9Sstevel@tonic-gate if (exi->exi_export.ex_flags & EX_LOG) { 6267c478bd9Sstevel@tonic-gate LOG_BUFFER_HOLD(exi->exi_logbuffer); 6277c478bd9Sstevel@tonic-gate lrp->lb = exi->exi_logbuffer; 6287c478bd9Sstevel@tonic-gate } else { 6297c478bd9Sstevel@tonic-gate lrp->lb = NULL; 6307c478bd9Sstevel@tonic-gate } 6317c478bd9Sstevel@tonic-gate 6327c478bd9Sstevel@tonic-gate *cookie = (void *)lrp; 6337c478bd9Sstevel@tonic-gate 6347c478bd9Sstevel@tonic-gate LOGGING_DPRINT((3, 6357c478bd9Sstevel@tonic-gate "nfslog_record_alloc(log_buffer=%p mem=%p size=%lu)\n", 636903a11ebSrh87107 (void *)exi->exi_logbuffer, (void *)lrp->log_record, lrp->size)); 6377c478bd9Sstevel@tonic-gate return (lrp->log_record); 6387c478bd9Sstevel@tonic-gate } 6397c478bd9Sstevel@tonic-gate 6407c478bd9Sstevel@tonic-gate /* 6417c478bd9Sstevel@tonic-gate * After the above nfslog_record_alloc() has been called and a record 6427c478bd9Sstevel@tonic-gate * encoded into the buffer that was returned, this function is called 6437c478bd9Sstevel@tonic-gate * to handle appropriate disposition of the newly created record. 6447c478bd9Sstevel@tonic-gate * The cookie value is the one that was returned from nfslog_record_alloc(). 6457c478bd9Sstevel@tonic-gate * Size is the actual size of the record that was encoded. This is 6467c478bd9Sstevel@tonic-gate * passed in because the size used for the alloc was just an approximation. 6477c478bd9Sstevel@tonic-gate * The sync parameter is used to tell us if we need to force this record 6487c478bd9Sstevel@tonic-gate * to disk and if not it will be queued for later writing. 6497c478bd9Sstevel@tonic-gate * 6507c478bd9Sstevel@tonic-gate * Note that if the size parameter has a value of 0, then the record is 6517c478bd9Sstevel@tonic-gate * not written to the log and the associated data structures are released. 6527c478bd9Sstevel@tonic-gate */ 6537c478bd9Sstevel@tonic-gate void 6547c478bd9Sstevel@tonic-gate nfslog_record_put(void *cookie, size_t size, bool_t sync, 6557c478bd9Sstevel@tonic-gate unsigned int which_buffers) 6567c478bd9Sstevel@tonic-gate { 6577c478bd9Sstevel@tonic-gate struct lr_alloc *lrp = (struct lr_alloc *)cookie; 6587c478bd9Sstevel@tonic-gate struct log_buffer *lbp = lrp->lb; 6597c478bd9Sstevel@tonic-gate 6607c478bd9Sstevel@tonic-gate /* 6617c478bd9Sstevel@tonic-gate * If the caller has nothing to write or if there is 6627c478bd9Sstevel@tonic-gate * an apparent error, rele the buffer and free. 6637c478bd9Sstevel@tonic-gate */ 6647c478bd9Sstevel@tonic-gate if (size == 0 || size > lrp->size) { 6657c478bd9Sstevel@tonic-gate nfslog_free_logrecords(lrp); 6667c478bd9Sstevel@tonic-gate return; 6677c478bd9Sstevel@tonic-gate } 6687c478bd9Sstevel@tonic-gate 6697c478bd9Sstevel@tonic-gate /* 6707c478bd9Sstevel@tonic-gate * Reset the size to what actually needs to be written 6717c478bd9Sstevel@tonic-gate * This is used later on when the iovec is built for 6727c478bd9Sstevel@tonic-gate * writing the records to the log file. 6737c478bd9Sstevel@tonic-gate */ 6747c478bd9Sstevel@tonic-gate lrp->size = size; 6757c478bd9Sstevel@tonic-gate 6767c478bd9Sstevel@tonic-gate /* append to all if public exi */ 6777c478bd9Sstevel@tonic-gate if (which_buffers == NFSLOG_ALL_BUFFERS) { 6787c478bd9Sstevel@tonic-gate (void) nfslog_record_append2all(lrp); 6797c478bd9Sstevel@tonic-gate nfslog_free_logrecords(lrp); 6807c478bd9Sstevel@tonic-gate return; 6817c478bd9Sstevel@tonic-gate } 6827c478bd9Sstevel@tonic-gate 6837c478bd9Sstevel@tonic-gate /* Insert the record on the list to be written */ 6847c478bd9Sstevel@tonic-gate mutex_enter(&lbp->lb_lock); 6857c478bd9Sstevel@tonic-gate if (lbp->lb_records == NULL) { 6867c478bd9Sstevel@tonic-gate lbp->lb_records = (caddr_t)lrp; 6877c478bd9Sstevel@tonic-gate lbp->lb_num_recs = 1; 6887c478bd9Sstevel@tonic-gate lbp->lb_size_queued = lrp->size; 6897c478bd9Sstevel@tonic-gate } else { 6907c478bd9Sstevel@tonic-gate insque(lrp, ((struct lr_alloc *)lbp->lb_records)->prev); 6917c478bd9Sstevel@tonic-gate lbp->lb_num_recs++; 6927c478bd9Sstevel@tonic-gate lbp->lb_size_queued += lrp->size; 6937c478bd9Sstevel@tonic-gate } 6947c478bd9Sstevel@tonic-gate 6957c478bd9Sstevel@tonic-gate /* 6967c478bd9Sstevel@tonic-gate * Determine if the queue for this log buffer should be flushed. 6977c478bd9Sstevel@tonic-gate * This is done by either the number of records queued, the total 6987c478bd9Sstevel@tonic-gate * size of all records queued or by the request of the caller 6997c478bd9Sstevel@tonic-gate * via the sync parameter. 7007c478bd9Sstevel@tonic-gate */ 7017c478bd9Sstevel@tonic-gate if (lbp->lb_size_queued >= nfslog_num_bytes_to_write || 7029d39bb88Sbatschul lbp->lb_num_recs > nfslog_num_records_to_write || sync == TRUE) { 7037c478bd9Sstevel@tonic-gate mutex_exit(&lbp->lb_lock); 7047c478bd9Sstevel@tonic-gate (void) nfslog_records_flush_to_disk(lbp); 7057c478bd9Sstevel@tonic-gate } else { 7067c478bd9Sstevel@tonic-gate mutex_exit(&lbp->lb_lock); 7077c478bd9Sstevel@tonic-gate } 7087c478bd9Sstevel@tonic-gate 7097c478bd9Sstevel@tonic-gate } 7107c478bd9Sstevel@tonic-gate 7117c478bd9Sstevel@tonic-gate /* 7127c478bd9Sstevel@tonic-gate * Examine the log_buffer struct to see if there are queue log records 7137c478bd9Sstevel@tonic-gate * that need to be written to disk. If some exist, pull them off of 7147c478bd9Sstevel@tonic-gate * the log buffer and write them to the log file. 7157c478bd9Sstevel@tonic-gate */ 7167c478bd9Sstevel@tonic-gate static int 7177c478bd9Sstevel@tonic-gate nfslog_records_flush_to_disk(struct log_buffer *lbp) 7187c478bd9Sstevel@tonic-gate { 7197c478bd9Sstevel@tonic-gate 7207c478bd9Sstevel@tonic-gate mutex_enter(&lbp->lb_lock); 7217c478bd9Sstevel@tonic-gate 7227c478bd9Sstevel@tonic-gate if (lbp->lb_records == NULL) { 7237c478bd9Sstevel@tonic-gate mutex_exit(&lbp->lb_lock); 7247c478bd9Sstevel@tonic-gate return (0); 7257c478bd9Sstevel@tonic-gate } 7267c478bd9Sstevel@tonic-gate return (nfslog_records_flush_to_disk_nolock(lbp)); 7277c478bd9Sstevel@tonic-gate } 7287c478bd9Sstevel@tonic-gate 7297c478bd9Sstevel@tonic-gate /* 7307c478bd9Sstevel@tonic-gate * Function requires that the caller holds lb_lock. 7317c478bd9Sstevel@tonic-gate * Function flushes any records in the log buffer to the disk. 7327c478bd9Sstevel@tonic-gate * Function drops the lb_lock on return. 7337c478bd9Sstevel@tonic-gate */ 7347c478bd9Sstevel@tonic-gate 7357c478bd9Sstevel@tonic-gate static int 7367c478bd9Sstevel@tonic-gate nfslog_records_flush_to_disk_nolock(struct log_buffer *lbp) 7377c478bd9Sstevel@tonic-gate { 7387c478bd9Sstevel@tonic-gate struct log_file *lfp = NULL; 7397c478bd9Sstevel@tonic-gate struct lr_alloc *lrp_writers; 7407c478bd9Sstevel@tonic-gate int num_recs; 7417c478bd9Sstevel@tonic-gate int error = 0; 7427c478bd9Sstevel@tonic-gate 7437c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&lbp->lb_lock)); 7447c478bd9Sstevel@tonic-gate 7457c478bd9Sstevel@tonic-gate lfp = lbp->lb_logfile; 7467c478bd9Sstevel@tonic-gate 7477c478bd9Sstevel@tonic-gate LOG_FILE_LOCK_TO_WRITE(lfp); 7487c478bd9Sstevel@tonic-gate ASSERT(lbp->lb_records != NULL); 7497c478bd9Sstevel@tonic-gate 7507c478bd9Sstevel@tonic-gate lrp_writers = (struct lr_alloc *)lbp->lb_records; 7517c478bd9Sstevel@tonic-gate lbp->lb_records = NULL; 7527c478bd9Sstevel@tonic-gate num_recs = lbp->lb_num_recs; 7537c478bd9Sstevel@tonic-gate lbp->lb_num_recs = 0; 7547c478bd9Sstevel@tonic-gate lbp->lb_size_queued = 0; 7557c478bd9Sstevel@tonic-gate mutex_exit(&lbp->lb_lock); 7567c478bd9Sstevel@tonic-gate error = nfslog_write_logrecords(lfp, lrp_writers, num_recs); 7577c478bd9Sstevel@tonic-gate 7587c478bd9Sstevel@tonic-gate LOG_FILE_UNLOCK_FROM_WRITE(lfp); 7597c478bd9Sstevel@tonic-gate 7607c478bd9Sstevel@tonic-gate nfslog_free_logrecords(lrp_writers); 7617c478bd9Sstevel@tonic-gate return (error); 7627c478bd9Sstevel@tonic-gate } 7637c478bd9Sstevel@tonic-gate 7647c478bd9Sstevel@tonic-gate 7657c478bd9Sstevel@tonic-gate /* 7667c478bd9Sstevel@tonic-gate * Take care of writing the provided log record(s) to the log file. 7677c478bd9Sstevel@tonic-gate * We group the log records with an iovec and use VOP_WRITE to append 7687c478bd9Sstevel@tonic-gate * them to the end of the log file. 7697c478bd9Sstevel@tonic-gate */ 7707c478bd9Sstevel@tonic-gate static int 771*aafcd32bSMarcel Telka nfslog_write_logrecords(struct log_file *lfp, struct lr_alloc *lrp_writers, 772*aafcd32bSMarcel Telka int num_recs) 7737c478bd9Sstevel@tonic-gate { 7747c478bd9Sstevel@tonic-gate struct uio uio; 7757c478bd9Sstevel@tonic-gate struct iovec *iovp; 7767c478bd9Sstevel@tonic-gate int size_iovecs; 7777c478bd9Sstevel@tonic-gate vnode_t *vp; 7787c478bd9Sstevel@tonic-gate struct vattr va; 7797c478bd9Sstevel@tonic-gate struct lr_alloc *lrp; 7807c478bd9Sstevel@tonic-gate int i; 7817c478bd9Sstevel@tonic-gate ssize_t len; 7827c478bd9Sstevel@tonic-gate int ioflag = FAPPEND; 7837c478bd9Sstevel@tonic-gate int error = 0; 7847c478bd9Sstevel@tonic-gate 7857c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&lfp->lf_lock)); 7867c478bd9Sstevel@tonic-gate 7877c478bd9Sstevel@tonic-gate vp = lfp->lf_vp; 7887c478bd9Sstevel@tonic-gate 7897c478bd9Sstevel@tonic-gate size_iovecs = sizeof (struct iovec) * num_recs; 7907c478bd9Sstevel@tonic-gate iovp = (struct iovec *)kmem_alloc(size_iovecs, KM_NOSLEEP); 7917c478bd9Sstevel@tonic-gate 7927c478bd9Sstevel@tonic-gate if (iovp == NULL) { 7937c478bd9Sstevel@tonic-gate error = ENOMEM; 7947c478bd9Sstevel@tonic-gate goto out; 7957c478bd9Sstevel@tonic-gate } 7967c478bd9Sstevel@tonic-gate 7977c478bd9Sstevel@tonic-gate /* Build the iovec based on the list of log records */ 7987c478bd9Sstevel@tonic-gate i = 0; 7997c478bd9Sstevel@tonic-gate len = 0; 8007c478bd9Sstevel@tonic-gate lrp = lrp_writers; 8017c478bd9Sstevel@tonic-gate do { 8027c478bd9Sstevel@tonic-gate iovp[i].iov_base = lrp->log_record; 8037c478bd9Sstevel@tonic-gate iovp[i].iov_len = lrp->size; 8047c478bd9Sstevel@tonic-gate len += lrp->size; 8057c478bd9Sstevel@tonic-gate lrp = lrp->next; 8067c478bd9Sstevel@tonic-gate i++; 8077c478bd9Sstevel@tonic-gate } while (lrp != lrp_writers); 8087c478bd9Sstevel@tonic-gate 8097c478bd9Sstevel@tonic-gate ASSERT(i == num_recs); 8107c478bd9Sstevel@tonic-gate 8117c478bd9Sstevel@tonic-gate uio.uio_iov = iovp; 8127c478bd9Sstevel@tonic-gate uio.uio_iovcnt = num_recs; 8137c478bd9Sstevel@tonic-gate uio.uio_loffset = 0; 8147c478bd9Sstevel@tonic-gate uio.uio_segflg = (short)UIO_SYSSPACE; 8157c478bd9Sstevel@tonic-gate uio.uio_resid = len; 8167c478bd9Sstevel@tonic-gate uio.uio_llimit = (rlim64_t)MAXOFFSET_T; 8177c478bd9Sstevel@tonic-gate uio.uio_fmode = FWRITE; 8187c478bd9Sstevel@tonic-gate uio.uio_extflg = UIO_COPY_DEFAULT; 8197c478bd9Sstevel@tonic-gate 8207c478bd9Sstevel@tonic-gate /* 8217c478bd9Sstevel@tonic-gate * Save the size. If the write fails, reset the size to avoid 8227c478bd9Sstevel@tonic-gate * corrupted log buffer files. 8237c478bd9Sstevel@tonic-gate */ 8247c478bd9Sstevel@tonic-gate va.va_mask = AT_SIZE; 8257c478bd9Sstevel@tonic-gate 8267c478bd9Sstevel@tonic-gate (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL); /* UIO_WRITE */ 827da6c28aaSamw if ((error = VOP_GETATTR(vp, &va, 0, CRED(), NULL)) == 0) { 8287c478bd9Sstevel@tonic-gate if ((len + va.va_size) < (MAXOFF32_T)) { 8297c478bd9Sstevel@tonic-gate error = VOP_WRITE(vp, &uio, ioflag, CRED(), NULL); 830d19d8227Spf199842 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL); 8317c478bd9Sstevel@tonic-gate if (uio.uio_resid) 8327c478bd9Sstevel@tonic-gate error = ENOSPC; 8337c478bd9Sstevel@tonic-gate if (error) 8347c478bd9Sstevel@tonic-gate (void) VOP_SETATTR(vp, &va, 0, CRED(), NULL); 8357c478bd9Sstevel@tonic-gate } else { 836d19d8227Spf199842 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL); 8377c478bd9Sstevel@tonic-gate if (!(lfp->lf_flags & L_PRINTED)) { 8387c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 8397c478bd9Sstevel@tonic-gate "NFS Logging: buffer file %s exceeds 2GB; " 8407c478bd9Sstevel@tonic-gate "stopped writing buffer \n", lfp->lf_path); 8417c478bd9Sstevel@tonic-gate } 8427c478bd9Sstevel@tonic-gate error = ENOSPC; 8437c478bd9Sstevel@tonic-gate } 844d19d8227Spf199842 } else { 8457c478bd9Sstevel@tonic-gate VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL); 846d19d8227Spf199842 } 8477c478bd9Sstevel@tonic-gate 8487c478bd9Sstevel@tonic-gate kmem_free(iovp, size_iovecs); 8497c478bd9Sstevel@tonic-gate 8507c478bd9Sstevel@tonic-gate out: 8517c478bd9Sstevel@tonic-gate if (error) { 8527c478bd9Sstevel@tonic-gate if (!(lfp->lf_flags & L_PRINTED)) { 8537c478bd9Sstevel@tonic-gate nfs_cmn_err(error, CE_WARN, 8547c478bd9Sstevel@tonic-gate "NFS Logging disabled for buffer %s - " 8557c478bd9Sstevel@tonic-gate "write error = %m\n", lfp->lf_path); 8567c478bd9Sstevel@tonic-gate lfp->lf_flags |= L_PRINTED; 8577c478bd9Sstevel@tonic-gate } 8587c478bd9Sstevel@tonic-gate } else if (lfp->lf_flags & (L_ERROR | L_PRINTED)) { 8597c478bd9Sstevel@tonic-gate lfp->lf_flags &= ~(L_ERROR | L_PRINTED); 8607c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 8617c478bd9Sstevel@tonic-gate "NFS Logging re-enabled for buffer %s\n", lfp->lf_path); 8627c478bd9Sstevel@tonic-gate } 8637c478bd9Sstevel@tonic-gate 8647c478bd9Sstevel@tonic-gate return (error); 8657c478bd9Sstevel@tonic-gate } 8667c478bd9Sstevel@tonic-gate 8677c478bd9Sstevel@tonic-gate static void 8687c478bd9Sstevel@tonic-gate nfslog_free_logrecords(struct lr_alloc *lrp_writers) 8697c478bd9Sstevel@tonic-gate { 8707c478bd9Sstevel@tonic-gate struct lr_alloc *lrp = lrp_writers; 8717c478bd9Sstevel@tonic-gate struct lr_alloc *lrp_free; 8727c478bd9Sstevel@tonic-gate 8737c478bd9Sstevel@tonic-gate do { 8747c478bd9Sstevel@tonic-gate lrp_free = lrp; 8757c478bd9Sstevel@tonic-gate 8767c478bd9Sstevel@tonic-gate lrp = lrp->next; 8777c478bd9Sstevel@tonic-gate 8787c478bd9Sstevel@tonic-gate /* 8797c478bd9Sstevel@tonic-gate * Check to see if we are supposed to free this structure 8807c478bd9Sstevel@tonic-gate * and relese the log_buffer ref count. 8817c478bd9Sstevel@tonic-gate * It may be the case that the caller does not want this 8827c478bd9Sstevel@tonic-gate * structure and its record contents freed just yet. 8837c478bd9Sstevel@tonic-gate */ 8847c478bd9Sstevel@tonic-gate if ((lrp_free->lr_flags & LR_ALLOC_NOFREE) == 0) { 8857c478bd9Sstevel@tonic-gate if (lrp_free->lb != NULL) 8867c478bd9Sstevel@tonic-gate log_buffer_rele(lrp_free->lb); 8877c478bd9Sstevel@tonic-gate if (lrp_free->alloc_cache) /* double check */ 8887c478bd9Sstevel@tonic-gate kmem_cache_free(lrp_free->alloc_cache, 8897c478bd9Sstevel@tonic-gate (void *)lrp_free); 8907c478bd9Sstevel@tonic-gate } else { 8917c478bd9Sstevel@tonic-gate /* 8927c478bd9Sstevel@tonic-gate * after being pulled from the list the 8937c478bd9Sstevel@tonic-gate * pointers need to be reinitialized. 8947c478bd9Sstevel@tonic-gate */ 8957c478bd9Sstevel@tonic-gate lrp_free->next = lrp_free; 8967c478bd9Sstevel@tonic-gate lrp_free->prev = lrp_free; 8977c478bd9Sstevel@tonic-gate } 8987c478bd9Sstevel@tonic-gate 8997c478bd9Sstevel@tonic-gate } while (lrp != lrp_writers); 9007c478bd9Sstevel@tonic-gate } 9017c478bd9Sstevel@tonic-gate 9027c478bd9Sstevel@tonic-gate /* 9037c478bd9Sstevel@tonic-gate * Rename lbp->lb_logfile to reflect the true name requested by 'share' 9047c478bd9Sstevel@tonic-gate */ 9057c478bd9Sstevel@tonic-gate static int 9067c478bd9Sstevel@tonic-gate nfslog_logbuffer_rename(struct log_buffer *lbp) 9077c478bd9Sstevel@tonic-gate { 9087c478bd9Sstevel@tonic-gate struct log_file *lf; 9097c478bd9Sstevel@tonic-gate int error; 9107c478bd9Sstevel@tonic-gate struct log_file *logfile; 9117c478bd9Sstevel@tonic-gate 9127c478bd9Sstevel@tonic-gate /* 9137c478bd9Sstevel@tonic-gate * Try our best to get the cache records into the log file 9147c478bd9Sstevel@tonic-gate * before the rename occurs. 9157c478bd9Sstevel@tonic-gate */ 9167c478bd9Sstevel@tonic-gate (void) nfslog_records_flush_to_disk(lbp); 9177c478bd9Sstevel@tonic-gate 9187c478bd9Sstevel@tonic-gate /* 9197c478bd9Sstevel@tonic-gate * Hold lb_lock before retrieving 9207c478bd9Sstevel@tonic-gate * lb_logfile. 9217c478bd9Sstevel@tonic-gate * Hold a reference to the 9227c478bd9Sstevel@tonic-gate * "lf" structure. this is 9237c478bd9Sstevel@tonic-gate * same as LOG_FILE_HOLD() 9247c478bd9Sstevel@tonic-gate */ 9257c478bd9Sstevel@tonic-gate mutex_enter(&(lbp)->lb_lock); 9267c478bd9Sstevel@tonic-gate lf = lbp->lb_logfile; 9277c478bd9Sstevel@tonic-gate mutex_enter(&(lf)->lf_lock); 9287c478bd9Sstevel@tonic-gate mutex_exit(&(lbp)->lb_lock); 9297c478bd9Sstevel@tonic-gate lf->lf_refcnt++; 9307c478bd9Sstevel@tonic-gate mutex_exit(&(lf)->lf_lock); 9317c478bd9Sstevel@tonic-gate 9327c478bd9Sstevel@tonic-gate LOGGING_DPRINT((10, "nfslog_logbuffer_rename: renaming %s to %s\n", 9337c478bd9Sstevel@tonic-gate lf->lf_path, lbp->lb_path)); 9347c478bd9Sstevel@tonic-gate 9357c478bd9Sstevel@tonic-gate /* 9367c478bd9Sstevel@tonic-gate * rename the current buffer to what the daemon expects 9377c478bd9Sstevel@tonic-gate */ 9387c478bd9Sstevel@tonic-gate if (error = nfslog_logfile_rename(lf->lf_path, lbp->lb_path)) 9397c478bd9Sstevel@tonic-gate goto out; 9407c478bd9Sstevel@tonic-gate 9417c478bd9Sstevel@tonic-gate /* 9427c478bd9Sstevel@tonic-gate * Create a new working buffer file and have all new data sent there. 9437c478bd9Sstevel@tonic-gate */ 9447c478bd9Sstevel@tonic-gate if (error = log_file_create(lbp->lb_path, &logfile)) { 9457c478bd9Sstevel@tonic-gate /* Attempt to rename to original */ 9467c478bd9Sstevel@tonic-gate (void) nfslog_logfile_rename(lbp->lb_path, lf->lf_path); 9477c478bd9Sstevel@tonic-gate goto out; 9487c478bd9Sstevel@tonic-gate } 9497c478bd9Sstevel@tonic-gate 9507c478bd9Sstevel@tonic-gate /* 9517c478bd9Sstevel@tonic-gate * Hold the lb_lock here, this will make 9527c478bd9Sstevel@tonic-gate * all the threads trying to access lb->logfile block 9537c478bd9Sstevel@tonic-gate * and get a new logfile structure instead of old one. 9547c478bd9Sstevel@tonic-gate */ 9557c478bd9Sstevel@tonic-gate mutex_enter(&(lbp)->lb_lock); 9567c478bd9Sstevel@tonic-gate lbp->lb_logfile = logfile; 9577c478bd9Sstevel@tonic-gate mutex_exit(&(lbp)->lb_lock); 9587c478bd9Sstevel@tonic-gate 9597c478bd9Sstevel@tonic-gate LOG_FILE_RELE(lf); /* release log_buffer's reference */ 9607c478bd9Sstevel@tonic-gate 9617c478bd9Sstevel@tonic-gate /* 9627c478bd9Sstevel@tonic-gate * Wait for log_file to be in a quiescent state before we 9637c478bd9Sstevel@tonic-gate * return to our caller to let it proceed with the reading of 9647c478bd9Sstevel@tonic-gate * this file. 9657c478bd9Sstevel@tonic-gate */ 9667c478bd9Sstevel@tonic-gate nfslog_logfile_wait(lf); 9677c478bd9Sstevel@tonic-gate 9687c478bd9Sstevel@tonic-gate out: 9697c478bd9Sstevel@tonic-gate /* 9707c478bd9Sstevel@tonic-gate * Release our reference on "lf" in two different cases. 9717c478bd9Sstevel@tonic-gate * 1. Error condition, release only the reference 9727c478bd9Sstevel@tonic-gate * that we held at the begining of this 9737c478bd9Sstevel@tonic-gate * routine on "lf" structure. 9747c478bd9Sstevel@tonic-gate * 2. Fall through condition, no errors but the old 9757c478bd9Sstevel@tonic-gate * logfile structure "lf" has been replaced with 9767c478bd9Sstevel@tonic-gate * the new "logfile" structure, so release the 9777c478bd9Sstevel@tonic-gate * reference that was part of the creation of 9787c478bd9Sstevel@tonic-gate * "lf" structure to free up the resources. 9797c478bd9Sstevel@tonic-gate */ 9807c478bd9Sstevel@tonic-gate 9817c478bd9Sstevel@tonic-gate LOG_FILE_RELE(lf); 9827c478bd9Sstevel@tonic-gate 9837c478bd9Sstevel@tonic-gate return (error); 9847c478bd9Sstevel@tonic-gate } 9857c478bd9Sstevel@tonic-gate 9867c478bd9Sstevel@tonic-gate /* 9877c478bd9Sstevel@tonic-gate * Renames the 'from' file to 'new'. 9887c478bd9Sstevel@tonic-gate */ 9897c478bd9Sstevel@tonic-gate static int 9907c478bd9Sstevel@tonic-gate nfslog_logfile_rename(char *from, char *new) 9917c478bd9Sstevel@tonic-gate { 9927c478bd9Sstevel@tonic-gate int error; 9937c478bd9Sstevel@tonic-gate 9947c478bd9Sstevel@tonic-gate if (error = vn_rename(from, new, UIO_SYSSPACE)) { 9957c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 9967c478bd9Sstevel@tonic-gate "nfslog_logfile_rename: couldn't rename %s to %s\n", 9977c478bd9Sstevel@tonic-gate from, new); 9987c478bd9Sstevel@tonic-gate } 9997c478bd9Sstevel@tonic-gate return (error); 10007c478bd9Sstevel@tonic-gate } 10017c478bd9Sstevel@tonic-gate 10027c478bd9Sstevel@tonic-gate /* 10037c478bd9Sstevel@tonic-gate * Wait for the log_file writers to finish before returning 10047c478bd9Sstevel@tonic-gate */ 10057c478bd9Sstevel@tonic-gate static void 10067c478bd9Sstevel@tonic-gate nfslog_logfile_wait(struct log_file *lf) 10077c478bd9Sstevel@tonic-gate { 10087c478bd9Sstevel@tonic-gate mutex_enter(&lf->lf_lock); 10097c478bd9Sstevel@tonic-gate while (lf->lf_writers > 0) { 10107c478bd9Sstevel@tonic-gate lf->lf_flags |= L_WAITING; 10117c478bd9Sstevel@tonic-gate (void) cv_wait_sig(&lf->lf_cv_waiters, &lf->lf_lock); 10127c478bd9Sstevel@tonic-gate } 10137c478bd9Sstevel@tonic-gate mutex_exit(&lf->lf_lock); 10147c478bd9Sstevel@tonic-gate } 10157c478bd9Sstevel@tonic-gate 10167c478bd9Sstevel@tonic-gate static int 10177c478bd9Sstevel@tonic-gate nfslog_record_append2all(struct lr_alloc *lrp) 10187c478bd9Sstevel@tonic-gate { 10197c478bd9Sstevel@tonic-gate struct log_buffer *lbp, *nlbp; 10207c478bd9Sstevel@tonic-gate int error, ret_error = 0; 10217c478bd9Sstevel@tonic-gate int lr_flags = lrp->lr_flags; 10227c478bd9Sstevel@tonic-gate 10237c478bd9Sstevel@tonic-gate rw_enter(&nfslog_buffer_list_lock, RW_READER); 10247c478bd9Sstevel@tonic-gate if ((lbp = nfslog_buffer_list) != NULL) 10257c478bd9Sstevel@tonic-gate LOG_BUFFER_HOLD(lbp); 10267c478bd9Sstevel@tonic-gate for (nlbp = NULL; lbp != NULL; lbp = nlbp) { 10277c478bd9Sstevel@tonic-gate if ((nlbp = lbp->lb_next) != NULL) { 10287c478bd9Sstevel@tonic-gate /* 10297c478bd9Sstevel@tonic-gate * Remember next element in the list 10307c478bd9Sstevel@tonic-gate */ 10317c478bd9Sstevel@tonic-gate LOG_BUFFER_HOLD(nlbp); 10327c478bd9Sstevel@tonic-gate } 10337c478bd9Sstevel@tonic-gate rw_exit(&nfslog_buffer_list_lock); 10347c478bd9Sstevel@tonic-gate 10357c478bd9Sstevel@tonic-gate /* 10367c478bd9Sstevel@tonic-gate * Insert the record on the buffer's list to be written 10377c478bd9Sstevel@tonic-gate * and then flush the records to the log file. 10387c478bd9Sstevel@tonic-gate * Make sure to set the no free flag so that the 10397c478bd9Sstevel@tonic-gate * record can be used for the next write 10407c478bd9Sstevel@tonic-gate */ 10417c478bd9Sstevel@tonic-gate lrp->lr_flags = LR_ALLOC_NOFREE; 10427c478bd9Sstevel@tonic-gate 10437c478bd9Sstevel@tonic-gate ASSERT(lbp != NULL); 10447c478bd9Sstevel@tonic-gate mutex_enter(&lbp->lb_lock); 10457c478bd9Sstevel@tonic-gate if (lbp->lb_records == NULL) { 10467c478bd9Sstevel@tonic-gate lbp->lb_records = (caddr_t)lrp; 10477c478bd9Sstevel@tonic-gate lbp->lb_num_recs = 1; 10487c478bd9Sstevel@tonic-gate lbp->lb_size_queued = lrp->size; 10497c478bd9Sstevel@tonic-gate } else { 10507c478bd9Sstevel@tonic-gate insque(lrp, ((struct lr_alloc *)lbp->lb_records)->prev); 10517c478bd9Sstevel@tonic-gate lbp->lb_num_recs++; 10527c478bd9Sstevel@tonic-gate lbp->lb_size_queued += lrp->size; 10537c478bd9Sstevel@tonic-gate } 10547c478bd9Sstevel@tonic-gate 10557c478bd9Sstevel@tonic-gate /* 10567c478bd9Sstevel@tonic-gate * Flush log records to disk. 10577c478bd9Sstevel@tonic-gate * Function is called with lb_lock held. 10587c478bd9Sstevel@tonic-gate * Function drops the lb_lock on return. 10597c478bd9Sstevel@tonic-gate */ 10607c478bd9Sstevel@tonic-gate error = nfslog_records_flush_to_disk_nolock(lbp); 10617c478bd9Sstevel@tonic-gate 10627c478bd9Sstevel@tonic-gate if (error) { 10637c478bd9Sstevel@tonic-gate ret_error = -1; 10647c478bd9Sstevel@tonic-gate nfs_cmn_err(error, CE_WARN, 10657c478bd9Sstevel@tonic-gate "rfsl_log_pubfh: could not append record to " 10667c478bd9Sstevel@tonic-gate "\"%s\" error = %m\n", lbp->lb_path); 10677c478bd9Sstevel@tonic-gate } 10687c478bd9Sstevel@tonic-gate log_buffer_rele(lbp); 10697c478bd9Sstevel@tonic-gate rw_enter(&nfslog_buffer_list_lock, RW_READER); 10707c478bd9Sstevel@tonic-gate } 10717c478bd9Sstevel@tonic-gate rw_exit(&nfslog_buffer_list_lock); 10727c478bd9Sstevel@tonic-gate 10737c478bd9Sstevel@tonic-gate lrp->lr_flags = lr_flags; 10747c478bd9Sstevel@tonic-gate 10757c478bd9Sstevel@tonic-gate return (ret_error); 10767c478bd9Sstevel@tonic-gate } 10777c478bd9Sstevel@tonic-gate 10787c478bd9Sstevel@tonic-gate #ifdef DEBUG 10797c478bd9Sstevel@tonic-gate static int logging_debug = 0; 10807c478bd9Sstevel@tonic-gate 10817c478bd9Sstevel@tonic-gate /* 10827c478bd9Sstevel@tonic-gate * 0) no debugging 10837c478bd9Sstevel@tonic-gate * 3) current test software 10847c478bd9Sstevel@tonic-gate * 10) random stuff 10857c478bd9Sstevel@tonic-gate */ 10867c478bd9Sstevel@tonic-gate void 10877c478bd9Sstevel@tonic-gate nfslog_dprint(const int level, const char *fmt, ...) 10887c478bd9Sstevel@tonic-gate { 10897c478bd9Sstevel@tonic-gate va_list args; 10907c478bd9Sstevel@tonic-gate 10917c478bd9Sstevel@tonic-gate if (logging_debug == level || 10927c478bd9Sstevel@tonic-gate (logging_debug > 10 && (logging_debug - 10) >= level)) { 10937c478bd9Sstevel@tonic-gate va_start(args, fmt); 10947c478bd9Sstevel@tonic-gate (void) vprintf(fmt, args); 10957c478bd9Sstevel@tonic-gate va_end(args); 10967c478bd9Sstevel@tonic-gate } 10977c478bd9Sstevel@tonic-gate } 10987c478bd9Sstevel@tonic-gate 10997c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 11007c478bd9Sstevel@tonic-gate 11017c478bd9Sstevel@tonic-gate /* 11027c478bd9Sstevel@tonic-gate * NFS Log Flush system call 11037c478bd9Sstevel@tonic-gate * Caller must check privileges. 11047c478bd9Sstevel@tonic-gate */ 11057c478bd9Sstevel@tonic-gate /* ARGSUSED */ 11067c478bd9Sstevel@tonic-gate int 11077c478bd9Sstevel@tonic-gate nfsl_flush(struct nfsl_flush_args *args, model_t model) 11087c478bd9Sstevel@tonic-gate { 11097c478bd9Sstevel@tonic-gate struct flush_thread_params *tparams; 11107c478bd9Sstevel@tonic-gate struct nfsl_flush_args *nfsl_args; 11117c478bd9Sstevel@tonic-gate int error = 0; 11127c478bd9Sstevel@tonic-gate ulong_t buffer_len; 11137c478bd9Sstevel@tonic-gate STRUCT_HANDLE(nfsl_flush_args, uap); 11147c478bd9Sstevel@tonic-gate 11157c478bd9Sstevel@tonic-gate STRUCT_SET_HANDLE(uap, model, args); 11167c478bd9Sstevel@tonic-gate 11177c478bd9Sstevel@tonic-gate tparams = (struct flush_thread_params *) 11187c478bd9Sstevel@tonic-gate kmem_zalloc(sizeof (*tparams), KM_SLEEP); 11197c478bd9Sstevel@tonic-gate 11207c478bd9Sstevel@tonic-gate nfsl_args = &tparams->tp_args; 11217c478bd9Sstevel@tonic-gate nfsl_args->version = STRUCT_FGET(uap, version); 11227c478bd9Sstevel@tonic-gate if (nfsl_args->version != NFSL_FLUSH_ARGS_VERS) { 11237c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "nfsl_flush: exected version %d, got %d", 11247c478bd9Sstevel@tonic-gate NFSL_FLUSH_ARGS_VERS, nfsl_args->version); 11257c478bd9Sstevel@tonic-gate return (EIO); 11267c478bd9Sstevel@tonic-gate } 11277c478bd9Sstevel@tonic-gate 11287c478bd9Sstevel@tonic-gate nfsl_args->directive = STRUCT_FGET(uap, directive); 11297c478bd9Sstevel@tonic-gate if ((nfsl_args->directive & NFSL_ALL) == 0) { 11307c478bd9Sstevel@tonic-gate /* 11317c478bd9Sstevel@tonic-gate * Process a specific buffer 11327c478bd9Sstevel@tonic-gate */ 11337c478bd9Sstevel@tonic-gate nfsl_args->buff_len = STRUCT_FGET(uap, buff_len); 11347c478bd9Sstevel@tonic-gate 11357c478bd9Sstevel@tonic-gate nfsl_args->buff = (char *) 11367c478bd9Sstevel@tonic-gate kmem_alloc(nfsl_args->buff_len, KM_NOSLEEP); 11377c478bd9Sstevel@tonic-gate if (nfsl_args->buff == NULL) 11387c478bd9Sstevel@tonic-gate return (ENOMEM); 11397c478bd9Sstevel@tonic-gate 11407c478bd9Sstevel@tonic-gate error = copyinstr((const char *)STRUCT_FGETP(uap, buff), 11417c478bd9Sstevel@tonic-gate nfsl_args->buff, nfsl_args->buff_len, &buffer_len); 11427c478bd9Sstevel@tonic-gate if (error) 11437c478bd9Sstevel@tonic-gate return (EFAULT); 11447c478bd9Sstevel@tonic-gate 11457c478bd9Sstevel@tonic-gate if (nfsl_args->buff_len != buffer_len) 11467c478bd9Sstevel@tonic-gate return (EFAULT); 11477c478bd9Sstevel@tonic-gate } 11487c478bd9Sstevel@tonic-gate 11497c478bd9Sstevel@tonic-gate LOGGING_DPRINT((10, "nfsl_flush: Flushing %s buffer(s)\n", 11507c478bd9Sstevel@tonic-gate nfsl_args->directive & NFSL_ALL ? "all" : nfsl_args->buff)); 11517c478bd9Sstevel@tonic-gate 11527c478bd9Sstevel@tonic-gate if (nfsl_args->directive & NFSL_SYNC) { 11537c478bd9Sstevel@tonic-gate /* 11547c478bd9Sstevel@tonic-gate * Do the work synchronously 11557c478bd9Sstevel@tonic-gate */ 11567c478bd9Sstevel@tonic-gate nfslog_do_flush(tparams); 11577c478bd9Sstevel@tonic-gate error = tparams->tp_error; 11587c478bd9Sstevel@tonic-gate kmem_free(nfsl_args->buff, nfsl_args->buff_len); 11597c478bd9Sstevel@tonic-gate kmem_free(tparams, sizeof (*tparams)); 11607c478bd9Sstevel@tonic-gate } else { 11617c478bd9Sstevel@tonic-gate /* 11627c478bd9Sstevel@tonic-gate * Do the work asynchronously 11637c478bd9Sstevel@tonic-gate */ 11647c478bd9Sstevel@tonic-gate (void) thread_create(NULL, 0, nfslog_do_flush, 11657c478bd9Sstevel@tonic-gate tparams, 0, &p0, TS_RUN, minclsyspri); 11667c478bd9Sstevel@tonic-gate } 11677c478bd9Sstevel@tonic-gate 11687c478bd9Sstevel@tonic-gate return (error); 11697c478bd9Sstevel@tonic-gate } 11707c478bd9Sstevel@tonic-gate 11717c478bd9Sstevel@tonic-gate /* 11727c478bd9Sstevel@tonic-gate * This is where buffer flushing would occur, but there is no buffering 11737c478bd9Sstevel@tonic-gate * at this time. 11747c478bd9Sstevel@tonic-gate * Possibly rename the log buffer for processing. 1175da6c28aaSamw * Sets tparams->ta_error equal to the value of the error that occurred, 11767c478bd9Sstevel@tonic-gate * 0 otherwise. 11777c478bd9Sstevel@tonic-gate * Returns ENOENT if the buffer is not found. 11787c478bd9Sstevel@tonic-gate */ 11797c478bd9Sstevel@tonic-gate static void 11807c478bd9Sstevel@tonic-gate nfslog_do_flush(struct flush_thread_params *tparams) 11817c478bd9Sstevel@tonic-gate { 11827c478bd9Sstevel@tonic-gate struct nfsl_flush_args *args; 11839d39bb88Sbatschul struct log_buffer *lbp, *nlbp; 11847c478bd9Sstevel@tonic-gate int error = ENOENT; 11857c478bd9Sstevel@tonic-gate int found = 0; 11867c478bd9Sstevel@tonic-gate char *buf_inprog; /* name of buff in progress */ 11877c478bd9Sstevel@tonic-gate int buf_inprog_len; 11887c478bd9Sstevel@tonic-gate 11897c478bd9Sstevel@tonic-gate /* 11907c478bd9Sstevel@tonic-gate * Sanity check on the arguments. 11917c478bd9Sstevel@tonic-gate */ 11927c478bd9Sstevel@tonic-gate if (!tparams) 11937c478bd9Sstevel@tonic-gate return; 11947c478bd9Sstevel@tonic-gate args = &tparams->tp_args; 11957c478bd9Sstevel@tonic-gate if (!args) 11967c478bd9Sstevel@tonic-gate return; 11977c478bd9Sstevel@tonic-gate 11987c478bd9Sstevel@tonic-gate rw_enter(&nfslog_buffer_list_lock, RW_READER); 11999d39bb88Sbatschul if ((lbp = nfslog_buffer_list) != NULL) { 12009d39bb88Sbatschul LOG_BUFFER_HOLD(lbp); 12019d39bb88Sbatschul } 12029d39bb88Sbatschul for (nlbp = NULL; lbp != NULL; lbp = nlbp) { 12039d39bb88Sbatschul if ((nlbp = lbp->lb_next) != NULL) { 12049d39bb88Sbatschul LOG_BUFFER_HOLD(nlbp); 12059d39bb88Sbatschul } 12069d39bb88Sbatschul rw_exit(&nfslog_buffer_list_lock); 12077c478bd9Sstevel@tonic-gate if (args->directive & NFSL_ALL) { 12087c478bd9Sstevel@tonic-gate (void) nfslog_records_flush_to_disk(lbp); 12097c478bd9Sstevel@tonic-gate } else { 12107c478bd9Sstevel@tonic-gate if ((strcmp(lbp->lb_path, args->buff) == 0) && 12117c478bd9Sstevel@tonic-gate (args->directive & NFSL_RENAME)) { 12127c478bd9Sstevel@tonic-gate error = nfslog_logbuffer_rename(lbp); 12137c478bd9Sstevel@tonic-gate found++; 12149d39bb88Sbatschul if (nlbp != NULL) 12159d39bb88Sbatschul log_buffer_rele(nlbp); 12169d39bb88Sbatschul log_buffer_rele(lbp); 12177c478bd9Sstevel@tonic-gate break; 12187c478bd9Sstevel@tonic-gate } 12197c478bd9Sstevel@tonic-gate } 12209d39bb88Sbatschul log_buffer_rele(lbp); 12219d39bb88Sbatschul rw_enter(&nfslog_buffer_list_lock, RW_READER); 12227c478bd9Sstevel@tonic-gate } 12239d39bb88Sbatschul if (!found) 12247c478bd9Sstevel@tonic-gate rw_exit(&nfslog_buffer_list_lock); 12257c478bd9Sstevel@tonic-gate 12267c478bd9Sstevel@tonic-gate if (!found && ((args->directive & NFSL_ALL) == 0) && 12277c478bd9Sstevel@tonic-gate (args->directive & NFSL_RENAME)) { 12287c478bd9Sstevel@tonic-gate /* 12297c478bd9Sstevel@tonic-gate * The specified buffer is not currently in use, 12307c478bd9Sstevel@tonic-gate * simply rename the file indicated. 12317c478bd9Sstevel@tonic-gate */ 12327c478bd9Sstevel@tonic-gate buf_inprog_len = strlen(args->buff) + 12337c478bd9Sstevel@tonic-gate strlen(LOG_INPROG_STRING) + 1; 12347c478bd9Sstevel@tonic-gate buf_inprog = (caddr_t)kmem_alloc(buf_inprog_len, KM_SLEEP); 12357c478bd9Sstevel@tonic-gate (void) sprintf(buf_inprog, "%s%s", 12367c478bd9Sstevel@tonic-gate args->buff, LOG_INPROG_STRING); 12377c478bd9Sstevel@tonic-gate 12387c478bd9Sstevel@tonic-gate error = nfslog_logfile_rename(buf_inprog, args->buff); 12397c478bd9Sstevel@tonic-gate 12407c478bd9Sstevel@tonic-gate kmem_free(buf_inprog, buf_inprog_len); 12417c478bd9Sstevel@tonic-gate } 12427c478bd9Sstevel@tonic-gate 12437c478bd9Sstevel@tonic-gate out: 12447c478bd9Sstevel@tonic-gate if ((args->directive & NFSL_SYNC) == 0) { 12457c478bd9Sstevel@tonic-gate /* 12467c478bd9Sstevel@tonic-gate * Work was performed asynchronously, the caller is 12477c478bd9Sstevel@tonic-gate * no longer waiting for us. 12487c478bd9Sstevel@tonic-gate * Free the thread arguments and exit. 12497c478bd9Sstevel@tonic-gate */ 12507c478bd9Sstevel@tonic-gate kmem_free(args->buff, args->buff_len); 12517c478bd9Sstevel@tonic-gate kmem_free(tparams, sizeof (*tparams)); 12527c478bd9Sstevel@tonic-gate thread_exit(); 12537c478bd9Sstevel@tonic-gate /* NOTREACHED */ 12547c478bd9Sstevel@tonic-gate } 12557c478bd9Sstevel@tonic-gate 12567c478bd9Sstevel@tonic-gate tparams->tp_error = error; 12577c478bd9Sstevel@tonic-gate } 12587c478bd9Sstevel@tonic-gate 12597c478bd9Sstevel@tonic-gate /* 12607c478bd9Sstevel@tonic-gate * Generate buffer_header. 12617c478bd9Sstevel@tonic-gate * 'loghdr' points the the buffer_header, and *reclen 12627c478bd9Sstevel@tonic-gate * contains the length of the buffer. 12637c478bd9Sstevel@tonic-gate */ 12647c478bd9Sstevel@tonic-gate static void 12657c478bd9Sstevel@tonic-gate create_buffer_header(caddr_t *loghdr, size_t *reclen, size_t *freesize) 12667c478bd9Sstevel@tonic-gate { 12677c478bd9Sstevel@tonic-gate timestruc_t now; 12687c478bd9Sstevel@tonic-gate nfslog_buffer_header lh; 12697c478bd9Sstevel@tonic-gate XDR xdrs; 12707c478bd9Sstevel@tonic-gate unsigned int final_size; 12717c478bd9Sstevel@tonic-gate 12727c478bd9Sstevel@tonic-gate 12737c478bd9Sstevel@tonic-gate /* pick some size that will hold the buffer_header */ 12747c478bd9Sstevel@tonic-gate *freesize = NFSLOG_SMALL_RECORD_SIZE; 12757c478bd9Sstevel@tonic-gate 12767c478bd9Sstevel@tonic-gate /* 12777c478bd9Sstevel@tonic-gate * Fill header 12787c478bd9Sstevel@tonic-gate */ 12797c478bd9Sstevel@tonic-gate lh.bh_length = 0; /* don't know yet how large it will be */ 12807c478bd9Sstevel@tonic-gate lh.bh_version = NFSLOG_BUF_VERSION; 12817c478bd9Sstevel@tonic-gate lh.bh_flags = 0; 12827c478bd9Sstevel@tonic-gate lh.bh_offset = 0; 12837c478bd9Sstevel@tonic-gate gethrestime(&now); 12847c478bd9Sstevel@tonic-gate TIMESPEC_TO_TIMESPEC32(&lh.bh_timestamp, &now); 12857c478bd9Sstevel@tonic-gate 12867c478bd9Sstevel@tonic-gate /* 12877c478bd9Sstevel@tonic-gate * Encode the header 12887c478bd9Sstevel@tonic-gate */ 12897c478bd9Sstevel@tonic-gate *loghdr = (caddr_t)kmem_alloc(*freesize, KM_SLEEP); 12907c478bd9Sstevel@tonic-gate xdrmem_create(&xdrs, *loghdr, *freesize, XDR_ENCODE); 12917c478bd9Sstevel@tonic-gate 12927c478bd9Sstevel@tonic-gate (void) xdr_nfslog_buffer_header(&xdrs, &lh); 12937c478bd9Sstevel@tonic-gate 12947c478bd9Sstevel@tonic-gate /* 12957c478bd9Sstevel@tonic-gate * Reset with final size of the encoded data 12967c478bd9Sstevel@tonic-gate */ 12977c478bd9Sstevel@tonic-gate final_size = xdr_getpos(&xdrs); 12987c478bd9Sstevel@tonic-gate xdr_setpos(&xdrs, 0); 12997c478bd9Sstevel@tonic-gate (void) xdr_u_int(&xdrs, &final_size); 13007c478bd9Sstevel@tonic-gate 13017c478bd9Sstevel@tonic-gate *reclen = (size_t)final_size; 13027c478bd9Sstevel@tonic-gate } 13037c478bd9Sstevel@tonic-gate 13047c478bd9Sstevel@tonic-gate /* 13057c478bd9Sstevel@tonic-gate * **************************************************************** 13067c478bd9Sstevel@tonic-gate * RPC dispatch table for logging 13077c478bd9Sstevel@tonic-gate * Indexed by program, version, proc 13087c478bd9Sstevel@tonic-gate * Based on NFS dispatch table. 13097c478bd9Sstevel@tonic-gate */ 13107c478bd9Sstevel@tonic-gate struct nfslog_proc_disp { 13117c478bd9Sstevel@tonic-gate bool_t (*xdrargs)(); 13127c478bd9Sstevel@tonic-gate bool_t (*xdrres)(); 13137c478bd9Sstevel@tonic-gate bool_t affects_transactions; /* Operation affects transaction */ 13147c478bd9Sstevel@tonic-gate /* processing */ 13157c478bd9Sstevel@tonic-gate }; 13167c478bd9Sstevel@tonic-gate 13177c478bd9Sstevel@tonic-gate struct nfslog_vers_disp { 13187c478bd9Sstevel@tonic-gate int nfslog_dis_nprocs; /* number of procs */ 13197c478bd9Sstevel@tonic-gate struct nfslog_proc_disp *nfslog_dis_proc_table; /* proc array */ 13207c478bd9Sstevel@tonic-gate }; 13217c478bd9Sstevel@tonic-gate 13227c478bd9Sstevel@tonic-gate struct nfslog_prog_disp { 13237c478bd9Sstevel@tonic-gate int nfslog_dis_prog; /* program number */ 13247c478bd9Sstevel@tonic-gate int nfslog_dis_versmin; /* Minimum version value */ 13257c478bd9Sstevel@tonic-gate int nfslog_dis_nvers; /* Number of version values */ 13267c478bd9Sstevel@tonic-gate struct nfslog_vers_disp *nfslog_dis_vers_table; /* versions array */ 13277c478bd9Sstevel@tonic-gate }; 13287c478bd9Sstevel@tonic-gate 13297c478bd9Sstevel@tonic-gate static int rfs_log_bad = 0; /* incremented on bad log attempts */ 13307c478bd9Sstevel@tonic-gate static int rfs_log_good = 0; /* incremented on successful log attempts */ 13317c478bd9Sstevel@tonic-gate 13327c478bd9Sstevel@tonic-gate /* 13337c478bd9Sstevel@tonic-gate * Define the actions taken per prog/vers/proc: 13347c478bd9Sstevel@tonic-gate * 13357c478bd9Sstevel@tonic-gate * In some cases, the nl types are the same as the nfs types and a simple 13367c478bd9Sstevel@tonic-gate * bcopy should suffice. Rather that define tens of identical procedures, 13377c478bd9Sstevel@tonic-gate * simply define these to bcopy. Similarly this takes care of different 13387c478bd9Sstevel@tonic-gate * procs that use same parameter struct. 13397c478bd9Sstevel@tonic-gate */ 13407c478bd9Sstevel@tonic-gate 13417c478bd9Sstevel@tonic-gate static struct nfslog_proc_disp nfslog_proc_v2[] = { 13427c478bd9Sstevel@tonic-gate /* 13437c478bd9Sstevel@tonic-gate * NFS VERSION 2 13447c478bd9Sstevel@tonic-gate */ 13457c478bd9Sstevel@tonic-gate 13467c478bd9Sstevel@tonic-gate /* RFS_NULL = 0 */ 13477c478bd9Sstevel@tonic-gate {xdr_void, xdr_void, FALSE}, 13487c478bd9Sstevel@tonic-gate 13497c478bd9Sstevel@tonic-gate /* RFS_GETATTR = 1 */ 13507c478bd9Sstevel@tonic-gate {xdr_fhandle, xdr_nfslog_getattrres, FALSE}, 13517c478bd9Sstevel@tonic-gate 13527c478bd9Sstevel@tonic-gate /* RFS_SETATTR = 2 */ 13537c478bd9Sstevel@tonic-gate {xdr_nfslog_setattrargs, xdr_nfsstat, TRUE}, 13547c478bd9Sstevel@tonic-gate 13557c478bd9Sstevel@tonic-gate /* RFS_ROOT = 3 *** NO LONGER SUPPORTED *** */ 13567c478bd9Sstevel@tonic-gate {xdr_void, xdr_void, FALSE}, 13577c478bd9Sstevel@tonic-gate 13587c478bd9Sstevel@tonic-gate /* RFS_LOOKUP = 4 */ 13597c478bd9Sstevel@tonic-gate {xdr_nfslog_diropargs, xdr_nfslog_diropres, TRUE}, 13607c478bd9Sstevel@tonic-gate 13617c478bd9Sstevel@tonic-gate /* RFS_READLINK = 5 */ 13627c478bd9Sstevel@tonic-gate {xdr_fhandle, xdr_nfslog_rdlnres, FALSE}, 13637c478bd9Sstevel@tonic-gate 13647c478bd9Sstevel@tonic-gate /* RFS_READ = 6 */ 13657c478bd9Sstevel@tonic-gate {xdr_nfslog_nfsreadargs, xdr_nfslog_rdresult, TRUE}, 13667c478bd9Sstevel@tonic-gate 13677c478bd9Sstevel@tonic-gate /* RFS_WRITECACHE = 7 *** NO LONGER SUPPORTED *** */ 13687c478bd9Sstevel@tonic-gate {xdr_void, xdr_void, FALSE}, 13697c478bd9Sstevel@tonic-gate 13707c478bd9Sstevel@tonic-gate /* RFS_WRITE = 8 */ 13717c478bd9Sstevel@tonic-gate {xdr_nfslog_writeargs, xdr_nfslog_writeresult, TRUE}, 13727c478bd9Sstevel@tonic-gate 13737c478bd9Sstevel@tonic-gate /* RFS_CREATE = 9 */ 13747c478bd9Sstevel@tonic-gate {xdr_nfslog_createargs, xdr_nfslog_diropres, TRUE}, 13757c478bd9Sstevel@tonic-gate 13767c478bd9Sstevel@tonic-gate /* RFS_REMOVE = 10 */ 13777c478bd9Sstevel@tonic-gate {xdr_nfslog_diropargs, xdr_nfsstat, TRUE}, 13787c478bd9Sstevel@tonic-gate 13797c478bd9Sstevel@tonic-gate /* RFS_RENAME = 11 */ 13807c478bd9Sstevel@tonic-gate {xdr_nfslog_rnmargs, xdr_nfsstat, TRUE}, 13817c478bd9Sstevel@tonic-gate 13827c478bd9Sstevel@tonic-gate /* RFS_LINK = 12 */ 13837c478bd9Sstevel@tonic-gate {xdr_nfslog_linkargs, xdr_nfsstat, TRUE}, 13847c478bd9Sstevel@tonic-gate 13857c478bd9Sstevel@tonic-gate /* RFS_SYMLINK = 13 */ 13867c478bd9Sstevel@tonic-gate {xdr_nfslog_symlinkargs, xdr_nfsstat, TRUE}, 13877c478bd9Sstevel@tonic-gate 13887c478bd9Sstevel@tonic-gate /* RFS_MKDIR = 14 */ 13897c478bd9Sstevel@tonic-gate {xdr_nfslog_createargs, xdr_nfslog_diropres, TRUE}, 13907c478bd9Sstevel@tonic-gate 13917c478bd9Sstevel@tonic-gate /* RFS_RMDIR = 15 */ 13927c478bd9Sstevel@tonic-gate {xdr_nfslog_diropargs, xdr_nfsstat, TRUE}, 13937c478bd9Sstevel@tonic-gate 13947c478bd9Sstevel@tonic-gate /* RFS_READDIR = 16 */ 13957c478bd9Sstevel@tonic-gate {xdr_nfslog_rddirargs, xdr_nfslog_rddirres, TRUE}, 13967c478bd9Sstevel@tonic-gate 13977c478bd9Sstevel@tonic-gate /* RFS_STATFS = 17 */ 13987c478bd9Sstevel@tonic-gate {xdr_fhandle, xdr_nfslog_statfs, FALSE}, 13997c478bd9Sstevel@tonic-gate }; 14007c478bd9Sstevel@tonic-gate 14017c478bd9Sstevel@tonic-gate 14027c478bd9Sstevel@tonic-gate /* 14037c478bd9Sstevel@tonic-gate * NFS VERSION 3 14047c478bd9Sstevel@tonic-gate */ 14057c478bd9Sstevel@tonic-gate 14067c478bd9Sstevel@tonic-gate static struct nfslog_proc_disp nfslog_proc_v3[] = { 14077c478bd9Sstevel@tonic-gate 14087c478bd9Sstevel@tonic-gate /* NFSPROC3_NULL = 0 */ 14097c478bd9Sstevel@tonic-gate {xdr_void, xdr_void, FALSE}, 14107c478bd9Sstevel@tonic-gate 14117c478bd9Sstevel@tonic-gate /* NFSPROC3_GETATTR = 1 */ 141227242a7cSthurlow {xdr_nfslog_nfs_fh3, xdr_nfslog_GETATTR3res, FALSE}, 14137c478bd9Sstevel@tonic-gate 14147c478bd9Sstevel@tonic-gate /* NFSPROC3_SETATTR = 2 */ 14157c478bd9Sstevel@tonic-gate {xdr_nfslog_SETATTR3args, xdr_nfslog_SETATTR3res, TRUE}, 14167c478bd9Sstevel@tonic-gate 14177c478bd9Sstevel@tonic-gate /* NFSPROC3_LOOKUP = 3 */ 14187c478bd9Sstevel@tonic-gate {xdr_nfslog_diropargs3, xdr_nfslog_LOOKUP3res, TRUE}, 14197c478bd9Sstevel@tonic-gate 14207c478bd9Sstevel@tonic-gate /* NFSPROC3_ACCESS = 4 */ 14217c478bd9Sstevel@tonic-gate {xdr_nfslog_ACCESS3args, xdr_nfslog_ACCESS3res, FALSE}, 14227c478bd9Sstevel@tonic-gate 14237c478bd9Sstevel@tonic-gate /* NFSPROC3_READLINK = 5 */ 142427242a7cSthurlow {xdr_nfslog_nfs_fh3, xdr_nfslog_READLINK3res, FALSE}, 14257c478bd9Sstevel@tonic-gate 14267c478bd9Sstevel@tonic-gate /* NFSPROC3_READ = 6 */ 14277c478bd9Sstevel@tonic-gate {xdr_nfslog_READ3args, xdr_nfslog_READ3res, TRUE}, 14287c478bd9Sstevel@tonic-gate 14297c478bd9Sstevel@tonic-gate /* NFSPROC3_WRITE = 7 */ 14307c478bd9Sstevel@tonic-gate {xdr_nfslog_WRITE3args, xdr_nfslog_WRITE3res, TRUE}, 14317c478bd9Sstevel@tonic-gate 14327c478bd9Sstevel@tonic-gate /* NFSPROC3_CREATE = 8 */ 14337c478bd9Sstevel@tonic-gate {xdr_nfslog_CREATE3args, xdr_nfslog_CREATE3res, TRUE}, 14347c478bd9Sstevel@tonic-gate 14357c478bd9Sstevel@tonic-gate /* NFSPROC3_MKDIR = 9 */ 14367c478bd9Sstevel@tonic-gate {xdr_nfslog_MKDIR3args, xdr_nfslog_MKDIR3res, TRUE}, 14377c478bd9Sstevel@tonic-gate 14387c478bd9Sstevel@tonic-gate /* NFSPROC3_SYMLINK = 10 */ 14397c478bd9Sstevel@tonic-gate {xdr_nfslog_SYMLINK3args, xdr_nfslog_SYMLINK3res, TRUE}, 14407c478bd9Sstevel@tonic-gate 14417c478bd9Sstevel@tonic-gate /* NFSPROC3_MKNOD = 11 */ 14427c478bd9Sstevel@tonic-gate {xdr_nfslog_MKNOD3args, xdr_nfslog_MKNOD3res, TRUE}, 14437c478bd9Sstevel@tonic-gate 14447c478bd9Sstevel@tonic-gate /* NFSPROC3_REMOVE = 12 */ 14457c478bd9Sstevel@tonic-gate {xdr_nfslog_REMOVE3args, xdr_nfslog_REMOVE3res, TRUE}, 14467c478bd9Sstevel@tonic-gate 14477c478bd9Sstevel@tonic-gate /* NFSPROC3_RMDIR = 13 */ 14487c478bd9Sstevel@tonic-gate {xdr_nfslog_RMDIR3args, xdr_nfslog_RMDIR3res, TRUE}, 14497c478bd9Sstevel@tonic-gate 14507c478bd9Sstevel@tonic-gate /* NFSPROC3_RENAME = 14 */ 14517c478bd9Sstevel@tonic-gate {xdr_nfslog_RENAME3args, xdr_nfslog_RENAME3res, TRUE}, 14527c478bd9Sstevel@tonic-gate 14537c478bd9Sstevel@tonic-gate /* NFSPROC3_LINK = 15 */ 14547c478bd9Sstevel@tonic-gate {xdr_nfslog_LINK3args, xdr_nfslog_LINK3res, TRUE}, 14557c478bd9Sstevel@tonic-gate 14567c478bd9Sstevel@tonic-gate /* NFSPROC3_READDIR = 16 */ 14577c478bd9Sstevel@tonic-gate {xdr_nfslog_READDIR3args, xdr_nfslog_READDIR3res, TRUE}, 14587c478bd9Sstevel@tonic-gate 14597c478bd9Sstevel@tonic-gate /* NFSPROC3_READDIRPLUS = 17 */ 14607c478bd9Sstevel@tonic-gate {xdr_nfslog_READDIRPLUS3args, xdr_nfslog_READDIRPLUS3res, TRUE}, 14617c478bd9Sstevel@tonic-gate 14627c478bd9Sstevel@tonic-gate /* NFSPROC3_FSSTAT = 18 */ 14637c478bd9Sstevel@tonic-gate {xdr_nfslog_FSSTAT3args, xdr_nfslog_FSSTAT3res, FALSE}, 14647c478bd9Sstevel@tonic-gate 14657c478bd9Sstevel@tonic-gate /* NFSPROC3_FSINFO = 19 */ 14667c478bd9Sstevel@tonic-gate {xdr_nfslog_FSINFO3args, xdr_nfslog_FSINFO3res, FALSE}, 14677c478bd9Sstevel@tonic-gate 14687c478bd9Sstevel@tonic-gate /* NFSPROC3_PATHCONF = 20 */ 14697c478bd9Sstevel@tonic-gate {xdr_nfslog_PATHCONF3args, xdr_nfslog_PATHCONF3res, FALSE}, 14707c478bd9Sstevel@tonic-gate 14717c478bd9Sstevel@tonic-gate /* NFSPROC3_COMMIT = 21 */ 14727c478bd9Sstevel@tonic-gate {xdr_nfslog_COMMIT3args, xdr_nfslog_COMMIT3res, FALSE}, 14737c478bd9Sstevel@tonic-gate }; 14747c478bd9Sstevel@tonic-gate 14757c478bd9Sstevel@tonic-gate static struct nfslog_proc_disp nfslog_proc_v1[] = { 14767c478bd9Sstevel@tonic-gate /* 14777c478bd9Sstevel@tonic-gate * NFSLOG VERSION 1 14787c478bd9Sstevel@tonic-gate */ 14797c478bd9Sstevel@tonic-gate 14807c478bd9Sstevel@tonic-gate /* NFSLOG_NULL = 0 */ 14817c478bd9Sstevel@tonic-gate {xdr_void, xdr_void, TRUE}, 14827c478bd9Sstevel@tonic-gate 14837c478bd9Sstevel@tonic-gate /* NFSLOG_SHARE = 1 */ 14847c478bd9Sstevel@tonic-gate {xdr_nfslog_sharefsargs, xdr_nfslog_sharefsres, TRUE}, 14857c478bd9Sstevel@tonic-gate 14867c478bd9Sstevel@tonic-gate /* NFSLOG_UNSHARE = 2 */ 14877c478bd9Sstevel@tonic-gate {xdr_nfslog_sharefsargs, xdr_nfslog_sharefsres, TRUE}, 14887c478bd9Sstevel@tonic-gate 14897c478bd9Sstevel@tonic-gate /* NFSLOG_LOOKUP = 3 */ 14907c478bd9Sstevel@tonic-gate {xdr_nfslog_diropargs3, xdr_nfslog_LOOKUP3res, TRUE}, 14917c478bd9Sstevel@tonic-gate 14927c478bd9Sstevel@tonic-gate /* NFSLOG_GETFH = 4 */ 14937c478bd9Sstevel@tonic-gate {xdr_nfslog_getfhargs, xdr_nfsstat, TRUE}, 14947c478bd9Sstevel@tonic-gate }; 14957c478bd9Sstevel@tonic-gate 14967c478bd9Sstevel@tonic-gate static struct nfslog_vers_disp nfslog_vers_disptable[] = { 14977c478bd9Sstevel@tonic-gate {sizeof (nfslog_proc_v2) / sizeof (nfslog_proc_v2[0]), 14987c478bd9Sstevel@tonic-gate nfslog_proc_v2}, 14997c478bd9Sstevel@tonic-gate {sizeof (nfslog_proc_v3) / sizeof (nfslog_proc_v3[0]), 15007c478bd9Sstevel@tonic-gate nfslog_proc_v3}, 15017c478bd9Sstevel@tonic-gate }; 15027c478bd9Sstevel@tonic-gate 15037c478bd9Sstevel@tonic-gate static struct nfslog_vers_disp nfslog_nfslog_vers_disptable[] = { 15047c478bd9Sstevel@tonic-gate {sizeof (nfslog_proc_v1) / sizeof (nfslog_proc_v1[0]), 15057c478bd9Sstevel@tonic-gate nfslog_proc_v1}, 15067c478bd9Sstevel@tonic-gate }; 15077c478bd9Sstevel@tonic-gate 15087c478bd9Sstevel@tonic-gate static struct nfslog_prog_disp nfslog_dispatch_table[] = { 15097c478bd9Sstevel@tonic-gate {NFS_PROGRAM, NFS_VERSMIN, 15107c478bd9Sstevel@tonic-gate (sizeof (nfslog_vers_disptable) / 15117c478bd9Sstevel@tonic-gate sizeof (nfslog_vers_disptable[0])), 15127c478bd9Sstevel@tonic-gate nfslog_vers_disptable}, 15137c478bd9Sstevel@tonic-gate 15147c478bd9Sstevel@tonic-gate {NFSLOG_PROGRAM, NFSLOG_VERSMIN, 15157c478bd9Sstevel@tonic-gate (sizeof (nfslog_nfslog_vers_disptable) / 15167c478bd9Sstevel@tonic-gate sizeof (nfslog_nfslog_vers_disptable[0])), 15177c478bd9Sstevel@tonic-gate nfslog_nfslog_vers_disptable}, 15187c478bd9Sstevel@tonic-gate }; 15197c478bd9Sstevel@tonic-gate 15207c478bd9Sstevel@tonic-gate static int nfslog_dispatch_table_arglen = sizeof (nfslog_dispatch_table) / 15217c478bd9Sstevel@tonic-gate sizeof (nfslog_dispatch_table[0]); 15227c478bd9Sstevel@tonic-gate 15237c478bd9Sstevel@tonic-gate /* 15247c478bd9Sstevel@tonic-gate * This function will determine the appropriate export info struct to use 15257c478bd9Sstevel@tonic-gate * and allocate a record id to be used in the written log buffer. 15267c478bd9Sstevel@tonic-gate * Usually this is a straightforward operation but the existence of the 15277c478bd9Sstevel@tonic-gate * multicomponent lookup and its semantics of crossing file system 15287c478bd9Sstevel@tonic-gate * boundaries add to the complexity. See the comments below... 15297c478bd9Sstevel@tonic-gate */ 15307c478bd9Sstevel@tonic-gate struct exportinfo * 15317c478bd9Sstevel@tonic-gate nfslog_get_exi( 15327c478bd9Sstevel@tonic-gate struct exportinfo *exi, 15337c478bd9Sstevel@tonic-gate struct svc_req *req, 15347c478bd9Sstevel@tonic-gate caddr_t res, 15357c478bd9Sstevel@tonic-gate unsigned int *nfslog_rec_id) 15367c478bd9Sstevel@tonic-gate { 15377c478bd9Sstevel@tonic-gate struct log_buffer *lb; 15387c478bd9Sstevel@tonic-gate struct exportinfo *exi_ret = NULL; 153927242a7cSthurlow fhandle_t *fh; 15407c478bd9Sstevel@tonic-gate nfs_fh3 *fh3; 15417c478bd9Sstevel@tonic-gate 15427c478bd9Sstevel@tonic-gate if (exi == NULL) 15437c478bd9Sstevel@tonic-gate return (NULL); 15447c478bd9Sstevel@tonic-gate 15457c478bd9Sstevel@tonic-gate /* 15467c478bd9Sstevel@tonic-gate * If the exi is marked for logging, allocate a record id and return 15477c478bd9Sstevel@tonic-gate */ 15487c478bd9Sstevel@tonic-gate if (exi->exi_export.ex_flags & EX_LOG) { 15497c478bd9Sstevel@tonic-gate lb = exi->exi_logbuffer; 15507c478bd9Sstevel@tonic-gate 15517c478bd9Sstevel@tonic-gate /* obtain the unique record id for the caller */ 15527c478bd9Sstevel@tonic-gate *nfslog_rec_id = atomic_add_32_nv(&lb->lb_rec_id, (int32_t)1); 15537c478bd9Sstevel@tonic-gate 15547c478bd9Sstevel@tonic-gate /* 15557c478bd9Sstevel@tonic-gate * The caller will expect to be able to exi_rele() it, 15567c478bd9Sstevel@tonic-gate * so exi->exi_count must be incremented before it can 15577c478bd9Sstevel@tonic-gate * be returned, to make it uniform with exi_ret->exi_count 15587c478bd9Sstevel@tonic-gate */ 15593ccecb66SThomas Haynes exi_hold(exi); 15607c478bd9Sstevel@tonic-gate return (exi); 15617c478bd9Sstevel@tonic-gate } 15627c478bd9Sstevel@tonic-gate 15637c478bd9Sstevel@tonic-gate if (exi != exi_public) 15647c478bd9Sstevel@tonic-gate return (NULL); 15657c478bd9Sstevel@tonic-gate 15667c478bd9Sstevel@tonic-gate /* 15677c478bd9Sstevel@tonic-gate * Here we have an exi that is not marked for logging. 15687c478bd9Sstevel@tonic-gate * It is possible that this request is a multicomponent lookup 15697c478bd9Sstevel@tonic-gate * that was done from the public file handle (not logged) and 15707c478bd9Sstevel@tonic-gate * the resulting file handle being returned to the client exists 15717c478bd9Sstevel@tonic-gate * in a file system that is being logged. If this is the case 15727c478bd9Sstevel@tonic-gate * we need to log this multicomponent lookup to the appropriate 15737c478bd9Sstevel@tonic-gate * log buffer. This will allow for the appropriate path name 15747c478bd9Sstevel@tonic-gate * mapping to occur at user level. 15757c478bd9Sstevel@tonic-gate */ 15767c478bd9Sstevel@tonic-gate if (req->rq_prog == NFS_PROGRAM) { 15777c478bd9Sstevel@tonic-gate switch (req->rq_vers) { 15787c478bd9Sstevel@tonic-gate case NFS_V3: 15797c478bd9Sstevel@tonic-gate if ((req->rq_proc == NFSPROC3_LOOKUP) && 15807c478bd9Sstevel@tonic-gate (((LOOKUP3res *)res)->status == NFS3_OK)) { 15817c478bd9Sstevel@tonic-gate fh3 = &((LOOKUP3res *)res)->res_u.ok.object; 158227242a7cSthurlow exi_ret = checkexport(&fh3->fh3_fsid, 1583fbd2e8e1SArne Jansen FH3TOXFIDP(fh3), NULL); 15847c478bd9Sstevel@tonic-gate } 15857c478bd9Sstevel@tonic-gate break; 15867c478bd9Sstevel@tonic-gate 15877c478bd9Sstevel@tonic-gate case NFS_VERSION: 15887c478bd9Sstevel@tonic-gate if ((req->rq_proc == RFS_LOOKUP) && 15897c478bd9Sstevel@tonic-gate (((struct nfsdiropres *) 15907c478bd9Sstevel@tonic-gate res)->dr_status == NFS_OK)) { 15919d39bb88Sbatschul fh = &((struct nfsdiropres *)res)-> 15929d39bb88Sbatschul dr_u.dr_drok_u.drok_fhandle; 159327242a7cSthurlow exi_ret = checkexport(&fh->fh_fsid, 1594fbd2e8e1SArne Jansen (fid_t *)&fh->fh_xlen, NULL); 15957c478bd9Sstevel@tonic-gate } 15967c478bd9Sstevel@tonic-gate break; 15977c478bd9Sstevel@tonic-gate default: 15987c478bd9Sstevel@tonic-gate break; 15997c478bd9Sstevel@tonic-gate } 16007c478bd9Sstevel@tonic-gate } 16017c478bd9Sstevel@tonic-gate 16027c478bd9Sstevel@tonic-gate if (exi_ret != NULL && exi_ret->exi_export.ex_flags & EX_LOG) { 16037c478bd9Sstevel@tonic-gate lb = exi_ret->exi_logbuffer; 16047c478bd9Sstevel@tonic-gate /* obtain the unique record id for the caller */ 16057c478bd9Sstevel@tonic-gate *nfslog_rec_id = atomic_add_32_nv(&lb->lb_rec_id, (int32_t)1); 16067c478bd9Sstevel@tonic-gate 16077c478bd9Sstevel@tonic-gate return (exi_ret); 16087c478bd9Sstevel@tonic-gate } 16097c478bd9Sstevel@tonic-gate return (NULL); 16107c478bd9Sstevel@tonic-gate } 16117c478bd9Sstevel@tonic-gate 16127c478bd9Sstevel@tonic-gate #ifdef DEBUG 16137c478bd9Sstevel@tonic-gate static long long rfslog_records_ignored = 0; 16147c478bd9Sstevel@tonic-gate #endif 16157c478bd9Sstevel@tonic-gate 16167c478bd9Sstevel@tonic-gate /* 16177c478bd9Sstevel@tonic-gate * nfslog_write_record - Fill in the record buffer for writing out. 16187c478bd9Sstevel@tonic-gate * If logrecp is null, log it, otherwise, malloc the record and return it. 16197c478bd9Sstevel@tonic-gate * 16207c478bd9Sstevel@tonic-gate * It is the responsibility of the caller to check whether this exportinfo 16217c478bd9Sstevel@tonic-gate * has logging enabled. 16227c478bd9Sstevel@tonic-gate * Note that nfslog_share_public_record() only needs to check for the 16237c478bd9Sstevel@tonic-gate * existence of at least one logbuffer to which the public filehandle record 16247c478bd9Sstevel@tonic-gate * needs to be logged. 16257c478bd9Sstevel@tonic-gate */ 16267c478bd9Sstevel@tonic-gate void 1627*aafcd32bSMarcel Telka nfslog_write_record(struct exportinfo *exi, struct svc_req *req, caddr_t args, 1628*aafcd32bSMarcel Telka caddr_t res, cred_t *cr, struct netbuf *pnb, unsigned int record_id, 1629*aafcd32bSMarcel Telka unsigned int which_buffers) 16307c478bd9Sstevel@tonic-gate { 16317c478bd9Sstevel@tonic-gate struct nfslog_prog_disp *progtable; /* prog struct */ 16327c478bd9Sstevel@tonic-gate struct nfslog_vers_disp *verstable; /* version struct */ 16337c478bd9Sstevel@tonic-gate struct nfslog_proc_disp *disp = NULL; /* proc struct */ 16347c478bd9Sstevel@tonic-gate int i, vers; 16357c478bd9Sstevel@tonic-gate void *log_cookie; /* for logrecord if */ 16367c478bd9Sstevel@tonic-gate caddr_t buffer; 16377c478bd9Sstevel@tonic-gate XDR xdrs; 16387c478bd9Sstevel@tonic-gate unsigned int final_size; 16397c478bd9Sstevel@tonic-gate int encode_ok; 16407c478bd9Sstevel@tonic-gate int alloc_indx; 16417c478bd9Sstevel@tonic-gate 16427c478bd9Sstevel@tonic-gate ASSERT(exi != NULL); ASSERT(req != NULL); ASSERT(args != NULL); 16437c478bd9Sstevel@tonic-gate ASSERT(res != NULL); ASSERT(cr != NULL); 16447c478bd9Sstevel@tonic-gate 16457c478bd9Sstevel@tonic-gate /* 16467c478bd9Sstevel@tonic-gate * Find program element 16477c478bd9Sstevel@tonic-gate * Search the list since program can not be used as index 16487c478bd9Sstevel@tonic-gate */ 16497c478bd9Sstevel@tonic-gate for (i = 0; (i < nfslog_dispatch_table_arglen); i++) { 16507c478bd9Sstevel@tonic-gate if (req->rq_prog == nfslog_dispatch_table[i].nfslog_dis_prog) 16517c478bd9Sstevel@tonic-gate break; 16527c478bd9Sstevel@tonic-gate } 16537c478bd9Sstevel@tonic-gate if (i >= nfslog_dispatch_table_arglen) { /* program not logged */ 16547c478bd9Sstevel@tonic-gate /* not an error */ 16557c478bd9Sstevel@tonic-gate return; 16567c478bd9Sstevel@tonic-gate } 16577c478bd9Sstevel@tonic-gate 16587c478bd9Sstevel@tonic-gate /* 16597c478bd9Sstevel@tonic-gate * Extract the dispatch functions based on program/version 16607c478bd9Sstevel@tonic-gate */ 16617c478bd9Sstevel@tonic-gate progtable = &nfslog_dispatch_table[i]; 16627c478bd9Sstevel@tonic-gate vers = req->rq_vers - progtable->nfslog_dis_versmin; 16637c478bd9Sstevel@tonic-gate verstable = &progtable->nfslog_dis_vers_table[vers]; 16647c478bd9Sstevel@tonic-gate disp = &verstable->nfslog_dis_proc_table[req->rq_proc]; 16657c478bd9Sstevel@tonic-gate 16667c478bd9Sstevel@tonic-gate if (!(exi->exi_export.ex_flags & EX_LOG_ALLOPS) && 16677c478bd9Sstevel@tonic-gate !disp->affects_transactions) { 16687c478bd9Sstevel@tonic-gate /* 16697c478bd9Sstevel@tonic-gate * Only interested in logging operations affecting 16707c478bd9Sstevel@tonic-gate * transaction generation. This is not one of them. 16717c478bd9Sstevel@tonic-gate */ 16727c478bd9Sstevel@tonic-gate #ifdef DEBUG 16737c478bd9Sstevel@tonic-gate rfslog_records_ignored++; 16747c478bd9Sstevel@tonic-gate #endif 16757c478bd9Sstevel@tonic-gate return; 16767c478bd9Sstevel@tonic-gate } 16777c478bd9Sstevel@tonic-gate 16787c478bd9Sstevel@tonic-gate switch (req->rq_prog) { 16797c478bd9Sstevel@tonic-gate case NFS_PROGRAM: 16807c478bd9Sstevel@tonic-gate switch (req->rq_vers) { 16817c478bd9Sstevel@tonic-gate case NFS_V3: 16827c478bd9Sstevel@tonic-gate switch (req->rq_proc) { 16837c478bd9Sstevel@tonic-gate case NFSPROC3_READDIRPLUS: 16847c478bd9Sstevel@tonic-gate alloc_indx = MEDIUM_INDX; 16857c478bd9Sstevel@tonic-gate break; 16867c478bd9Sstevel@tonic-gate default: 16877c478bd9Sstevel@tonic-gate alloc_indx = SMALL_INDX; 16887c478bd9Sstevel@tonic-gate break; 16897c478bd9Sstevel@tonic-gate } 16907c478bd9Sstevel@tonic-gate break; 16917c478bd9Sstevel@tonic-gate default: 16927c478bd9Sstevel@tonic-gate alloc_indx = SMALL_INDX; 16937c478bd9Sstevel@tonic-gate break; 16947c478bd9Sstevel@tonic-gate } 16957c478bd9Sstevel@tonic-gate break; 16967c478bd9Sstevel@tonic-gate case NFSLOG_PROGRAM: 16977c478bd9Sstevel@tonic-gate alloc_indx = MEDIUM_INDX; 16987c478bd9Sstevel@tonic-gate break; 16997c478bd9Sstevel@tonic-gate default: 17007c478bd9Sstevel@tonic-gate alloc_indx = SMALL_INDX; 17017c478bd9Sstevel@tonic-gate break; 17027c478bd9Sstevel@tonic-gate } 17037c478bd9Sstevel@tonic-gate 17047c478bd9Sstevel@tonic-gate do { 17057c478bd9Sstevel@tonic-gate encode_ok = FALSE; 17067c478bd9Sstevel@tonic-gate 17077c478bd9Sstevel@tonic-gate /* Pick the size to alloc; end of the road - return */ 17087c478bd9Sstevel@tonic-gate if (nfslog_mem_alloc[alloc_indx].size == (-1)) { 17097c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 17107c478bd9Sstevel@tonic-gate "NFSLOG: unable to encode record - prog=%d " 17117c478bd9Sstevel@tonic-gate "proc = %d", req->rq_prog, req->rq_proc); 17127c478bd9Sstevel@tonic-gate return; 17137c478bd9Sstevel@tonic-gate } 17147c478bd9Sstevel@tonic-gate 17157c478bd9Sstevel@tonic-gate buffer = nfslog_record_alloc(exi, alloc_indx, &log_cookie, 0); 17167c478bd9Sstevel@tonic-gate if (buffer == NULL) { 17177c478bd9Sstevel@tonic-gate /* Error processing - no space alloced */ 17187c478bd9Sstevel@tonic-gate rfs_log_bad++; 17197c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "NFSLOG: can't get record"); 17207c478bd9Sstevel@tonic-gate return; 17217c478bd9Sstevel@tonic-gate } 17227c478bd9Sstevel@tonic-gate 17237c478bd9Sstevel@tonic-gate xdrmem_create(&xdrs, buffer, 17247c478bd9Sstevel@tonic-gate nfslog_mem_alloc[alloc_indx].size, XDR_ENCODE); 17257c478bd9Sstevel@tonic-gate 17267c478bd9Sstevel@tonic-gate /* 17277c478bd9Sstevel@tonic-gate * Encode the header, args and results of the record 17287c478bd9Sstevel@tonic-gate */ 17297c478bd9Sstevel@tonic-gate if (xdr_nfslog_request_record(&xdrs, exi, req, cr, pnb, 17307c478bd9Sstevel@tonic-gate nfslog_mem_alloc[alloc_indx].size, record_id) && 17317c478bd9Sstevel@tonic-gate (*disp->xdrargs)(&xdrs, args) && 17327c478bd9Sstevel@tonic-gate (*disp->xdrres)(&xdrs, res)) { 17337c478bd9Sstevel@tonic-gate encode_ok = TRUE; 17347c478bd9Sstevel@tonic-gate 17357c478bd9Sstevel@tonic-gate rfs_log_good++; 17367c478bd9Sstevel@tonic-gate /* 17377c478bd9Sstevel@tonic-gate * Get the final size of the encoded 17387c478bd9Sstevel@tonic-gate * data and insert that length at the 17397c478bd9Sstevel@tonic-gate * beginning. 17407c478bd9Sstevel@tonic-gate */ 17417c478bd9Sstevel@tonic-gate final_size = xdr_getpos(&xdrs); 17427c478bd9Sstevel@tonic-gate xdr_setpos(&xdrs, 0); 17437c478bd9Sstevel@tonic-gate (void) xdr_u_int(&xdrs, &final_size); 17447c478bd9Sstevel@tonic-gate } else { 17457c478bd9Sstevel@tonic-gate /* Oops, the encode failed so we need to free memory */ 17467c478bd9Sstevel@tonic-gate nfslog_record_put(log_cookie, 0, FALSE, which_buffers); 17477c478bd9Sstevel@tonic-gate alloc_indx++; 17487c478bd9Sstevel@tonic-gate } 17497c478bd9Sstevel@tonic-gate 17507c478bd9Sstevel@tonic-gate } while (encode_ok == FALSE); 17517c478bd9Sstevel@tonic-gate 17527c478bd9Sstevel@tonic-gate 17537c478bd9Sstevel@tonic-gate /* 17547c478bd9Sstevel@tonic-gate * Take the final log record and put it in the log file. 17557c478bd9Sstevel@tonic-gate * This may be queued to the file internally and written 17567c478bd9Sstevel@tonic-gate * later unless the last parameter is TRUE. 17577c478bd9Sstevel@tonic-gate * If the record_id is 0 then this is most likely a share/unshare 17587c478bd9Sstevel@tonic-gate * request and it should be written synchronously to the log file. 17597c478bd9Sstevel@tonic-gate */ 17609d39bb88Sbatschul nfslog_record_put(log_cookie, 17619d39bb88Sbatschul final_size, (record_id == 0), which_buffers); 17627c478bd9Sstevel@tonic-gate } 17637c478bd9Sstevel@tonic-gate 17647c478bd9Sstevel@tonic-gate static char * 17657c478bd9Sstevel@tonic-gate get_publicfh_path(int *alloc_length) 17667c478bd9Sstevel@tonic-gate { 17677c478bd9Sstevel@tonic-gate extern struct exportinfo *exi_public; 17687c478bd9Sstevel@tonic-gate char *pubpath; 17697c478bd9Sstevel@tonic-gate 17707c478bd9Sstevel@tonic-gate rw_enter(&exported_lock, RW_READER); 17717c478bd9Sstevel@tonic-gate 17727c478bd9Sstevel@tonic-gate *alloc_length = exi_public->exi_export.ex_pathlen + 1; 17737c478bd9Sstevel@tonic-gate pubpath = kmem_alloc(*alloc_length, KM_SLEEP); 17747c478bd9Sstevel@tonic-gate 17757c478bd9Sstevel@tonic-gate (void) strcpy(pubpath, exi_public->exi_export.ex_path); 17767c478bd9Sstevel@tonic-gate 17777c478bd9Sstevel@tonic-gate rw_exit(&exported_lock); 17787c478bd9Sstevel@tonic-gate 17797c478bd9Sstevel@tonic-gate return (pubpath); 17807c478bd9Sstevel@tonic-gate } 17817c478bd9Sstevel@tonic-gate 17827c478bd9Sstevel@tonic-gate static void 17837c478bd9Sstevel@tonic-gate log_public_record(struct exportinfo *exi, cred_t *cr) 17847c478bd9Sstevel@tonic-gate { 17857c478bd9Sstevel@tonic-gate struct svc_req req; 17867c478bd9Sstevel@tonic-gate struct netbuf nb = {0, 0, NULL}; 17877c478bd9Sstevel@tonic-gate int free_length = 0; 17887c478bd9Sstevel@tonic-gate diropargs3 args; 17897c478bd9Sstevel@tonic-gate LOOKUP3res res; 17907c478bd9Sstevel@tonic-gate 17917c478bd9Sstevel@tonic-gate bzero(&req, sizeof (req)); 17927c478bd9Sstevel@tonic-gate req.rq_prog = NFSLOG_PROGRAM; 17937c478bd9Sstevel@tonic-gate req.rq_vers = NFSLOG_VERSION; 17947c478bd9Sstevel@tonic-gate req.rq_proc = NFSLOG_LOOKUP; 17957c478bd9Sstevel@tonic-gate req.rq_cred.oa_flavor = AUTH_NONE; 17967c478bd9Sstevel@tonic-gate 17977c478bd9Sstevel@tonic-gate bzero(&args, sizeof (diropargs3)); 17987c478bd9Sstevel@tonic-gate bzero(&res, sizeof (LOOKUP3res)); 17997c478bd9Sstevel@tonic-gate 18007c478bd9Sstevel@tonic-gate args.dir.fh3_length = 0; 18017c478bd9Sstevel@tonic-gate if ((args.name = get_publicfh_path(&free_length)) == NULL) 18027c478bd9Sstevel@tonic-gate return; 18037c478bd9Sstevel@tonic-gate args.dirp = &args.dir; 18047c478bd9Sstevel@tonic-gate 18057c478bd9Sstevel@tonic-gate res.status = NFS3_OK; 18067c478bd9Sstevel@tonic-gate res.res_u.ok.object.fh3_length = 0; 18077c478bd9Sstevel@tonic-gate 18087c478bd9Sstevel@tonic-gate /* 18097c478bd9Sstevel@tonic-gate * Calling this function with the exi_public 18107c478bd9Sstevel@tonic-gate * will have the effect of appending the record 18117c478bd9Sstevel@tonic-gate * to each of the open log buffers 18127c478bd9Sstevel@tonic-gate */ 18137c478bd9Sstevel@tonic-gate nfslog_write_record(exi, &req, 18147c478bd9Sstevel@tonic-gate (caddr_t)&args, (caddr_t)&res, cr, &nb, 0, NFSLOG_ALL_BUFFERS); 18157c478bd9Sstevel@tonic-gate 18167c478bd9Sstevel@tonic-gate kmem_free(args.name, free_length); 18177c478bd9Sstevel@tonic-gate } 18187c478bd9Sstevel@tonic-gate 18197c478bd9Sstevel@tonic-gate /* 18207c478bd9Sstevel@tonic-gate * nfslog_share_record - logs a share request. 18217c478bd9Sstevel@tonic-gate * This is not an NFS request, but we pretend here... 18227c478bd9Sstevel@tonic-gate */ 18237c478bd9Sstevel@tonic-gate void 18247c478bd9Sstevel@tonic-gate nfslog_share_record(struct exportinfo *exi, cred_t *cr) 18257c478bd9Sstevel@tonic-gate { 18267c478bd9Sstevel@tonic-gate struct svc_req req; 18277c478bd9Sstevel@tonic-gate int res = 0; 18287c478bd9Sstevel@tonic-gate struct netbuf nb = {0, 0, NULL}; 18297c478bd9Sstevel@tonic-gate 18307c478bd9Sstevel@tonic-gate ASSERT(exi != NULL); 18317c478bd9Sstevel@tonic-gate 18327c478bd9Sstevel@tonic-gate if (nfslog_buffer_list == NULL) 18337c478bd9Sstevel@tonic-gate return; 18347c478bd9Sstevel@tonic-gate 18357c478bd9Sstevel@tonic-gate if (exi->exi_export.ex_flags & EX_LOG) { 18367c478bd9Sstevel@tonic-gate bzero(&req, sizeof (req)); 18377c478bd9Sstevel@tonic-gate req.rq_prog = NFSLOG_PROGRAM; 18387c478bd9Sstevel@tonic-gate req.rq_vers = NFSLOG_VERSION; 18397c478bd9Sstevel@tonic-gate req.rq_proc = NFSLOG_SHARE; 18407c478bd9Sstevel@tonic-gate req.rq_cred.oa_flavor = AUTH_NONE; 18419d39bb88Sbatschul nfslog_write_record(exi, &req, (caddr_t)exi, (caddr_t)&res, cr, 18427c478bd9Sstevel@tonic-gate &nb, 0, NFSLOG_ONE_BUFFER); 18437c478bd9Sstevel@tonic-gate } 18447c478bd9Sstevel@tonic-gate 18457c478bd9Sstevel@tonic-gate log_public_record(exi, cr); 18467c478bd9Sstevel@tonic-gate } 18477c478bd9Sstevel@tonic-gate 18487c478bd9Sstevel@tonic-gate /* 18497c478bd9Sstevel@tonic-gate * nfslog_unshare_record - logs an unshare request. 18507c478bd9Sstevel@tonic-gate * This is not an NFS request, but we pretend here... 18517c478bd9Sstevel@tonic-gate */ 18527c478bd9Sstevel@tonic-gate void 18537c478bd9Sstevel@tonic-gate nfslog_unshare_record(struct exportinfo *exi, cred_t *cr) 18547c478bd9Sstevel@tonic-gate { 18557c478bd9Sstevel@tonic-gate struct svc_req req; 18567c478bd9Sstevel@tonic-gate int res = 0; 18577c478bd9Sstevel@tonic-gate struct netbuf nb = {0, 0, NULL}; 18587c478bd9Sstevel@tonic-gate 18597c478bd9Sstevel@tonic-gate ASSERT(exi != NULL); 18607c478bd9Sstevel@tonic-gate ASSERT(exi->exi_export.ex_flags & EX_LOG); 18617c478bd9Sstevel@tonic-gate 18627c478bd9Sstevel@tonic-gate bzero(&req, sizeof (req)); 18637c478bd9Sstevel@tonic-gate req.rq_prog = NFSLOG_PROGRAM; 18647c478bd9Sstevel@tonic-gate req.rq_vers = NFSLOG_VERSION; 18657c478bd9Sstevel@tonic-gate req.rq_proc = NFSLOG_UNSHARE; 18667c478bd9Sstevel@tonic-gate req.rq_cred.oa_flavor = AUTH_NONE; 18677c478bd9Sstevel@tonic-gate nfslog_write_record(exi, &req, 18687c478bd9Sstevel@tonic-gate (caddr_t)exi, (caddr_t)&res, cr, &nb, 0, NFSLOG_ONE_BUFFER); 18697c478bd9Sstevel@tonic-gate } 18707c478bd9Sstevel@tonic-gate 18717c478bd9Sstevel@tonic-gate 18727c478bd9Sstevel@tonic-gate void 1873*aafcd32bSMarcel Telka nfslog_getfh(struct exportinfo *exi, fhandle *fh, char *fname, enum uio_seg seg, 18747c478bd9Sstevel@tonic-gate cred_t *cr) 18757c478bd9Sstevel@tonic-gate { 18767c478bd9Sstevel@tonic-gate struct svc_req req; 18777c478bd9Sstevel@tonic-gate int res = 0; 18787c478bd9Sstevel@tonic-gate struct netbuf nb = {0, 0, NULL}; 18797c478bd9Sstevel@tonic-gate int error = 0; 18807c478bd9Sstevel@tonic-gate char *namebuf; 18817c478bd9Sstevel@tonic-gate size_t len; 18827c478bd9Sstevel@tonic-gate nfslog_getfhargs gfh; 18837c478bd9Sstevel@tonic-gate 18847c478bd9Sstevel@tonic-gate ASSERT(exi != NULL); 18857c478bd9Sstevel@tonic-gate ASSERT(exi->exi_export.ex_flags & EX_LOG); 18867c478bd9Sstevel@tonic-gate 18877c478bd9Sstevel@tonic-gate bzero(&req, sizeof (req)); 18887c478bd9Sstevel@tonic-gate req.rq_prog = NFSLOG_PROGRAM; 18897c478bd9Sstevel@tonic-gate req.rq_vers = NFSLOG_VERSION; 18907c478bd9Sstevel@tonic-gate req.rq_proc = NFSLOG_GETFH; 18917c478bd9Sstevel@tonic-gate req.rq_cred.oa_flavor = AUTH_NONE; 18927c478bd9Sstevel@tonic-gate 18937c478bd9Sstevel@tonic-gate namebuf = kmem_alloc(MAXPATHLEN + 4, KM_SLEEP); 18947c478bd9Sstevel@tonic-gate if (seg == UIO_USERSPACE) { 18957c478bd9Sstevel@tonic-gate error = copyinstr(fname, namebuf, MAXPATHLEN, &len); 18967c478bd9Sstevel@tonic-gate } else { 18977c478bd9Sstevel@tonic-gate error = copystr(fname, namebuf, MAXPATHLEN, &len); 18987c478bd9Sstevel@tonic-gate } 18997c478bd9Sstevel@tonic-gate 19007c478bd9Sstevel@tonic-gate if (!error) { 19017c478bd9Sstevel@tonic-gate gfh.gfh_fh_buf = *fh; 19027c478bd9Sstevel@tonic-gate gfh.gfh_path = namebuf; 19037c478bd9Sstevel@tonic-gate 19049d39bb88Sbatschul nfslog_write_record(exi, &req, (caddr_t)&gfh, (caddr_t)&res, 19059d39bb88Sbatschul cr, &nb, 0, NFSLOG_ONE_BUFFER); 19067c478bd9Sstevel@tonic-gate } 19077c478bd9Sstevel@tonic-gate kmem_free(namebuf, MAXPATHLEN + 4); 19087c478bd9Sstevel@tonic-gate } 1909