open-iscsi / configshell-fb

configshell with additional modifications, see README
Apache License 2.0
28 stars 37 forks source link

Execute targetcli commands concurrently raise EOFError #60

Open zoumingzhe opened 3 years ago

zoumingzhe commented 3 years ago

Hello, the following error occur intermittently when 10 targetcli commands are executed concurrently.

Traceback (most recent call last):
  File "/usr/bin/targetcli", line 329, in <module>
    main()
  File "/usr/bin/targetcli", line 254, in main
    shell = TargetCLI(getenv("TARGETCLI_HOME", '~/.targetcli'))
  File "/usr/lib/python2.7/site-packages/configshell_fb/shell.py", line 176, in __init__
    self.prefs.load()
  File "/usr/lib/python2.7/site-packages/configshell_fb/prefs.py", line 150, in load
    self._prefs = six.moves.cPickle.load(fsock)
EOFError
zoumingzhe commented 3 years ago

I think save in class Prefs used the wrong lock type 'fcntl.LOCK_UN'. Please see pull https://github.com/open-iscsi/configshell-fb/pull/43 for details. Then, call open via 'wb' will truncate the file without lock protection, if load prefs.bin at the same time, maybe read empty prefs.bin and cause EOFError with very low probability.

    def save(self, filename=None):
        '''
        Saves the preferences to disk. If filename is not specified,
        use the default one if it is set, else do nothing.
        @param filename: Optional alternate file to use.
        @type filename: str
        '''
        if filename is None:
            filename = self.filename

        if filename is not None:
            fsock = open(filename, 'wb')
            fcntl.lockf(fsock, fcntl.LOCK_UN)
            try:
                six.moves.cPickle.dump(self._prefs, fsock, 2)
            finally:
                fsock.close()

    def load(self, filename=None):
        '''
        Loads the preferences from file. Use either the supplied filename,
        or the default one if set. Else, do nothing.
        '''
        if filename is None:
            filename = self.filename

        if filename is not None and os.path.exists(filename):
            fsock = open(filename, 'rb')
            fcntl.lockf(fsock, fcntl.LOCK_SH)
            try:
                self._prefs = six.moves.cPickle.load(fsock)
            finally:
                fsock.close()