[PATCH] Add tmpfs support (#918621)

Vratislav Podzimek vpodzime at redhat.com
Fri Sep 27 12:38:03 UTC 2013


On Thu, 2013-09-26 at 18:56 +0200, Martin Kolman wrote:
> 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
                                       ^^^ double 't'
> +    # in the regard that the format is atuomatically created
                                          ^^^ typo
> +    # 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)
                   ^^^ should be appendOptions with double 'p'

> +        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
It's better to use spaces around operators (applies to a few more
places).

> +            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])
Comment describing the format of the 'df -P' output may help here.

Apart from those nitpicking comments this looks good and surprisingly
clean to me.

-- 
Vratislav Podzimek

Anaconda Rider | Red Hat, Inc. | Brno - Czech Republic



More information about the anaconda-patches mailing list