self.inst = None
self.addr = None
- def mount(self, mount_path=None, mount_fs_name=None, mountpoint=None):
+ def mount(self, mount_path=None, mount_fs_name=None, mountpoint=None, mount_options=[]):
if mountpoint is not None:
self.mountpoint = mountpoint
self.setupfs(name=mount_fs_name)
try:
- return self._mount(mount_path, mount_fs_name)
+ return self._mount(mount_path, mount_fs_name, mount_options)
except RuntimeError:
# Catch exceptions by the mount() logic (i.e. not remote command
# failures) and ensure the mount is not left half-up.
self.umount_wait(force=True)
raise
- def _mount(self, mount_path, mount_fs_name):
+ def _mount(self, mount_path, mount_fs_name, mount_options):
log.info("Client client.%s config is %s" % (self.client_id, self.client_config))
daemon_signal = 'kill'
if mount_fs_name is not None:
fuse_cmd += ["--client_mds_namespace={0}".format(mount_fs_name)]
+ fuse_cmd += mount_options
+
fuse_cmd += [
'--name', 'client.{id}'.format(id=self.client_id),
# TODO ceph-fuse doesn't understand dash dash '--',
self.ipmi_password = ipmi_password
self.ipmi_domain = ipmi_domain
- def mount(self, mount_path=None, mount_fs_name=None, mountpoint=None):
+ def mount(self, mount_path=None, mount_fs_name=None, mountpoint=None, mount_options=[]):
if mountpoint is not None:
self.mountpoint = mountpoint
self.setupfs(name=mount_fs_name)
if mount_fs_name is not None:
opts += ",mds_namespace={0}".format(mount_fs_name)
+ for mount_opt in mount_options :
+ opts += ",{0}".format(mount_opt)
+
self.client_remote.run(
args=[
'sudo',
self.fs.wait_for_daemons()
log.info('Ready to start {}...'.format(type(self).__name__))
- def mount(self, mount_path=None, mount_fs_name=None, mountpoint=None):
+ def mount(self, mount_path=None, mount_fs_name=None, mountpoint=None, mount_options=[]):
raise NotImplementedError()
def umount(self):
import re
import os
+from teuthology.orchestra import run
from teuthology.orchestra.run import CommandFailedError, ConnectionLostError
from tasks.cephfs.fuse_mount import FuseMount
from tasks.cephfs.cephfs_test_case import CephFSTestCase
self.assert_session_count(1)
self.mount_a.kill_cleanup()
+
+ def test_reconnect_after_blacklisted(self):
+ """
+ Test reconnect after blacklisted.
+ - writing to a fd that was opened before blacklist should return -EBADF
+ - reading/writing to a file with lost file locks should return -EIO
+ - readonly fd should continue to work
+ """
+
+ self.mount_a.umount_wait()
+
+ if isinstance(self.mount_a, FuseMount):
+ self.skipTest("Not implemented in FUSE client yet")
+ else:
+ try:
+ self.mount_a.mount(mount_options=['recover_session=clean'])
+ except CommandFailedError:
+ self.mount_a.kill_cleanup()
+ self.skipTest("Not implemented in current kernel")
+
+ self.mount_a.wait_until_mounted()
+
+ path = os.path.join(self.mount_a.mountpoint, 'testfile_reconnect_after_blacklisted')
+ pyscript = dedent("""
+ import os
+ import sys
+ import fcntl
+ import errno
+ import time
+
+ fd1 = os.open("{path}.1", os.O_RDWR | os.O_CREAT, 0O666)
+ fd2 = os.open("{path}.1", os.O_RDONLY)
+ fd3 = os.open("{path}.2", os.O_RDWR | os.O_CREAT, 0O666)
+ fd4 = os.open("{path}.2", os.O_RDONLY)
+
+ os.write(fd1, b'content')
+ os.read(fd2, 1);
+
+ os.write(fd3, b'content')
+ os.read(fd4, 1);
+ fcntl.flock(fd4, fcntl.LOCK_SH | fcntl.LOCK_NB)
+
+ print("blacklist")
+ sys.stdout.flush()
+
+ sys.stdin.readline()
+
+ # wait for mds to close session
+ time.sleep(10);
+
+ # trigger 'open session' message. kclient relies on 'session reject' message
+ # to detect if itself is blacklisted
+ try:
+ os.stat("{path}.1")
+ except:
+ pass
+
+ # wait for auto reconnect
+ time.sleep(10);
+
+ try:
+ os.write(fd1, b'content')
+ except OSError as e:
+ if e.errno != errno.EBADF:
+ raise
+ else:
+ raise RuntimeError("write() failed to raise error")
+
+ os.read(fd2, 1);
+
+ try:
+ os.read(fd4, 1)
+ except OSError as e:
+ if e.errno != errno.EIO:
+ raise
+ else:
+ raise RuntimeError("read() failed to raise error")
+ """).format(path=path)
+ rproc = self.mount_a.client_remote.run(
+ args=['sudo', 'python3', '-c', pyscript],
+ wait=False, stdin=run.PIPE, stdout=run.PIPE)
+
+ rproc.stdout.readline()
+
+ mount_a_client_id = self.mount_a.get_global_id()
+ self.fs.mds_asok(['session', 'evict', "%s" % mount_a_client_id])
+
+ rproc.stdin.writelines(['done\n'])
+ rproc.stdin.flush()
+
+ rproc.wait()
+ self.assertEqual(rproc.exitstatus, 0)
rproc.wait()
self.mounted = False
- def mount(self, mount_path=None, mount_fs_name=None):
+ def mount(self, mount_path=None, mount_fs_name=None, mount_options=[]):
self.setupfs(name=mount_fs_name)
log.info('Mounting kclient client.{id} at {remote} {mnt}...'.format(
if mount_fs_name is not None:
opts += ",mds_namespace={0}".format(mount_fs_name)
+ for mount_opt in mount_options:
+ opts += ",{0}".format(mount_opt)
+
self.client_remote.run(
args=[
'sudo',
if self.is_mounted():
super(LocalFuseMount, self).umount()
- def mount(self, mount_path=None, mount_fs_name=None, mountpoint=None):
+ def mount(self, mount_path=None, mount_fs_name=None, mountpoint=None, mount_options=[]):
if mountpoint is not None:
self.mountpoint = mountpoint
self.setupfs(name=mount_fs_name)
if mount_fs_name is not None:
prefix += ["--client_mds_namespace={0}".format(mount_fs_name)]
+ prefix += mount_options;
+
self.fuse_daemon = self.client_remote.run(args=
prefix + [
"-f",