github.com/swiftstack/ProxyFS@v0.0.0-20210203235616-4017c267d62f/evtlog/config.go (about)

     1  // Copyright (c) 2015-2021, NVIDIA CORPORATION.
     2  // SPDX-License-Identifier: Apache-2.0
     3  
     4  package evtlog
     5  
     6  import (
     7  	"fmt"
     8  	"syscall"
     9  	"time"
    10  
    11  	"github.com/swiftstack/ProxyFS/conf"
    12  	"github.com/swiftstack/ProxyFS/logger"
    13  	"github.com/swiftstack/ProxyFS/trackedlock"
    14  	"github.com/swiftstack/ProxyFS/transitions"
    15  )
    16  
    17  // #include <errno.h>
    18  // #include <stdint.h>
    19  // #include <sys/ipc.h>
    20  // #include <sys/shm.h>
    21  // #include <sys/types.h>
    22  //
    23  // uintptr_t shmat_returning_uintptr(int shmid, uintptr_t shmaddr, int shmflg) {
    24  //     void *shmat_return;
    25  //     shmat_return = shmat(shmid, (void *)shmaddr, shmflg);
    26  //     return (uintptr_t)shmat_return;
    27  // }
    28  //
    29  // int shmdt_returning_errno(uintptr_t shmaddr) {
    30  //     int shmdt_return;
    31  //     shmdt_return = shmdt((void *)shmaddr);
    32  //     if (0 == shmdt_return) {
    33  //         return 0;
    34  //     } else {
    35  //         return errno;
    36  //     }
    37  // }
    38  import "C"
    39  
    40  type globalsStruct struct {
    41  	trackedlock.Mutex       // While there can only ever be a single Consumer, multiple Producers are possible (within the same process)
    42  	eventLogEnabled         bool
    43  	eventLogBufferKey       uint64
    44  	eventLogBufferLength    uint64
    45  	eventLogLockMinBackoff  time.Duration
    46  	eventLogLockMaxBackoff  time.Duration
    47  	shmKey                  C.key_t
    48  	shmSize                 C.size_t
    49  	shmID                   C.int
    50  	shmAddr                 C.uintptr_t
    51  	shmKnownToBeInitialized bool // Iindicates that this instance "knows" initialization has completed
    52  }
    53  
    54  var globals globalsStruct
    55  
    56  type eventLogConfigSettings struct {
    57  	eventLogEnabled        bool
    58  	eventLogBufferKey      uint64
    59  	eventLogBufferLength   uint64
    60  	eventLogLockMinBackoff time.Duration
    61  	eventLogLockMaxBackoff time.Duration
    62  }
    63  
    64  func init() {
    65  	transitions.Register("evtlog", &globals)
    66  }
    67  
    68  // Extract the settings from the confMap and perform minimal sanity checking
    69  //
    70  func parseConfMap(confMap conf.ConfMap) (settings eventLogConfigSettings, err error) {
    71  	settings.eventLogEnabled, err = confMap.FetchOptionValueBool("EventLog", "Enabled")
    72  	if (nil != err) || !settings.eventLogEnabled {
    73  		// ignore parsing errors and treat this as logging disabled
    74  		settings.eventLogEnabled = false
    75  		err = nil
    76  		return
    77  	}
    78  
    79  	settings.eventLogBufferKey, err = confMap.FetchOptionValueUint64("EventLog", "BufferKey")
    80  	if nil != err {
    81  		err = fmt.Errorf("confMap.FetchOptionValueUint32(\"EventLog\", \"BufferKey\") failed: %v", err)
    82  		return
    83  	}
    84  
    85  	settings.eventLogBufferLength, err = confMap.FetchOptionValueUint64("EventLog", "BufferLength")
    86  	if nil != err {
    87  		err = fmt.Errorf("confMap.FetchOptionValueUint64(\"EventLog\", \"BufferLength\") failed: %v", err)
    88  		return
    89  	}
    90  	if 0 != (globals.eventLogBufferLength % 4) {
    91  		err = fmt.Errorf("confMap.FetchOptionValueUint64(\"EventLog\", \"BufferLength\") not divisible by 4")
    92  		return
    93  	}
    94  
    95  	settings.eventLogLockMinBackoff, err = confMap.FetchOptionValueDuration("EventLog", "MinBackoff")
    96  	if nil != err {
    97  		err = fmt.Errorf("confMap.FetchOptionValueDuration(\"EventLog\", \"MinBackoff\") failed: %v", err)
    98  		return
    99  	}
   100  
   101  	settings.eventLogLockMaxBackoff, err = confMap.FetchOptionValueDuration("EventLog", "MaxBackoff")
   102  	if nil != err {
   103  		err = fmt.Errorf("confMap.FetchOptionValueDuration(\"EventLog\", \"MaxBackoff\") failed: %v", err)
   104  		return
   105  	}
   106  
   107  	return
   108  }
   109  
   110  func (dummy *globalsStruct) Up(confMap conf.ConfMap) (err error) {
   111  	var settings eventLogConfigSettings
   112  
   113  	settings, err = parseConfMap(confMap)
   114  	if nil != err {
   115  		return
   116  	}
   117  
   118  	logger.Infof("evtlog.Up(): event logging is %v", settings.eventLogEnabled)
   119  
   120  	globals.eventLogEnabled = settings.eventLogEnabled
   121  	if !globals.eventLogEnabled {
   122  		return
   123  	}
   124  
   125  	globals.eventLogBufferKey = settings.eventLogBufferKey
   126  	globals.eventLogBufferLength = settings.eventLogBufferLength
   127  	globals.eventLogLockMinBackoff = settings.eventLogLockMinBackoff
   128  	globals.eventLogLockMaxBackoff = settings.eventLogLockMaxBackoff
   129  
   130  	err = enableLogging()
   131  	return
   132  }
   133  
   134  func (dummy *globalsStruct) VolumeGroupCreated(confMap conf.ConfMap, volumeGroupName string, activePeer string, virtualIPAddr string) (err error) {
   135  	return nil
   136  }
   137  func (dummy *globalsStruct) VolumeGroupMoved(confMap conf.ConfMap, volumeGroupName string, activePeer string, virtualIPAddr string) (err error) {
   138  	return nil
   139  }
   140  func (dummy *globalsStruct) VolumeGroupDestroyed(confMap conf.ConfMap, volumeGroupName string) (err error) {
   141  	return nil
   142  }
   143  func (dummy *globalsStruct) VolumeCreated(confMap conf.ConfMap, volumeName string, volumeGroupName string) (err error) {
   144  	return nil
   145  }
   146  func (dummy *globalsStruct) VolumeMoved(confMap conf.ConfMap, volumeName string, volumeGroupName string) (err error) {
   147  	return nil
   148  }
   149  func (dummy *globalsStruct) VolumeDestroyed(confMap conf.ConfMap, volumeName string) (err error) {
   150  	return nil
   151  }
   152  func (dummy *globalsStruct) ServeVolume(confMap conf.ConfMap, volumeName string) (err error) {
   153  	return nil
   154  }
   155  func (dummy *globalsStruct) UnserveVolume(confMap conf.ConfMap, volumeName string) (err error) {
   156  	return nil
   157  }
   158  func (dummy *globalsStruct) VolumeToBeUnserved(confMap conf.ConfMap, volumeName string) (err error) {
   159  	return nil
   160  }
   161  func (dummy *globalsStruct) SignaledStart(confMap conf.ConfMap) (err error) {
   162  	return nil
   163  }
   164  
   165  func (dummy *globalsStruct) SignaledFinish(confMap conf.ConfMap) (err error) {
   166  	var settings eventLogConfigSettings
   167  
   168  	settings, err = parseConfMap(confMap)
   169  	if nil != err {
   170  		return
   171  	}
   172  
   173  	logger.Infof("evtlog.Signaled(): event logging is now %v (was %v)", settings.eventLogEnabled, globals.eventLogEnabled)
   174  
   175  	if !settings.eventLogEnabled {
   176  		if !globals.eventLogEnabled {
   177  			// was disabled and still is; no work to do
   178  			return
   179  		}
   180  
   181  		// was enabled but is now disabled
   182  		err = disableLogging()
   183  		return
   184  	}
   185  
   186  	// event logging will be enabled
   187  	//
   188  	// if it was enabled previously certain settings cannot be changed
   189  	if globals.eventLogEnabled {
   190  		if settings.eventLogBufferKey != globals.eventLogBufferKey {
   191  			err = fmt.Errorf("confMap[EventLog][BufferKey] not modifable without a restart")
   192  			return
   193  		}
   194  		if settings.eventLogBufferLength != globals.eventLogBufferLength {
   195  			err = fmt.Errorf("confMap[EventLog][BufferLength] not modifable without a restart")
   196  			return
   197  		}
   198  	}
   199  
   200  	globals.eventLogEnabled = settings.eventLogEnabled
   201  	globals.eventLogBufferKey = settings.eventLogBufferKey
   202  	globals.eventLogBufferLength = settings.eventLogBufferLength
   203  	globals.eventLogLockMinBackoff = settings.eventLogLockMinBackoff
   204  	globals.eventLogLockMaxBackoff = settings.eventLogLockMaxBackoff
   205  
   206  	err = enableLogging()
   207  	return
   208  }
   209  
   210  func (dummy *globalsStruct) Down(confMap conf.ConfMap) (err error) {
   211  	if globals.eventLogEnabled {
   212  		err = disableLogging()
   213  	}
   214  
   215  	return
   216  }
   217  
   218  func enableLogging() (err error) {
   219  	var (
   220  		rmidResult                    C.int
   221  		errno                         error
   222  		sharedMemoryObjectPermissions C.int
   223  	)
   224  
   225  	globals.shmKey = C.key_t(globals.eventLogBufferKey)
   226  	globals.shmSize = C.size_t(globals.eventLogBufferLength)
   227  
   228  	sharedMemoryObjectPermissions = 0 |
   229  		syscall.S_IRUSR |
   230  		syscall.S_IWUSR |
   231  		syscall.S_IRGRP |
   232  		syscall.S_IWGRP |
   233  		syscall.S_IROTH |
   234  		syscall.S_IWOTH
   235  
   236  	globals.shmID, errno = C.shmget(globals.shmKey, globals.shmSize, C.IPC_CREAT|sharedMemoryObjectPermissions)
   237  
   238  	if C.int(-1) == globals.shmID {
   239  		globals.eventLogEnabled = false
   240  		err = fmt.Errorf("C.shmget(globals.shmKey, globals.shmSize, C.IPC_CREAT) failed with errno: %v", errno)
   241  		return
   242  	}
   243  
   244  	globals.shmAddr = C.shmat_returning_uintptr(globals.shmID, C.uintptr_t(0), C.int(0))
   245  
   246  	if ^C.uintptr_t(0) == globals.shmAddr {
   247  		globals.eventLogEnabled = false
   248  		rmidResult = C.shmctl(globals.shmID, C.IPC_RMID, nil)
   249  		if C.int(-1) == rmidResult {
   250  			err = fmt.Errorf("C.shmat_returning_uintptr(globals.shmID, C.uintptr_t(0), C.int(0)) then C.shmctl(globals.shmID, C.IPC_RMID, nil) failed")
   251  			return
   252  		}
   253  		err = fmt.Errorf("C.shmat_returning_uintptr(globals.shmID, C.uintptr_t(0), C.int(0)) failed")
   254  		return
   255  	}
   256  
   257  	globals.eventLogEnabled = true
   258  
   259  	err = nil
   260  	return
   261  }
   262  
   263  func disableLogging() (err error) {
   264  	var (
   265  		shmdtErrnoReturn syscall.Errno
   266  		shmdtIntReturn   C.int
   267  	)
   268  
   269  	globals.eventLogEnabled = false
   270  
   271  	shmdtIntReturn = C.shmdt_returning_errno(globals.shmAddr)
   272  	if C.int(0) != shmdtIntReturn {
   273  		shmdtErrnoReturn = syscall.Errno(shmdtIntReturn)
   274  		err = fmt.Errorf("C.shmdt() returned non-zero failure... errno: %v", shmdtErrnoReturn.Error())
   275  		return
   276  	}
   277  
   278  	err = nil
   279  	return
   280  }