[PATCH] Add tmpfs support (#918621)
Martin Kolman
mkolman at redhat.com
Thu Sep 26 16:56:19 UTC 2013
Add support for creating tmpfs mounts, mounting them
and adding them to fstab.
Tmpfs is a filesystem that lives in the Kernel page cache
and stores data primarily in RAM and in swap once RAM runs out.
Data stored on tmpfs mounts will not survive a system
reboot/crash/shutdown.
About tmpfs mount size:
- if no size is specified, the size will be 50% by default
- if size is specified, the mount will have this size
-> there is no limit on the size on tmpfs mounts
-> just note that once it fills RAM (and any swap),
the system will grind to a halt
- grow and maxsize are supported
-> just using grow without maxsize will set the size to 100% RAM
-> if maxsize is > RAM, the size will be 100% RAM
-> if maxize is < RAM, the size will be a corresponding percentage of RAM
Signed-off-by: Martin Kolman <mkolman at redhat.com>
---
blivet/__init__.py | 4 ++
blivet/deviceaction.py | 7 ++-
blivet/devices.py | 24 ++++++++++
blivet/formats/fs.py | 125 ++++++++++++++++++++++++++++++++++++++++++++++++-
4 files changed, 157 insertions(+), 3 deletions(-)
diff --git a/blivet/__init__.py b/blivet/__init__.py
index d15a0d0..afd5a49 100644
--- a/blivet/__init__.py
+++ b/blivet/__init__.py
@@ -1192,6 +1192,10 @@ class Blivet(object):
kwargs["subvol"] = True
return self.newBTRFS(*args, **kwargs)
+ def newTmpFS(self, *args, **kwargs):
+ """ Return a new TmpFSDevice. """
+ return TmpFSDevice(*args, **kwargs)
+
def createDevice(self, device):
""" Schedule creation of a device.
diff --git a/blivet/deviceaction.py b/blivet/deviceaction.py
index 202a66c..7160cce 100644
--- a/blivet/deviceaction.py
+++ b/blivet/deviceaction.py
@@ -473,8 +473,11 @@ class ActionCreateFormat(DeviceAction):
udev_settle()
self.device.updateSysfsPath()
info = udev_get_block_device(self.device.sysfsPath)
- self.device.format.uuid = udev_device_get_uuid(info)
- self.device.deviceLinks = udev_device_get_symlinks(info)
+ # only do this if the format has a device known to udev
+ # (the format might not have a normal device at all)
+ if info:
+ self.device.format.uuid = udev_device_get_uuid(info)
+ self.device.deviceLinks = udev_device_get_symlinks(info)
def cancel(self):
self.device.format = self.origFormat
diff --git a/blivet/devices.py b/blivet/devices.py
index 6650086..c278433 100644
--- a/blivet/devices.py
+++ b/blivet/devices.py
@@ -3760,6 +3760,30 @@ class NoDevice(StorageDevice):
self._preDestroy()
+class TmpFSDevice(NoDevice):
+ def __init__(self, *args, **kwargs):
+ """Create a tmpfs device"""
+ format = kwargs.get('format')
+ NoDevice.__init__(self, format)
+ # the tmpfs device does not exist until mounted
+ self.exists = False
+ self._size = kwargs["size"]
+ self._targetSize = self._size
+
+ @property
+ def size(self):
+ if self._size is not None:
+ return self._size
+ elif self.format:
+ return self.format.size
+ else:
+ return None
+
+ @property
+ def fstabSpec(self):
+ return "tmpfs"
+
+
class FileDevice(StorageDevice):
""" A file on a filesystem.
diff --git a/blivet/formats/fs.py b/blivet/formats/fs.py
index 13896c9..f7e1da8 100644
--- a/blivet/formats/fs.py
+++ b/blivet/formats/fs.py
@@ -1406,7 +1406,7 @@ class NoDevFS(FS):
def __init__(self, *args, **kwargs):
FS.__init__(self, *args, **kwargs)
self.exists = True
- self.device = self.type
+ self.device = self._type
def _setDevice(self, devspec):
self._device = devspec
@@ -1451,6 +1451,129 @@ register_device_format(SysFS)
class TmpFS(NoDevFS):
_type = "tmpfs"
+ _supported = True
+ _resizable = True
+ # as tmpfs is part of the Linux kernel,
+ # I guess it is linux-native
+ _linuxNative = True
+ # empty tmpfs has zero overhead
+ _minSize = 0
+ _minInstanceSize = 0
+ # tmpfs really does not occupy any space by itself
+ _minSize = 0
+ # in a sense, I guess tmpfs is formatable
+ # in the regard that the format is atuomatically created
+ # once mounted
+ _formattable = True
+
+ def __init__(self, *args, **kwargs):
+ NoDevFS.__init__(self, *args, **kwargs)
+ self.exists = True
+ self._device = "tmpfs"
+
+ # check if fixed filesystem size has been specified,
+ # if no size is specified, tmpfs will by default
+ # be limited to half of the system RAM
+ # (sizes of all tmpfs mounts are independent)
+ fsoptions = kwargs.get("mountopts")
+ grow = kwargs.get("grow")
+ maxsize = kwargs.get("maxsize")
+ size_option = ""
+ if fsoptions:
+ self._apendOptions(fsoptions)
+ if self._size:
+ self._apendOptions("size=%dm" % self._size)
+ elif grow:
+ # grow to 100% RAM
+ size_option = "size=100%%"
+ system_ram = util.total_memory()/1024 # kB to MB
+ fs_size = system_ram
+ if maxsize:
+ # check if maxsize is < RAM
+ if maxsize < system_ram:
+ # as maxsize is smaller than RAM, filesystem size = maxsize
+ fs_size = maxsize
+ # maxsize is less than size of RAM
+ # -> convert to % of RAM
+ size_fraction = maxsize/float(system_ram)
+ # "size=%1.0f%%" % (0.5555*100) -> "size=56%"
+ size_option = "size=%1.0f%%" % (size_fraction*100)
+ self._size = fs_size
+ kwargs["size"] = fs_size
+
+ if size_option:
+ self._apendOptions(size_option)
+
+ def mount(self, *args, **kwargs):
+ """The filesystem doesn't need to be separately mounted"""
+ pass
+
+ def create(self, *arg, **kwargs):
+ """A filesystem is created automatically once tmpfs is mounted"""
+ pass
+
+ @property
+ def mountable(self):
+ return True
+
+ def _getOptions(self):
+ if self._options:
+ return self._options
+ else:
+ return "defaults"
+
+ def _setOptions(self, options):
+ self._options = options
+
+ # override the options property
+ # so that the size and other options
+ # are correctly added to fstab
+ options = property(_getOptions, _setOptions)
+
+ @property
+ def size(self):
+ return self._size
+
+ @property
+ def minSize(self):
+ """ The minimum filesystem size in megabytes. """
+ return self._minInstanceSize
+
+ @property
+ def free(self):
+ free_space = 0
+ if self.mountpoint:
+ # we need both the output and the return code
+ rc, buf = util._run_program(['df', '-P', self.mountpoint])
+ # XXXX, what about changeroot ?
+ if rc == 0:
+ lines = buf.readlines()
+ if len(lines) == 2: # header and a single data row
+ space_data = lines[0].split(" ")
+ if len(space_data) >= 6:
+ free_space = int(space_data[3])
+ # convert to MB
+ free_space = math.ceil(size / 1024.0)
+ return free_space
+
+ def _setDevice(self, devspec):
+ self._device = devspec
+
+ def _getDevice(self):
+ return self._device
+
+ device = property(lambda f: f._getDevice(),
+ lambda f,d: f._setDevice(d),
+ doc="Full path the device this format occupies")
+
+ def _apendOptions(self, new_options):
+ """Append free form option string
+ to the options (used among others in fstab)
+ """
+ if self._options: # append to existing options
+ self._options = "%s,%s" % (self._options, new_options)
+ else: # not yet set, just assign it
+ self._options = new_options
register_device_format(TmpFS)
--
1.8.3.1
More information about the anaconda-patches
mailing list