From 25fb90d1f81a3a30453534c6ab480c4fbc246a89 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Wed, 13 Apr 2016 14:17:22 -0700 Subject: [PATCH 001/113] Added python-yaml and python-parted to base ONL build --- builds/any/rootfs/jessie/common/common-packages.yml | 2 ++ builds/any/rootfs/wheezy/common/common-packages.yml | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/builds/any/rootfs/jessie/common/common-packages.yml b/builds/any/rootfs/jessie/common/common-packages.yml index 74ef19c4..980a86b1 100644 --- a/builds/any/rootfs/jessie/common/common-packages.yml +++ b/builds/any/rootfs/jessie/common/common-packages.yml @@ -70,3 +70,5 @@ - onl-loader-initscripts - onlp-snmpd - oom-shim +- python-parted +- python-yaml diff --git a/builds/any/rootfs/wheezy/common/common-packages.yml b/builds/any/rootfs/wheezy/common/common-packages.yml index 5857b0f2..b93183b1 100644 --- a/builds/any/rootfs/wheezy/common/common-packages.yml +++ b/builds/any/rootfs/wheezy/common/common-packages.yml @@ -69,5 +69,5 @@ - onl-loader-initscripts - onlp-snmpd - oom-shim - - +- python-parted +- python-yaml From f9b34e1ef8b6d6d148b543673d2ea28927a1c0f5 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Thu, 14 Apr 2016 11:19:45 -0700 Subject: [PATCH 002/113] Add onl-vendor-config-onl to initrd --- packages/base/any/initrds/loader/builds/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/base/any/initrds/loader/builds/Makefile b/packages/base/any/initrds/loader/builds/Makefile index 23bc0fbb..6f290bed 100644 --- a/packages/base/any/initrds/loader/builds/Makefile +++ b/packages/base/any/initrds/loader/builds/Makefile @@ -23,6 +23,7 @@ $(TARGET): sudo rm -rf $(ROOT) && mkdir $(ROOT) $(ONLPM) --sudo --force --extract-dir onl-loader-initrd-files:all $(ROOT) $(ONLPM) --sudo $(foreach p,$(PLATFORM_PACKAGES),--extract-dir $(p) $(ROOT)) + $(ONLPM) --sudo --force --extract-dir onl-vendor-config-onl:all $(ROOT) $(ONL)/tools/sjson.py --kj version $(ONL)/make/version-onl.json --kl platforms $(PLATFORMS) --kv arch $(ARCH) --out manifest.json sudo mkdir -p $(ROOT)/etc/onl/loader && sudo cp manifest.json $(ROOT)/etc/onl/loader sudo $(ONL)/tools/makedevs -d $(ROOT)/etc/rootperms $(abspath $(ROOT)) From 58cf4e503621ffc502281ecbf8defd8cae4a0a32 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Mon, 2 May 2016 12:41:21 -0700 Subject: [PATCH 003/113] Updated install template for vendor-config-onl - Include stub shell file for new installer - put Python files in a proper site install location --- packages/base/all/vendor-config-onl/PKG.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/base/all/vendor-config-onl/PKG.yml b/packages/base/all/vendor-config-onl/PKG.yml index 794948a1..923f4274 100644 --- a/packages/base/all/vendor-config-onl/PKG.yml +++ b/packages/base/all/vendor-config-onl/PKG.yml @@ -11,6 +11,7 @@ packages: src/python/onl : $PY_INSTALL/onl src/boot.d : /etc/boot.d src/bin : /usr/bin + src/lib : /lib/vendor-config/onl changelog: Changes @@ -23,7 +24,7 @@ packages: summary: ONL Base Configuration Package (Loader) files: - src/python/onl : /usr/lib/python2.7/onl + src/python/onl : /usr/lib/python2.7/dist-packages/onl src/bin/initmounts : /bin/initmounts changelog: Changes From dc0178c9840f53d7fc245d0e01a1953bc34c5b36 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Mon, 2 May 2016 12:42:37 -0700 Subject: [PATCH 004/113] Initial checkin of pythonic installer library - u-boot is currently broken --- .../src/python/onl/install/App.py | 234 +++++ .../src/python/onl/install/BaseInstall.py | 708 +++++++++++++++ .../src/python/onl/install/BaseRecovery.py | 240 +++++ .../src/python/onl/install/ConfUtils.py | 390 ++++++++ .../src/python/onl/install/Fit.py | 578 ++++++++++++ .../src/python/onl/install/InstallUtils.py | 829 ++++++++++++++++++ .../src/python/onl/install/RecoverApp.py | 81 ++ .../src/python/onl/install/ShellApp.py | 251 ++++++ .../src/python/onl/install/__init__.py | 4 + 9 files changed, 3315 insertions(+) create mode 100644 packages/base/all/vendor-config-onl/src/python/onl/install/App.py create mode 100644 packages/base/all/vendor-config-onl/src/python/onl/install/BaseInstall.py create mode 100644 packages/base/all/vendor-config-onl/src/python/onl/install/BaseRecovery.py create mode 100644 packages/base/all/vendor-config-onl/src/python/onl/install/ConfUtils.py create mode 100644 packages/base/all/vendor-config-onl/src/python/onl/install/Fit.py create mode 100644 packages/base/all/vendor-config-onl/src/python/onl/install/InstallUtils.py create mode 100644 packages/base/all/vendor-config-onl/src/python/onl/install/RecoverApp.py create mode 100644 packages/base/all/vendor-config-onl/src/python/onl/install/ShellApp.py create mode 100644 packages/base/all/vendor-config-onl/src/python/onl/install/__init__.py diff --git a/packages/base/all/vendor-config-onl/src/python/onl/install/App.py b/packages/base/all/vendor-config-onl/src/python/onl/install/App.py new file mode 100644 index 00000000..714fd182 --- /dev/null +++ b/packages/base/all/vendor-config-onl/src/python/onl/install/App.py @@ -0,0 +1,234 @@ +"""App.py + +top-level install app +""" + +import subprocess +import sys, os +import logging +import imp +import glob +import distutils.sysconfig + +from InstallUtils import InitrdContext +from InstallUtils import SubprocessMixin +import ConfUtils, BaseInstall + +# locate the platform-config files using SWI path rules +sys.path.append("/usr/lib/python%s/dist-packages" + % (distutils.sysconfig.get_python_version(),)) + +import onl.platform.base +import onl.platform.current + +class App(SubprocessMixin): + + def __init__(self, log=None): + + if log is not None: + self.log = log + else: + self.log = logging.getLogger(self.__class__.__name__) + + self.installer = None + self.machineConf = None + self.installerConf = None + self.platform = None + + def run(self): + + self.log.info("getting installer configuration") + self.machineConf = ConfUtils.MachineConf() + self.installerConf = ConfUtils.InstallerConf() + + ##self.log.info("using native GRUB") + ##self.grubEnv = ConfUtils.GrubEnv(log=self.log.getChild("grub")) + + pat = "/mnt/onie-boot/onie/initrd.img*" + l = glob.glob(pat) + if l: + initrd = l[0] + self.log.info("using native ONIE initrd+chroot GRUB (%s)", initrd) + initrdDir = InitrdContext.mkChroot(initrd, log=self.log) + self.grubEnv = ConfUtils.ChrootGrubEnv(initrdDir, + bootDir="/mnt/onie-boot", + path="/grub/grubenv", + log=self.log.getChild("grub")) + # direct access using ONIE initrd as a chroot + # (will need to fix up bootDir and bootPart later) + else: + self.log.info("using proxy GRUB") + self.grubEnv = ConfUtils.ProxyGrubEnv(self.installerConf, + bootDir="/mnt/onie-boot", + path="/grub/grubenv", + chroot=False, + log=self.log.getChild("grub")) + # indirect access through chroot host + # (will need to fix up bootDir and bootPart later) + + if os.path.exists(ConfUtils.UbootEnv.SETENV): + self.ubootEnv = ConfUtils.UbootEnv(log=self.log.getChild("u-boot")) + else: + self.ubootEnv = None + + self.log.info("ONL Installer %s", self.installerConf.onl_version) + + code = self.findPlatform() + if code: return code + + self.onlPlatform = onl.platform.current.OnlPlatform() + + if 'grub' in self.onlPlatform.platform_config: + self.log.info("trying a GRUB based installer") + iklass = BaseInstall.GrubInstaller + elif 'flat_image_tree' in self.onlPlatform.platform_config: + self.log.info("trying a U-Boot based installer") + iklass = BaseInstall.UbootInstaller + else: + self.log.error("cannot detect installer type") + return 1 + + # run the platform-specific installer + self.installer = iklass(machineConf=self.machineConf, + installerConf=self.installerConf, + platformConf=self.onlPlatform.platform_config, + grubEnv=self.grubEnv, + ubootEnv=self.ubootEnv, + log=self.log) + try: + code = self.installer.run() + except: + self.log.exception("installer failed") + code = 1 + if self.log.level < logging.INFO: + self.post_mortem() + if code: return code + + if getattr(self.installer, 'grub', False): + code = self.finalizeGrub() + if code: return code + if getattr(self.installer, 'uboot', False): + code = self.finalizeUboot() + if code: return code + + self.log.info("Install finished.") + return 0 + + def findPlatform(self): + + plat = getattr(self.machineConf, 'onie_platform', None) + arch = getattr(self.machineConf, 'onie_arch', None) + if plat and arch: + self.log.info("ONL installer running under ONIE.") + plat = plat.replace('_', '-') + self.installerConf.installer_platform = plat + self.installerConf.installer_arch = arch + else: + self.log.error("The installation platform cannot be determined.") + self.log.error("It does not appear that we are running under ONIE or the ONL loader.") + self.log.error("If you know what you are doing you can re-run this installer") + self.log.error("with an explicit 'installer_platform=' setting,") + self.log.error("though this is unlikely to be the correct procedure at this point.") + return 1 + + self.log.info("Detected platform %s", self.installerConf.installer_platform) + + self.installerConf.installer_platform_dir = ("/lib/platform-config/%s" + % (self.installerConf.installer_platform,)) + if not os.path.isdir(self.installerConf.installer_platform_dir): + self.log.error("This installer does not support the %s platform.", + self.installerConf.installer_platform) + self.log.error("Available platforms are:") + for d in os.listdir("/lib/platform-config"): + self.log.error(" %s", d) + self.log.error("Installation cannot continue.") + return 1 + + return 0 + + def finalizeGrub(self): + + def _m(src, dst): + val = getattr(self.installerConf, src, None) + if val is not None: + setattr(self.grubEnv, dst, val) + else: + delattr(self.grubEnv, dst) + + _m('installer_md5', 'onl_installer_md5') + _m('onl_version', 'onl_installer_version') + _m('installer_url', 'onl_installer_url') + + return 0 + + def finalizeUboot(self): + + if self.installer.platform.isOnie(): + def _m(src, dst): + val = getattr(self.installerConf, src, None) + if val is not None: + setattr(self.ubootEnv, dst, val) + else: + delattr(self.ubootEnv, dst) + + _m('installer_md5', 'onl_installer_md5') + _m('onl_version', 'onl_installer_version') + _m('installer_url', 'onl_installer_url') + else: + self.log.info("To configure U-Boot to boot ONL automatically, reboot the switch,") + self.log.info("enter the U-Boot shell, and run these 2 commands:") + self.log.info("=> setenv bootcmd '%s'", self.installer.platform.str_bootcmd()) + self.log.info("saveenv") + + return 0 + + def shutdown(self): + + installer, self.installer = self.installer, None + if installer is not None: + installer.shutdown() + + def post_mortem(self): + self.log.info("re-attaching to tty") + fdno = os.open("/dev/console", os.O_RDWR) + os.dup2(fdno, sys.stdin.fileno()) + os.dup2(fdno, sys.stdout.fileno()) + os.dup2(fdno, sys.stderr.fileno()) + os.close(fdno) + + self.log.info("entering Python debugger (installer_debug=1)") + import pdb + pdb.post_mortem(sys.exc_info()[2]) + + @classmethod + def main(cls): + + logging.basicConfig() + logger = logging.getLogger("install") + logger.setLevel(logging.DEBUG) + + # send to ONIE log + hnd = logging.FileHandler("/dev/console") + logger.addHandler(hnd) + logger.propagate = False + + debug = 'installer_debug' in os.environ + if debug: + logger.setLevel(logging.DEBUG) + + app = cls(log=logger) + try: + code = app.run() + except: + logger.exception("runner failed") + code = 1 + if debug: + app.post_mortem() + + app.shutdown() + sys.exit(code) + +main = App.main + +if __name__ == "__main__": + main() diff --git a/packages/base/all/vendor-config-onl/src/python/onl/install/BaseInstall.py b/packages/base/all/vendor-config-onl/src/python/onl/install/BaseInstall.py new file mode 100644 index 00000000..22ae8850 --- /dev/null +++ b/packages/base/all/vendor-config-onl/src/python/onl/install/BaseInstall.py @@ -0,0 +1,708 @@ +"""BaseInstall.py + +Base classes for installers. +""" + +import os, stat +import subprocess +import re +import tempfile +import logging +import StringIO +import parted +import yaml + +from InstallUtils import MountContext, BlkidParser, PartedParser, SubprocessMixin +import onl.YamlUtils + +class Base: + + class installmeta: + def __init__(self, + installerConf=None, + machineConf=None, + platformConf=None, + grubEnv=None, ubootEnv=None): + self.installerConf = installerConf + self.machineConf = machineConf + self.platformConf = platformConf + self.grubEnv = grubEnv + self.ubootEnv = ubootEnv + + def isOnie(self): + if self.machineConf is None: return False + plat = getattr(self.machineConf, 'onie_platform', None) + return plat is not None + + def __init__(self, + machineConf=None, installerConf=None, platformConf=None, + grubEnv=None, ubootEnv=None, + log=None): + self.machineConf = machineConf + self.installerConf = installerConf + self.im = self.installmeta(installerConf=installerConf, + machineConf=machineConf, + platformConf=platformConf, + grubEnv=grubEnv, + ubootEnv = ubootEnv) + self.grubEnv = grubEnv + self.ubootEnv = ubootEnv + self.log = log or logging.getLogger(self.__class__.__name__) + + def run(self): + self.log.error("not implemented") + return 1 + + def shutdown(self): + pass + + def installSwi(self): + + swis = [x for x in os.listdir(self.installerConf.installer_dir) if x.endswith('.swi')] + if not swis: + self.log.info("No ONL Software Image available for installation.") + self.log.info("Post-install ZTN installation will be required.") + return + if len(swis) > 1: + self.log.warn("Multiple SWIs found in installer: %s", " ".join(swis)) + return + + base = swis[0] + src = os.path.join(self.installerConf.installer_dir, base) + + self.log.info("Installing ONL Software Image (%s)...", base) + dev = self.blkidParts['ONL-IMAGES'] + with MountContext(dev.device, log=self.log) as ctx: + dst = os.path.join(ctx.dir, base) + self.copy2(src, dst) + + return 0 + + def backupConfig(self, dev): + """Back up the ONL-CONFIG partition for later restore.""" + self.configArchive = tempfile.mktemp(prefix="onl-config-", + suffix=".tar.gz") + self.log.info("backing up ONL-CONFIG partition %s to %s", + dev, self.configArchive) + with MountContext(dev, log=self.log) as ctx: + self.log.debug("+ tar -zcf %s -C %s .", + self.configArchive, ctx.dir) + pipe = subprocess.Popen(["tar", "-zcf", self.configArchive, ".",], + cwd=ctx.dir) + pipe.communicate() + code = pipe.wait() + if code: + raise SystemExit("backup of ONL-CONFIG failed") + + def restoreConfig(self, dev): + """Restore the saved ONL-CONFIG.""" + archive, self.configArchive = self.configArchive, None + self.log.info("restoring ONL-CONFIG archive %s to %s", + archive, dev) + with MountContext(dev, log=self.log) as ctx: + self.log.debug("+ tar -zxf %s -C %s", + archive, ctx.dir) + pipe = subprocess.Popen(["tar", "-zxf", archive,], + cwd=ctx.dir) + pipe.communicate() + code = pipe.wait() + if code: + raise SystemExit("backup of ONL-CONFIG failed") + self.unlink(archive) + +GRUB_TPL = """\ +#serial --port=0x3f8 --speed=115200 --word=8 --parity=no --stop=1 +serial %(serial)s +terminal_input serial +terminal_output serial +set timeout=5 + +menuentry OpenNetworkLinux { + search --no-floppy --label --set=root ONL-BOOT + echo 'Loading Open Network Linux ...' + insmod gzio + insmod part_msdos + #linux /kernel-3.9.6-x86-64-all nopat console=ttyS0,115200n8 onl_platform=x86-64-kvm-x86-64-r0 + linux /%(kernel)s %(args)s onl_platform=%(platform)s + initrd /%(initrd)s +} + +# Menu entry to chainload ONIE +menuentry ONIE { + search --no-floppy --label --set=root ONIE-BOOT + echo 'Loading ONIE ...' + chainloader +1 +} +""" + +class GrubInstaller(SubprocessMixin, Base): + """Installer for grub-based systems (x86).""" + + class installmeta(Base.installmeta): + grub = True + + def __init__(self, *args, **kwargs): + Base.__init__(self, *args, **kwargs) + + self.device = None + self.minpart = None + self.nextBlock = None + + self.blkidParts = [] + + self.partedDevice = None + self.partedDisk = None + + self.configArchive = None + # backup of ONL-CONFIG during re-partitioning + + def findGpt(self): + self.blkidParts = BlkidParser(log=self.log.getChild("blkid")) + + deviceOrLabel = self.im.platformConf['grub']['device'] + if deviceOrLabel.startswith('/dev'): + tgtDevice, tgtLabel = deviceOrLabel, None + else: + tgtDevice, tgtLabel = None, deviceOrLabel + + # enumerate labeled partitions to try to identify + # the boot device + for part in self.blkidParts: + dev, partno = part.splitDev() + if tgtLabel is not None and tgtLabel == part.label: + if not len(partno): + self.log.error("cannot use whole disk") + return 1 + if self.device is None: + self.device = dev + else: + self.log.error("found multiple devices: %s, %s", + dev, self.device) + return 1 + elif tgtDevice is not None and tgtDevice == dev: + if not len(partno): + self.log.error("cannot use whole disk") + return 1 + if self.device is None: + self.device = dev + else: + self.log.error("found multiple devices: %s, %s", + dev, self.device) + return 1 + if self.device is None: + self.log.error("cannot find an install device") + return 1 + + # optionally back up a config partition + # if it's on the boot device + for part in self.blkidParts: + dev, partno = part.splitDev() + if dev == self.device and part.label == 'ONL-CONFIG': + self.backupConfig(part.device) + + self.partedDevice = parted.getDevice(self.device) + self.partedDisk = parted.newDisk(self.partedDevice) + + # enumerate the partitions that will stay and go + minpart = -1 + for part in self.partedDisk.partitions: + + if part.getFlag(parted.PARTITION_HIDDEN): + minpart = max(minpart, part.number+1) + continue + + # else, the partition should exist + blkidParts = [x for x in self.blkidParts if x.device == part.path] + if not blkidParts: + self.log.warn("cannot identify partition %s", part) + continue + + blkidPart = blkidParts[0] + if not blkidPart.isOnieReserved(): continue + + # else, check the GPT label for reserved-ness + if (part.name + and ('GRUB' in part.name + or 'ONIE-BOOT' in part.name + or 'DIAG' in part.name)): + minpart = max(minpart, part.number+1) + + if minpart < 0: + self.log.error("cannot find an install partition") + return 1 + self.minpart = minpart + + return 0 + + def deletePartitions(self): + + nextBlock = -1 + for part in self.partedDisk.partitions: + self.log.info("examining %s part %d", + self.partedDisk.device.path, part.number) + if part.number < self.minpart: + self.log.info("skip this part") + nextBlock = max(part.geometry.start+part.geometry.length, + nextBlock) + else: + self.log.info("deleting this part") + self.partedDisk.removePartition(part) + + if nextBlock < 0: + self.log.error("cannot find a starting block") + return 1 + + self.nextBlock = nextBlock + return 0 + + def partitionGpt(self): + + constraint = self.partedDevice.optimalAlignedConstraint + # default partition layout constraint + + devices = {} + + def _u2s(sz, u): + bsz = sz * u + bsz = bsz + self.partedDevice.physicalSectorSize - 1 + return bsz / self.partedDevice.physicalSectorSize + + UNITS = { + 'GiB' : 1024 * 1024 * 1024, + 'G' : 1000 * 1000 * 1000, + 'MiB' : 1024 * 1024, + 'M' : 1000 * 1000, + 'KiB' : 1024, + 'K' : 1000, + } + + for part in self.im.platformConf['installer']: + + label, sz = list(part.items())[0] + if type(sz) == dict: + sz, fmt = sz['='], sz.get('format', 'ext4') + else: + fmt = 'ext4' + + cnt = None + for ul, ub in UNITS.items(): + if sz.endswith(ul): + cnt = _u2s(int(sz[:-len(ul)], 10), ub) + break + if sz == '100%': + cnt = self.partedDevice.getLength() - self.nextBlock + if cnt is None: + self.log.error("invalid size (no units) for %s: %s", + part, sz) + return 1 + + start = self.nextBlock + end = start + cnt - 1 + if end <= self.partedDevice.getLength(): + self.log.info("Allocating %d sectors for %s", + cnt, label) + else: + self.log.warn("%s: start sector %d, end sector %d, max %d", + label, start, end, + self.partedDevice.getLength()) + self.log.error("invalid partition %s [%s] (too big)", + label, sz) + return 1 + + geom = parted.Geometry(device=self.partedDevice, + start=start, length=end-start+1) + fs = parted.FileSystem(type=fmt, geometry=geom) + part = parted.Partition(disk=self.partedDisk, + type=parted.PARTITION_NORMAL, + fs=fs, + geometry=geom) + part.getPedPartition().set_name(label) + self.partedDisk.addPartition(part, constraint=constraint) + self.partedDisk.commit() + + self.log.info("Formatting %s (%s) as %s", + part.path, label, fmt) + if fmt == 'msdos': + cmd = ('mkdosfs', '-n', label, part.path,) + else: + cmd = ('mkfs.%s' % fmt, '-L', label, part.path,) + self.check_call(cmd, vmode=self.V1) + + self.nextBlock, self.minpart = end+1, self.minpart+1 + + devices[label] = part.path + + if label == 'ONL-CONFIG' and self.configArchive is not None: + self.restoreConfig(part.path) + + self.blkidParts = BlkidParser(log=self.log.getChild("blkid")) + # re-read the partitions + + return 0 + + def installBootConfig(self): + dev = self.blkidParts['ONL-BOOT'] + self.log.info("Installing boot-config to %s", dev.device) + + src = os.path.join(self.installerConf.installer_dir, 'boot-config') + with MountContext(dev.device, log=self.log) as ctx: + dst = os.path.join(ctx.dir, 'boot-config') + self.copy2(src, dst) + + with open(src) as fd: + ecf = fd.read().encode('base64', 'strict').strip() + setattr(self.grubEnv, 'boot_config_default', ecf) + + return 0 + + def installLoader(self): + + ctx = {} + + kernel = self.im.platformConf['grub']['kernel'] + ctx['kernel'] = kernel['='] if type(kernel) == dict else kernel + + initrd = self.im.platformConf['grub']['initrd'] + ctx['initrd'] = initrd['='] if type(initrd) == dict else initrd + + ctx['args'] = self.im.platformConf['grub']['args'] + ctx['platform'] = self.installerConf.installer_platform + ctx['serial'] = self.im.platformConf['grub']['serial'] + + cf = GRUB_TPL % ctx + + self.log.info("Installing kernel") + dev = self.blkidParts['ONL-BOOT'] + with MountContext(dev.device, log=self.log) as ctx: + def _cp(b): + src = os.path.join(self.installerConf.installer_dir, b) + if not os.path.isfile(src): return + if b.startswith('kernel-') or b.startswith('onl-loader-initrd-'): + dst = os.path.join(ctx.dir, b) + self.copy2(src, dst) + [_cp(e) for e in os.listdir(self.installerConf.installer_dir)] + + d = os.path.join(ctx.dir, "grub") + self.makedirs(d) + dst = os.path.join(ctx.dir, 'grub/grub.cfg') + with open(dst, "w") as fd: + fd.write(cf) + + return 0 + + def installGrub(self): + self.log.info("Installing GRUB to %s", self.partedDevice.path) + self.grubEnv.install(self.partedDevice.path) + return 0 + + def installGpt(self): + + code = self.findGpt() + if code: return code + + self.log.info("Installing to %s starting at partition %d", + self.device, self.minpart) + + self.log.info("disk is %s", self.partedDevice.path) + + if self.partedDisk.type != 'gpt': + self.log.error("not a GPT partition table") + return 1 + if self.partedDevice.sectorSize != 512: + self.log.error("invalid logical block size") + return 1 + if self.partedDevice.physicalSectorSize != 512: + self.log.error("invalid physical block size") + return 1 + + self.log.info("found a disk with %d blocks", + self.partedDevice.getLength()) + + code = self.deletePartitions() + if code: return code + + self.log.info("next usable block is %s", self.nextBlock) + + code = self.partitionGpt() + if code: return code + + # once we assign the ONL-BOOT partition, + # we can re-target the grub environment + dev = self.blkidParts['ONL-BOOT'] + self.grubEnv.__dict__['bootPart'] = dev.device + self.grubEnv.__dict__['bootDir'] = None + + code = self.installSwi() + if code: return code + + code = self.installLoader() + if code: return code + + code = self.installBootConfig() + if code: return code + + code = self.installGrub() + if code: return code + + self.log.info("ONL loader install successful.") + self.log.info("GRUB installation is required next.") + + return 0 + + def run(self): + if 'grub' not in self.im.platformConf: + self.log.error("platform config is missing a GRUB section") + return 1 + label = self.im.platformConf['grub'].get('label', None) + if label != 'gpt': + self.log.error("invalid GRUB label in platform config: %s", label) + return 1 + return self.installGpt() + + def shutdown(self): + pass + +class UbootInstaller(SubprocessMixin, Base): + + class installmeta(Base.installmeta): + + device = None + uboot = True + + loaderBlocks = None + flashBlocks = None + flash2Blocks = None + # block count, or -1 for "rest" + + loaderRaw = True + # true for raw loader partition (FIT image) + + loaderSrc = None + # default loader source file (auto-detect) + + loaderDst = "onl-loader" + # destination path on ONL-BOOT for non-raw installs + + bootConf = None + # optional pre-formatted boot-config contents + # (string or list of strings) + + bootCmd = None + # pre-formatted string + + bootCmds = None + # ... or a list of strings + + def str_bootcmd(self): + if self.bootCmd is not None: return self.bootCmd + if self.bootCmds: + return "; ".join(self.bootCmds) + raise ValueError("missing boot commands") + + def __init__(self, *args, **kwargs): + kwargs = dict(kwargs) + installerConf = kwargs.pop('installerConf', None) + machineConf = kwargs.pop('machineConf', None) + platformConf = kwargs.pop('platformConf', None) + ubootEnv = kwargs.pop('ubootEnv', None) + self.im = self.installmeta(installerConf=installerConf, + machineConf=machineConf, + platformConf=platormConf, + ubootEnv=ubootEnv) + Base.__init__(self, *args, + machineConf=machineConf, installerConf=installerConf, platformConf=platformConf, + ubootEnv=ubootEnv, + **kwargs) + + # XXX roth + self.onlBootDev = None + self.onlConfigDev = None + self.onlDataDev = None + + def formatBlockdev(self): + + if self.im.loaderBlocks < 0: + self.log.error("no size defined for ONL-BOOT") + return 1 + if self.im.flashBlocks < 0: + self.log.error("no size defined for FLASH") + return 1 + + self.log.info("Formatting %s as %d:%d:%d", + self.im.device, + self.im.loaderBlocks, + self.im.flashBlocks, + self.im.flash2Blocks) + + self.check_call(('parted', '-s', self.im.device, + 'mklabel', 'msdos',)) + + start = 1 + end = start + self.im.loaderBlocks-1 + + self.check_call(('parted', '-s', self.im.device, + 'unit', 's', + 'mkpart', 'primary', 'fat32', str(start)+'s', str(end)+'s',)) + + self.onlBootDev = self.im.device + '1' + if not self.im.loaderRaw: + cmd = ('mkdosfs', '-n', 'ONL-BOOT', self.onlBootDev,) + self.check_call(cmd, vmode=self.V1) + + start = end + 1 + end = start + self.im.flashBlocks-1 + + self.check_call(('parted', '-s', self.im.device, + 'unit', 's', + 'mkpart', 'primary', 'fat32', str(start)+'s', str(end)+'s',)) + + self.onlConfigDev = self.im.device + '2' + cmd = ('mkdosfs', '-n', 'FLASH', self.onlConfigDev,) + self.check_call(cmd, vmode=self.V1) + + start = end + 1 + if self.im.flash2Blocks > -1: + end = start + self.im.flash2Blocks-1 + self.check_call(('parted', '-s', self.im.device, + 'unit', 's', + 'mkpart', 'primary', 'fat32', str(start)+'s', str(end)+'s',)) + else: + self.check_call(('parted', '-s', self.im.device, + 'unit', 's', + 'mkpart', 'primary', 'fat32', str(start)+'s', '100%',)) + + self.onlDataDev = self.im.device + '3' + cmd = ('mkdosfs', '-n', 'FLASH2', self.onlDataDev,) + self.check_call(cmd, vmode=self.V1) + + return 0 + + def installLoader(self): + + loaderSrc = None + for cand in (("%s/%s.itb" + % (self.installerConf.installer_dir, + self.installerConf.installer_platform,)), + os.path.join(self.installerConf.installer_dir, 'powerpc-fit-all.itb'), + self.im.loaderSrc, + ("%s/onl.%s.loader" + % (self.installerConf.installer_dir, + self.installerConf.installer_platform,))): + if os.path.exists(cand): + loaderSrc = cand + break + if not loaderSrc: + self.log.error("The platform loader file is missing.") + self.log.error("This is unexpected - %s", loaderSrc) + return 1 + + self.log.info("Installing the ONL loader...") + + if self.im.loaderRaw: + cmd = ('dd', + 'if=' + loaderSrc, + 'of=' + self.onlBootDev,) + self.check_call(cmd, vmode=self.V2) + else: + with MountContext(self.onlBootDev, log=self.log) as ctx: + dst = os.path.join(ctx, self.im.loaderDst) + self.copy2(loaderSrc, dst) + + return 0 + + def installBootconfig(self): + + cf = None + + p = os.path.join(self.installerConf.installer_dir, 'boot-config') + if cf is None and os.path.exists(p): + cf = open(p, "r").read() + + p = os.path.join(self.installerConf.installer_platform_dir, 'boot-config') + if cf is None and os.path.exists(p): + cf = open(p, "r").read() + + if cf is None and self.im.bootConf: + if isinstance(self.im.bootConf, basestring): + cf = self.im.bootConf + else: + cf = "\n".join(cf) + "\n" + + if cf is None: + buf = StringIO.StringIO() + buf.write("SWI=images:onl-%s.swi\n" + % (self.platformConf.installer_arch,)) + buf.write("NETDEV=ma1\n") + cf = buf.getvalue() + + self.log.info("Writing boot-config.") + with MountContext(self.onlConfigDev, log=self.log) as ctx: + dst = os.path.join(ctx.dir, "boot-config") + with open(dst, "w") as fd: + fd.write(cf) + + ecf = cf.encode('base64', 'strict').strip() + setattr(self.ubootEnv, 'boot-config-default', ecf) + + return 0 + + def installUbootEnv(self): + + # Special access instructions for initrd + off = getattr(self.installerConf, 'initrd_offset', None) + if off is not None: + if self.im.loaderRaw: + a = self.onlBootDev + else: + a = self.installerConf.initrd_archive + s = int(self.installerConf.initrd_offset) + e = s + int(self.installerConf.initrd_size) - 1 + self.ubootEnv.onl_installer_initrd = ("%s:%x:%x" % (a, s, e,)) + else: + try: + del self.installerConf.onl_installer_initrd + except AttributeError: + pass + + if self.im.isOnie(): + self.log.info("Setting ONIE nos_bootcmd to boot ONL") + self.ubootEnv.nos_bootcmd = self.im.str_bootcmd() + else: + self.log.warn("U-boot boot setting is not changed") + + return 0 + + def installUboot(self): + + st = os.stat(self.im.device) + if not stat.S_ISBLK(st[stat.ST_MODE]): + self.log.error("not a block device: %s", + self.im.device) + return 1 + + code = self.formatBlockdev() + if code: return code + + code = self.installLoader() + if code: return code + + code = self.installBootconfig() + if code: return code + + code = self.installSwi() + if code: return code + + self.log.info("syncing block devices") + self.check_call(('sync',)) + # XXX roth probably not needed + + code = self.installUbootEnv() + if code: return code + + return 0 + + def run(self): + return self.installUboot() + + def shutdown(self): + pass diff --git a/packages/base/all/vendor-config-onl/src/python/onl/install/BaseRecovery.py b/packages/base/all/vendor-config-onl/src/python/onl/install/BaseRecovery.py new file mode 100644 index 00000000..881b9b4f --- /dev/null +++ b/packages/base/all/vendor-config-onl/src/python/onl/install/BaseRecovery.py @@ -0,0 +1,240 @@ +"""BaseRecovery.py + +Base classes for recovery. +""" + +import subprocess, os, stat +import tempfile +import binascii +import glob +import logging +from InstallUtils import TempdirContext, MountContext, SubprocessMixin, ProcMountsParser +from InstallUtils import InitrdContext, BlkidParser +from ConfUtils import ChrootGrubEnv + +class Base(SubprocessMixin): + + class recovermeta: + + bootConfig = "/mnt/flash/boot-config" + bootConfigDfl = "/etc/boot-config.default" + + @property + def needRecovery(self): + if os.path.exists('/mnt/flash/.notmounted'): return True + if os.path.exists('/mnt/flash2/.notmounted'): return True + return False + + def __init__(self, + ubootEnv=None, + log=None): + self.platform = self.recovermeta() + self.ubootEnv = ubootEnv + self.log = log or logging.getLogger(self.__class__.__name__) + + def recoverFull(self): + self.log.error("not implemented") + return 1 + + def recoverConfig(self): + if os.path.exists(self.platform.bootConfig): return 0 + self.copy2(self.platform.bootConfigDfl, self.platform.bootConfig) + return 0 + + def run(self): + + if self.platform.needRecovery: + self.log.info("Attempting recovery") + code = self.recoverFull() + if code: return code + + code = self.recoverConfig() + if code: return code + + return 0 + + def umountAny(self, device=None, label=None): + p = ProcMountsParser() + if label is not None: + b = BlkidParser(log=self.log) + for e in b.parts: + if label == e.label: + device = e.device + break + + for m in p.mounts: + if device is not None and device in m.device: + try: + self.check_call(('umount', m.device,), + vmode=self.V1) + except CalledProcessError, what: + self.log.warn("cannot umount %s: %s", + m.device, str(what)) + return 0 + + def shutdown(self): + pass + +class GrubRecovery(Base): + + class recovermeta(Base.recovermeta): + pass + + def recoverX86(self): + + def _u(l): + self.umountAny(label=l) + def _l(l): + try: + return self.check_output(('blkid', '-L', l,)).strip() + except subprocess.CalledProcessError: + return None + def _r(l): + _u(l) + dev = _l(l) + if dev is not None: + self.log.info("Recovering %s partition", l) + self.check_call(('mkdosfs', '-n', l, dev,), + vmode=self.V1) + + _r('FLASH') + _r('FLASH2') + + return 0 + + def recoverGrubConfig(self): + + with MountContext(label='ONIE-BOOT', log=self.log) as octx: + + pat = "%s/onie/initrd.img*" % octx.dir + l = glob.glob(pat) + if not l: + raise ValueError("cannot find ONIE initrd") + initrd = l[0] + + with InitrdContext(initrd=initrd, log=self.log) as ictx: + + # copy the Switch Light grubenv out of its GRUB directory + dst = os.path.join(ictx.dir, "tmp/grubenv") + with MountContext(label='SL-BOOT', log=self.log) as sctx: + src = os.path.join(sctx.dir, "grub/grubenv") + self.copy2(src, dst) + + # use the ONIE runtime's GRUB tools to read it + grubEnv = ChrootGrubEnv(ictx.dir, mounted=True, + bootDir="/", + path="/tmp/grubenv", + log=self.log) + buf = getattr(grubEnv, 'boot_config_default', None) + + if buf is None: + raise ValueError("Cannot recover filesystem(s) -- missing boot_config_default.") + if buf == "": + raise ValueError("Cannot recover filesystem(s) -- empty boot_config_default.") + try: + buf = buf.decode('base64', 'strict') + except binascii.Error: + raise ValueError("Cannot recover filesystem(s) -- corrupted boot_config_default.") + if "SWI=flash" in buf: + raise ValueError("Cannot recover filesystem(s) -- local SWI cannot be recovered.") + + with MountContext(label='FLASH', log=self.log) as ctx: + dst = os.path.join(ctx.dir, 'boot-config') + with open(dst, "w") as fd: + self.log.debug("+ cat > %s", dst) + fd.write(buf) + + return 0 + + def recoverFull(self): + self.log.info("Recovering flash partitions.") + + code = self.recoverX86() + if code: return code + + code = self.recoverGrubConfig() + if code: return code + + self.check_call(('initmounts',)) + + return 0 + +class UbootRecovery(Base): + + class recovermeta(Base.recovermeta): + + def __init__(self, ubootEnv=None): + self.ubootEnv = ubootEnv + + device = None + # fill this in per-platform + + @property + def bootConfigEnv(self): + if self.ubootEnv is None: + raise ValueError("missing u-boot environment tools") + buf = getattr(self.ubootEnv, 'boot-config-default', None) + if buf is None: + raise ValueError("Cannot recover filesystem(s) -- missing boot-config-default.") + if buf == "": + raise ValueError("Cannot recover filesystem(s) -- empty boot-config-default.") + try: + buf = buf.decode('base64', 'strict') + except binascii.Error: + raise ValueError("Cannot recover filesystem(s) -- corrupted boot-config-default.") + if "SWI=flash" in buf: + raise ValueError("Cannot recover filesystem(s) -- local SWI cannot be recovered.") + return buf + + def __init__(self, + ubootEnv=None, + log=None): + self.ubootEnv = ubootEnv + self.platform = self.recovermeta(ubootEnv=ubootEnv) + self.log = log or logging.getLogger(self.__class__.__name__) + + self.flashDev = self.platform.device + '2' + self.flash2Dev = self.platform.device + '3' + + def recoverUboot(self): + if not os.path.exists(self.platform.device): + self.log.error("missing block device, cannot recover") + return 1 + st = os.stat(self.platform.device) + if not stat.S_ISBLK(st[stat.ST_MODE]): + self.log.error("invalid block device") + return 1 + + code = self.umountAny(device=self.platform.device) + if code: return code + + self.log.info("Re-formatting %s", self.platform.device) + cmd = ('mkdosfs', '-n', 'FLASH', self.flashDev,) + self.check_call(cmd, vmode=self.V1) + cmd = ('mkdosfs', '-n', 'FLASH2', self.flash2Dev,) + self.check_call(cmd, vmode=self.V1) + return 0 + + def recoverUbootConfig(self): + with MountContext(self.flashDev, log=self.log) as ctx: + dst = os.path.join(ctx.dir, 'boot-config') + with open(dst, "w") as fd: + self.log.debug("+ cat > %s", dst) + fd.write(self.platform.bootConfigEnv) + return 0 + + def recoverFull(self): + + code = self.recoverUboot() + if code: return code + + self.recoverUbootConfig() + if code: return code + + self.log.info("syncing block devices") + self.check_call(('sync',)) + # XXX roth probably not needed + + self.check_call(('initmounts',)) + + return 0 diff --git a/packages/base/all/vendor-config-onl/src/python/onl/install/ConfUtils.py b/packages/base/all/vendor-config-onl/src/python/onl/install/ConfUtils.py new file mode 100644 index 00000000..b81fd347 --- /dev/null +++ b/packages/base/all/vendor-config-onl/src/python/onl/install/ConfUtils.py @@ -0,0 +1,390 @@ +"""ConfUtils.py + +Config interfaces to different backend mechanisms. +""" + +import os +import logging +import subprocess +from InstallUtils import SubprocessMixin, ChrootSubprocessMixin, MountContext + +class ConfBase: + + def __init__(self): + self._parse() + + def _parse(self): + raise NotImplementedError + + def _feedLine(self, line): + line = line.strip() + if not line: return + + idx = line.find('=') + if idx < 0: + raise ValueError("invalid line in %s: %s" + % (self.path, line,)) + key, val = line[:idx], line[idx+1:] + if val[:1] == '"' and val[-1:] == '"': + val = val[1:-1] + if val[:1] == "'" and val[-1:] == "'": + val = val[1:-1] + self.__dict__['_data'][key] = val + + def __getattr__(self, attr, *args): + if len(args) == 1: + return self.__dict__['_data'].get(attr, args[0]) + elif len(args) == 0: + try: + return self.__dict__['_data'][attr] + except KeyError, what: + raise AttributeError(str(what)) + else: + raise ValueError("extra arguments") + + def __setattr__(self, attr, val): + self.__dict__['_data'][attr] = val + +class ConfFileBase(ConfBase): + + PATH = None + # Override me + + def __init__(self, path=None): + self.__dict__['path'] = path or self.PATH + ConfBase.__init__(self) + + def _parse(self): + self.__dict__['_data'] = {} + with open(self.path) as fd: + for line in fd.xreadlines(): + self._feedLine(line) + +class MachineConf(ConfFileBase): + PATH = "/etc/machine.conf" + +class InstallerConf(ConfFileBase): + PATH = "/etc/onl/installer.conf" + +class ConfBuf(ConfBase): + + def __init__(self, buf): + self.__dict__['buf'] = buf + ConfBase.__init__(self) + + def _parse(self): + self.__dict__['_data'] = {} + for line in self.buf.splitlines(): + self._feedLine(line) + +class GrubEnv(SubprocessMixin): + + INSTALL = "grub-install" + EDITENV = "grub-editenv" + # system default + + ENV_PATH = "/grub/grubenv" + # override me + + def __init__(self, + bootDir=None, bootPart=None, + path=None, + log=None): + + if bootDir and bootPart: + raise ValueError("cannot specify bootDir and bootPart") + if not bootDir and not bootPart: + raise ValueError("missing bootDir or bootPart") + self.__dict__['bootDir'] = bootDir + self.__dict__['bootPart'] = bootPart + # location of GRUB boot files (mounted directory or unmounted partition) + + self.__dict__['path'] = path or self.ENV_PATH + # path to grubenv, relative to above + + self.__dict__['log'] = log or logging.getLogger("grub") + + def mountCtx(self, device): + return MountContext(device, fsType='ext4', log=self.log) + + def asDict(self): + if self.bootPart: + with self.mountCtx(self.bootPart) as ctx: + p = os.path.join(ctx.dir, self.path.lstrip('/')) + buf = self.check_output((self.EDITENV, p, 'list',)).strip() + else: + p = os.path.join(self.bootDir, self.path.lstrip('/')) + buf = self.check_output((self.EDITENV, p, 'list',)).strip() + cf = ConfBuf(buf) + return cf.__dict__['_data'] + + toDict = asDict + + def __getattr__(self, *args): + + args = list(args) + attr = args.pop(0) + + d = self.asDict() + if args: + return d.get(attr, args[0]) + try: + return d[attr] + except KeyError, what: + raise AttributeError(str(what)) + + def __setattr__(self, attr, val): + if self.bootPart: + with self.mountCtx(self.bootPart) as ctx: + p = os.path.join(ctx.dir, self.path.lstrip('/')) + cmd = (self.EDITENV, p, 'set', ("%s=%s" % (attr, val,)),) + self.check_call(cmd) + else: + p = os.path.join(self.bootDir, self.path.lstrip('/')) + cmd = (self.EDITENV, p, 'set', ("%s=%s" % (attr, val,)),) + self.check_call(cmd) + + def __delattr__(self, attr): + if self.bootPart: + with self.mountCtx(self.bootPart) as ctx: + p = os.path.join(ctx.dir, self.path.lstrip('/')) + cmd = (self.EDITENV, p, 'unset', attr,) + self.check_call(cmd) + else: + p = os.path.join(self.bootDir, self.path.lstrip('/')) + cmd = (self.EDITENV, p, 'unset', attr,) + self.check_call(cmd) + + def install(self, device): + if self.bootDir is not None: + self.check_call((self.INSTALL, '--boot-directory=' + self.bootDir, device,)) + elif self.bootPart is not None: + with self.mountCtx(self.bootPart) as ctx: + self.check_call((self.INSTALL, '--boot-directory=' + ctx.dir, device,)) + else: + self.check_call((self.INSTALL, device,)) + +class ChrootGrubEnv(ChrootSubprocessMixin, GrubEnv): + + def __init__(self, + chrootDir, + mounted=False, + bootDir=None, bootPart=None, + path=None, + log=None): + self.__dict__['chrootDir'] = chrootDir + self.__dict__['mounted'] = mounted + GrubEnv.__init__(self, + bootDir=bootDir, bootPart=bootPart, + path=path, + log=log) + + def mountCtx(self, device): + return MountContext(device, + chroot=self.chrootDir, fsType='ext4', + log=self.log) + +class ProxyGrubEnv: + """Pretend to manipulate the GRUB environment. + + Instead, write a trace of shell commands to a log + so that e.g. the chroot's host can execute it with + the proper GRUB runtime. + """ + + INSTALL = "grub-install" + EDITENV = "grub-editenv" + # system defaults + + ENV_PATH = "/grub/grubenv" + # override this + + def __init__(self, + installerConf, + bootDir=None, chroot=True, bootPart=None, + path=None, + log=None): + + self.__dict__['installerConf'] = installerConf + # installer state, to retrieve e.g. chroot directory and trace log + + if bootDir and bootPart: + raise ValueError("cannot specify bootDir and bootPart") + if not bootDir and not bootPart: + raise ValueError("missing bootDir or bootPart") + self.__dict__['bootDir'] = bootDir + self.__dict__['bootPart'] = bootPart + # location of GRUB boot files (mounted directory or unmounted partition) + + self.__dict__['chroot'] = chroot + # True of the bootDir is inside the chroot, + # else bootDir is in the host's file namespace + + self.__dict__['path'] = path or self.ENV_PATH + # path to grubenv, relative to above + + self.__dict__['log'] = log or logging.getLogger("grub") + + def asDict(self): + raise NotImplementedError("proxy grubenv list not implemented") + + toDict = asDict + + def __getattr__(self, *args): + raise NotImplementedError("proxy grubenv list not implemented") + + def __setattr__(self, attr, val): + self.log.warn("deferring commands to %s...", self.installerConf.installer_postinst) + + cmds = [] + if self.bootDir and self.chroot: + p = os.path.join(self.installerConf.installer_chroot, + self.bootDir.lstrip('/'), + self.path.lstrip('/')) + cmds.append(("%s %s set %s=\"%s\"" % (self.EDITENV, p, attr, val,))) + elif self.bootDir: + p = os.path.join(self.bootDir, + self.path.lstrip('/')) + cmds.append(("%s %s set %s=\"%s\"" % (self.EDITENV, p, attr, val,))) + else: + p = ("${mpt}/%s" + % (self.path.lstrip('/'),)) + cmds.append("mpt=$(mktemp -t -d)") + cmds.append("mount %s $mpt" % self.bootPart) + cmds.append(("sts=0; %s %s set %s=\"%s\" || sts=$?" + % (self.EDITENV, p, attr, val,))) + cmds.append("umount $mpt") + cmds.append("rmdir $mpt") + cmds.append("test $sts -eq 0") + + with open(self.installerConf.installer_postinst, "a") as fd: + for cmd in cmds: + self.log.debug("+ [PROXY] " + cmd) + fd.write(cmd) + fd.write("\n") + + def __delattr__(self, attr): + self.log.warn("deferring commands to %s...", self.installerConf.installer_postinst) + + cmds = [] + if self.bootDir and self.chroot: + p = os.path.join(self.installerConf.installer_chroot, + self.bootDir.lstrip('/'), + self.path.lstrip('/')) + cmds.append(("%s %s unset %s" % (self.EDITENV, p, attr,))) + elif self.bootDir: + p = os.path.join(self.bootDir, + self.path.lstrip('/')) + cmds.append(("%s %s unset %s" % (self.EDITENV, p, attr,))) + else: + p = ("$mpt%s" + % (self.path.lstrip('/'),)) + cmds.append("mpt=$(mktemp -t -d)") + cmds.append("mount %s $mpt" % self.bootPart) + cmds.append(("sts=0; %s %s unset %s || sts=$?" + % (self.EDITENV, p, attr,))) + cmds.append("umount $mpt") + cmds.append("rmdir $mpt") + cmds.append("test $sts -eq 0") + + with open(self.installerConf.installer_postinst, "a") as fd: + for cmd in cmds: + self.log.debug("+ [PROXY] " + cmd) + fd.write(cmd) + fd.write("\n") + + def install(self, device): + self.log.warn("deferring commands to %s...", self.installerConf.installer_postinst) + cmds = [] + if self.bootDir and self.chroot: + p = os.pat.join(self.installerConf.installer_chroot, + self.bootDir.lstrip('/')) + cmds.append(("%s --boot-directory=\"%s\" %s" % (self.INSTALL, p, device,))) + elif self.bootDir: + p = self.bootDir + cmds.append(("%s --boot-directory=\"%s\" %s" % (self.INSTALL, p, device,))) + elif self.bootPart: + cmds.append("mpt=$(mktemp -t -d)") + cmds.append("mount %s $mpt" % self.bootPart) + cmds.append(("sts=0; %s --boot-directory=\"$mpt\" %s || sts=$?" + % (self.INSTALL, device,))) + cmds.append("umount $mpt") + cmds.append("rmdir $mpt") + cmds.append("test $sts -eq 0") + else: + cmds.append(("%s %s" + % (self.INSTALL, device,))) + + with open(self.installerConf.installer_postinst, "a") as fd: + for cmd in cmds: + self.log.debug("+ [PROXY] " + cmd) + fd.write(cmd) + fd.write("\n") + +class UbootEnv(SubprocessMixin): + + # ha ha, loader and SWI use different paths + if os.path.exists("/usr/sbin/fw_setenv"): + SETENV = "/usr/sbin/fw_setenv" + elif os.path.exists("/usr/bin/fw_setenv"): + SETENV = "/usr/bin/fw_setenv" + else: + SETENV = "/bin/false" + + if os.path.exists("/usr/sbin/fw_printenv"): + PRINTENV = "/usr/sbin/fw_printenv" + elif os.path.exists("/usr/bin/fw_printenv"): + PRINTENV = "/usr/bin/fw_printenv" + else: + PRINTENV = "/bin/false" + + def __init__(self, log=None): + self.__dict__['log'] = log or logging.getLogger("u-boot") + + self.__dict__['hasForceUpdate'] = False + try: + out = self.check_output((self.SETENV, '--help',), + stderr=subprocess.STDOUT) + if "-f" in out and "Force update" in out: + self.__dict__['hasForceUpdate'] = True + except subprocess.CalledProcessError: + if self.SETENV != '/bin/false': + raise + + def __getattr__(self, *args): + + args = list(args) + attr = args.pop(0) + + with open(os.devnull, "w") as nfd: + try: + out = self.check_output((self.PRINTENV, '-n', attr,), + stderr=nfd.fileno()) + except subprocess.CalledProcessError: + out = None + + if out is not None: return out + + if args: + return args[0] + + raise AttributeError("firmware tag not found") + + def __setattr__(self, attr, val): + if self.hasForceUpdate: + self.check_call((self.SETENV, '-f', attr, val,)) + else: + self.check_call((self.SETENV, attr, val,)) + + def __delattr__(self, attr): + + if self.hasForceUpdate: + self.check_call((self.SETENV, '-f', attr,)) + else: + self.check_call((self.SETENV, attr,)) + + def asDict(self): + buf = self.check_output((self.PRINTENV,)).strip() + return ConfBuf(buf).__dict__['_data'] + + toDict = asDict diff --git a/packages/base/all/vendor-config-onl/src/python/onl/install/Fit.py b/packages/base/all/vendor-config-onl/src/python/onl/install/Fit.py new file mode 100644 index 00000000..b3ca037f --- /dev/null +++ b/packages/base/all/vendor-config-onl/src/python/onl/install/Fit.py @@ -0,0 +1,578 @@ +"""Fit.py + +Parse FIT files. +""" + +import os, sys +import logging +import struct +import argparse +import time + +class FdtProperty: + def __init__(self, name, offset, sz): + self.name = name + self.offset = offset + self.sz = sz + +class FdtNode: + def __init__(self, name): + self.name = name + self.properties = {} + self.nodes = {} + +class Parser: + + FDT_MAGIC = 0xd00dfeed + + FDT_BEGIN_NODE = 1 + FDT_END_NODE = 2 + FDT_PROP = 3 + FDT_NOP = 4 + FDT_END = 9 + + def __init__(self, path=None, stream=None, log=None): + self.log = log or logging.getLogger(self.__class__.__name__) + self.path = path + self.stream = stream + self.rootNodes = {} + self._parse() + + def _parse(self): + if self.stream is not None: + try: + pos = self.stream.tell() + self._parseStream(self.stream) + finally: + self.stream.seek(pos, 0) + elif self.path is not None: + with open(self.path) as fd: + self._parseStream(fd) + else: + raise ValueError("missing file or stream") + + def _parseStream(self, fd): + strings = {} + + buf = fd.read(40) + hdr = list(struct.unpack(">10I", buf)) + magic = hdr.pop(0) + if magic != self.FDT_MAGIC: + raise ValueError("missing magic") + self.fdtSize = hdr.pop(0) + self.structPos = hdr.pop(0) + self.stringPos = hdr.pop(0) + self.version = hdr.pop(0) + if self.version < 17: + raise ValueError("invalid format version") + hdr.pop(0) # last compatible version + hdr.pop(0) # boot cpu + self.stringSize = hdr.pop(0) + self.structSize = hdr.pop(0) + + fd.seek(self.structPos, 0) + + def _align(): + pos = fd.tell() + pos = (pos+3) & ~3 + fd.seek(pos, 0) + + def _label(): + buf = "" + while True: + c = fd.read(1) + if c == '\x00': break + if c: + buf += c + return buf + + def _string(off): + if off in strings: + return strings[off] + pos = fd.tell() + fd.seek(self.stringPos, 0) + fd.seek(off, 1) + buf = _label() + fd.seek(pos) + return buf + + nodeStack = [] + + while True: + buf = fd.read(4) + s = list(struct.unpack(">I", buf)) + tag = s.pop(0) + + if tag == self.FDT_BEGIN_NODE: + name = _label() + _align() + + newNode = FdtNode(name) + + if nodeStack: + if name in nodeStack[-1].nodes: + raise ValueError("duplicate node") + nodeStack[-1].nodes[name] = newNode + nodeStack.append(newNode) + else: + if name in self.rootNodes: + raise ValueError("duplicate node") + self.rootNodes[name] = newNode + nodeStack.append(newNode) + + continue + + if tag == self.FDT_PROP: + buf = fd.read(8) + s = list(struct.unpack(">2I", buf)) + plen = s.pop(0) + nameoff = s.pop(0) + name = _string(nameoff) + pos = fd.tell() + fd.seek(plen, 1) + _align() + + newProp = FdtProperty(name, pos, plen) + + if nodeStack: + if name in nodeStack[-1].properties: + raise ValueError("duplicate property") + nodeStack[-1].properties[name] = newProp + else: + raise ValueError("property with no node") + + continue + + if tag == self.FDT_END_NODE: + if nodeStack: + nodeStack.pop(-1) + else: + raise ValueError("missing begin node") + continue + + if tag == self.FDT_NOP: + print "NOP" + continue + + if tag == self.FDT_END: + if nodeStack: + raise ValueError("missing end node(s)") + break + + raise ValueError("invalid tag %d" % tag) + + def report(self, stream=sys.stdout): + q = [(x, "") for x in self.rootNodes.values()] + while q: + n, pfx = q.pop(0) + + name = n.name or "/" + stream.write("%s%s\n" % (pfx, name,)) + + if n.properties: + stream.write("\n") + for p in n.properties.values(): + stream.write("%s %s (%d bytes)\n" + % (pfx, p.name, p.sz,)) + if n.properties: + stream.write("\n") + + pfx2 = pfx + " " + q[0:0] = [(x, pfx2) for x in n.nodes.values()] + + def getNode(self, path): + if path == '/': + return self.rootNodes.get('', None) + + els = path.split('/') + n = None + while els: + b = els.pop(0) + if n is None: + if b not in self.rootNodes: return None + n = self.rootNodes[b] + else: + if b not in n.nodes: return None + n = n.nodes[b] + return n + + def getNodeProperty(self, node, propName): + if propName not in node.properties: return None + prop = node.properties[propName] + def _get(fd): + fd.seek(self.structPos, 0) + fd.seek(prop.offset) + buf = fd.read(prop.sz) + if buf[-1] == '\x00': + return buf[:-1] + return buf + if self.stream is not None: + return _get(self.stream) + else: + with open(self.path) as fd: + return _get(fd) + + def dumpNodeProperty(self, node, propIsh, outPath): + if isinstance(propIsh, FdtProperty): + prop = propIsh + else: + if propIsh not in node.properties: + raise ValueError("missing property") + prop = node.properties[propIsh] + def _dump(fd): + with open(outPath, "w") as wfd: + fd.seek(prop.offset, 0) + buf = fd.read(prop.sz) + wfd.write(buf) + if self.stream is not None: + try: + pos = self.stream.tell() + _dump(self.stream) + finally: + self.stream.seek(pos, 0) + else: + with open(self.path) as fd: + _dump(fd) + + def getInitrdNode(self, profile=None): + """U-boot mechanism to retrieve boot profile.""" + + node = self.getNode('/configurations') + if node is None: + self.log.warn("missing /configurations node") + return None + if profile is not None: + if profile not in node.nodes: + self.log.warn("missing profile %s", profile) + return None + node = node.nodes[profile] + elif 'default' in node.properties: + pf = self.getNodeProperty(node, 'default') + self.log.debug("default profile is %s", pf) + node = node.nodes[pf] + else: + pf = node.nodes.keys()[0] + self.log.debug("using profile %s", pf) + node = node.nodes[pf] + + if 'ramdisk' not in node.properties: + self.log.warn("ramdisk property not found") + return None + rdName = self.getNodeProperty(node, 'ramdisk') + + self.log.debug("retrieving ramdisk %s", rdName) + node = self.getNode('/images/' + rdName) + return node + +class DumpRunner: + + def __init__(self, stream, + log=None): + self.log = log or logging.getLogger(self.__class__.__name__) + self.stream = stream + + def run(self): + p = Parser(stream=self.stream, log=self.log) + p.report() + return 0 + + def shutdown(self): + stream, self.stream = self.stream, None + if stream is not None: stream.close() + +class ExtractBase: + + def __init__(self, stream, + initrd=False, profile=None, path=None, + property=None, + log=None): + self.log = log or logging.getLogger(self.__class__.__name__) + self.stream = stream + self.initrd = initrd + self.profile = profile + self.path = path + self.property = property + + self.parser = None + self.node = None + self.dataProp = None + + def run(self): + self.parser = Parser(stream=self.stream, log=self.log) + if self.path is not None: + self.node = self.parser.getNode(self.path) + if self.node is None: + self.log.error("cannot find path") + return 1 + elif self.initrd: + self.node = self.parser.getInitrdNode(profile=self.profile) + if self.node is None: + self.log.error("cannot find initrd") + return 1 + else: + self.log.error("missing path or initrd") + return 1 + + def _t(n): + if n is None: return + self.dataProp = self.dataProp or self.node.properties.get(n, None) + _t(self.property) + _t('data') + _t('value') + if self.dataProp is None: + self.log.error("cannot find %s property", self.property) + return 1 + + return self._handleParsed() + + def _handleParsed(self): + raise NotImplementedError + + def shutdown(self): + stream, self.stream = self.stream, None + if stream is not None: stream.close() + +class ExtractRunner(ExtractBase): + + def __init__(self, stream, + outStream=None, + initrd=False, profile=None, path=None, + property=None, + text=False, numeric=False, timestamp=False, hex=False, + log=None): + ExtractBase.__init__(self, stream, + initrd=initrd, profile=profile, + path=path, + property=property, + log=log) + self.outStream = outStream + self.text = text + self.numeric = numeric + self.timestamp = timestamp + self.hex = hex + + def _handleParsed(self): + if (self.numeric or self.timestamp) and self.dataProp.sz != 4: + self.log.error("invalid size for number") + return 1 + def _dump(rfd, wfd): + rfd.seek(self.dataProp.offset, 0) + buf = rfd.read(self.dataProp.sz) + if self.text: + if buf[-1:] != '\x00': + self.log.error("missing NUL terminator") + return 1 + wfd.write(buf[:-1]) + return 0 + if self.numeric: + n = struct.unpack(">I", buf)[0] + wfd.write(str(n)) + return 0 + if self.timestamp: + n = struct.unpack(">I", buf)[0] + wfd.write(time.ctime(n)) + return 0 + if self.hex: + for c in buf: + wfd.write("%02x" % ord(c)) + return 0 + wfd.write(buf) + return 0 + if self.outStream is not None: + return _dump(self.stream, self.outStream) + else: + return _dump(self.stream, sys.stdout) + +class OffsetRunner(ExtractBase): + + def __init__(self, stream, + initrd=False, profile=None, path=None, + property=None, + log=None): + ExtractBase.__init__(self, stream, + initrd=initrd, profile=profile, + path=path, + property=property, + log=log) + + def _handleParsed(self): + start = self.dataProp.offset + self.log.debug("first byte is %d", start) + end = start + self.dataProp.sz - 1 + self.log.debug("data size is %d", self.dataProp.sz) + self.log.debug("last byte is %d", end) + sys.stdout.write("%s %s\n" % (start, end,)) + return 0 + +USAGE = """\ +pyfit [OPTIONS] dump|extract ... +""" + +EPILOG = """\ +Payload for 'offset' and 'extract' is specified as a given +PROPERTY for a tree node at PATH. + +Alternately, the initrd/ramdisk can be specified with '--initrd', +using the PROFILE machine configuration. If no PROFILE is specified, +the built-in default configuration from the FDT is used. +""" + +DESC="""\ +Extract or examine FIT file contents. +""" + +DUMP_USAGE = """\ +pyfit [OPTIONS] dump FIT-FILE +""" + +EXTRACT_USAGE = """\ +pyfit [OPTIONS] extract [OPTIONS] FIT-FILE +""" + +EXTRACT_EPILOG = """\ +Extracts payload to OUTPUT or to stdout if not specified. + +Output can be optionally reformatted +as a NUL-terminated string ('--text'), +as a decimal number ('--number'), +as a UNIX timestamp ('--timestamp'), +or as hex data ('--hex'). + +Numbers and timestamps must be 4-byte payloads. +""" + +OFFSET_USAGE = """\ +pyfit [OPTIONS] offset [OPTIONS] FIT-FILE +""" + +OFFSET_EPILOG = """\ +Outputs the first and last byte offsets, inclusive, containing the +payload. +""" + +class App: + + def __init__(self, log=None): + self.log = log or logging.getLogger("pyfit") + + def run(self): + + ap = argparse.ArgumentParser(usage=USAGE, + description=DESC, + epilog=EPILOG) + ap.add_argument('-q', '--quiet', action='store_true', + help="Suppress log messages") + ap.add_argument('-v', '--verbose', action='store_true', + help="Add more logging") + + sp = ap.add_subparsers() + + apd = sp.add_parser('dump', + help="Dump tree structure", + usage=DUMP_USAGE) + apd.set_defaults(mode='dump') + apd.add_argument('fit-file', type=open, + help="FIT file") + + apx = sp.add_parser('extract', + help="Extract items", + usage=EXTRACT_USAGE, + epilog=EXTRACT_EPILOG) + apx.set_defaults(mode='extract') + apx.add_argument('fit-file', type=open, + help="FIT file") + apx.add_argument('-o', '--output', + type=argparse.FileType('wb', 0), + help="File destination") + apx.add_argument('--initrd', action="store_true", + help="Extract platform initrd") + apx.add_argument('--profile', type=str, + help="Platform profile for initrd selection") + apx.add_argument('--path', type=str, + help="Tree path to extract") + apx.add_argument('--property', type=str, + help="Node property to extract") + apx.add_argument('--text', action='store_true', + help="Format property as text") + apx.add_argument('--numeric', action='store_true', + help="Format property as a number") + apx.add_argument('--hex', action='store_true', + help="Format property as hex") + apx.add_argument('--timestamp', action='store_true', + help="Format property as a date") + + apo = sp.add_parser('offset', + help="Extract item offset", + usage=OFFSET_USAGE, + epilog=OFFSET_EPILOG) + apo.set_defaults(mode='offset') + apo.add_argument('fit-file', type=open, + help="FIT file") + apo.add_argument('--initrd', action="store_true", + help="Extract platform initrd") + apo.add_argument('--profile', type=str, + help="Platform profile for initrd selection") + apo.add_argument('--path', type=str, + help="Tree path to extract") + apo.add_argument('--property', type=str, + help="Node property to extract") + + try: + args = ap.parse_args() + except SystemExit, what: + return what.code + + if args.quiet: + self.log.setLevel(logging.ERROR) + if args.verbose: + self.log.setLevel(logging.DEBUG) + + if args.mode == 'dump': + r = DumpRunner(getattr(args, 'fit-file'), log=self.log) + elif args.mode == 'extract': + r = ExtractRunner(getattr(args, 'fit-file'), + outStream=args.output, + path=args.path, + initrd=args.initrd, profile=args.profile, + property=args.property, + text=args.text, numeric=args.numeric, + timestamp=args.timestamp, hex=args.hex, + log=self.log) + elif args.mode == 'offset': + r = OffsetRunner(getattr(args, 'fit-file'), + path=args.path, + initrd=args.initrd, profile=args.profile, + property=args.property, + log=self.log) + else: + self.log.error("invalid mode") + return 1 + + try: + code = r.run() + except: + self.log.exception("runner failed") + code = 1 + r.shutdown() + return code + + def shutdown(self): + pass + + @classmethod + def main(cls): + logging.basicConfig() + logger = logging.getLogger("pyfit") + app = cls(log=logger) + try: + code = app.run() + except: + logger.exception("app failed") + code = 1 + app.shutdown() + sys.exit(code) + +main = App.main + +if __name__ == "__main__": + main() diff --git a/packages/base/all/vendor-config-onl/src/python/onl/install/InstallUtils.py b/packages/base/all/vendor-config-onl/src/python/onl/install/InstallUtils.py new file mode 100644 index 00000000..922aecef --- /dev/null +++ b/packages/base/all/vendor-config-onl/src/python/onl/install/InstallUtils.py @@ -0,0 +1,829 @@ +"""InstallUtils.py + +""" + +import os, sys +import stat +import logging +import subprocess +import tempfile +import string +import shutil + +class SubprocessMixin: + + V1 = "V1" + V2 = "V2" + + def check_call(self, *args, **kwargs): + args = list(args) + kwargs = dict(kwargs) + + cwd = kwargs.pop('cwd', None) + if cwd is not None: + self.log.debug("+ cd " + cwd) + + if args: + cmd = args.pop(0) + else: + cmd = kwargs.pop('cmd') + + vmode = kwargs.pop('vmode', None) + if vmode == self.V1 and self.log.isEnabledFor(logging.DEBUG): + if isinstance(cmd, basestring): + raise ValueError("vmode=V1 requires a list") + cmd = list(cmd) + cmd[1:1] = ['-v',] + if vmode == self.V2 and self.log.isEnabledFor(logging.DEBUG): + stdout = kwargs.pop('stdout', None) + stderr = kwargs.pop('stderr', None) + if stdout is not None: + raise ValueError("vmode=V2 conflicts with stdout") + if stderr is not None and stderr != subprocess.STDOUT: + raise ValueError("vmode=V2 conflicts with stderr") + fno, v2Out = tempfile.mkstemp(prefix='subprocess-', + suffix='out') + kwargs['stdout'] = fno + kwargs['stderr'] = subprocess.STDOUT + + if isinstance(cmd, basestring): + self.log.debug("+ " + cmd) + else: + self.log.debug("+ " + " ".join(cmd)) + + if vmode == self.V2 and self.log.isEnabledFor(logging.DEBUG): + try: + subprocess.check_call(cmd, *args, cwd=cwd, **kwargs) + finally: + with open(v2Out) as fd: + sys.stderr.write(fd.read()) + os.unlink(v2Out) + else: + subprocess.check_call(cmd, *args, cwd=cwd, **kwargs) + + def check_output(self, *args, **kwargs): + args = list(args) + kwargs = dict(kwargs) + + cwd = kwargs.pop('cwd', None) + if cwd is not None: + self.log.debug("+ cd " + cwd) + + if args: + cmd = args.pop(0) + else: + cmd = kwargs.pop('cmd') + + vmode = kwargs.pop('vmode', None) + if vmode == self.V1 and self.log.isEnabledFor(logging.DEBUG): + if isinstance(cmd, basestring): + raise ValueError("vmode=V1 requires a list") + cmd = list(cmd) + cmd[1:1] = ['-v',] + if vmode == self.V2 and self.log.isEnabledFor(logging.DEBUG): + stdout = kwargs.pop('stdout', None) + stderr = kwargs.pop('stderr', None) + if stdout is not None: + raise ValueError("vmode=V2 conflicts with stdout") + if stderr is not None and stderr != subprocess.STDOUT: + raise ValueError("vmode=V2 conflicts with stderr") + fno, v2Out = tempfile.mkstemp(prefix='subprocess-', + suffix='out') + kwargs['stderr'] = fno + + if isinstance(cmd, basestring): + self.log.debug("+ " + cmd) + else: + self.log.debug("+ " + " ".join(cmd)) + + if vmode == self.V2 and self.log.isEnabledFor(logging.DEBUG): + try: + return subprocess.check_output(cmd, *args, cwd=cwd, **kwargs) + finally: + with open(v2Out) as fd: + sys.stderr.write(fd.read()) + os.unlink(v2Out) + else: + return subprocess.check_output(cmd, *args, cwd=cwd, **kwargs) + + def rmdir(self, path): + self.log.debug("+ /bin/rmdir %s", path) + os.rmdir(path) + + def unlink(self, path): + self.log.debug("+ /bin/rm %s", path) + os.unlink(path) + + def rmtree(self, path): + self.log.debug("+ /bin/rm -fr %s", path) + shutil.rmtree(path) + + def mkdtemp(self, *args, **kwargs): + path = tempfile.mkdtemp(*args, **kwargs) + self.log.debug("+ /bin/mkdir %s", path) + return path + + def copy2(self, src, dst): + self.log.debug("+ /bin/cp -a %s %s", src, dst) + shutil.copy2(src, dst) + + def copyfile(self, src, dst): + self.log.debug("+ /bin/cp %s %s", src, dst) + shutil.copyfile(src, dst) + + def mkdir(self, path): + self.log.debug("+ /bin/mkdir %s", path) + os.mkdir(path) + + def makedirs(self, path): + self.log.debug("+ /bin/mkdir -p %s", path) + os.makedirs(path) + + def symlink(self, tgt, dst): + self.log.debug("+ /bin/ln -s %s %s", tgt, dst) + os.symlink(tgt, dst) + +class TempdirContext(SubprocessMixin): + + def __init__(self, prefix=None, suffix=None, chroot=None, log=None): + self.prefix = prefix + self.suffix = suffix + self.chroot = chroot + self.dir = None + self.hostDir = None + self.log = log or logging.getLogger("mount") + + def __enter__(self): + if self.chroot is not None: + self.hostDir = self.mkdtemp(prefix=self.prefix, + suffix=self.suffix, + dir=self.chroot + "/tmp") + self.dir = self.hostDir[len(self.chroot):] + else: + self.dir = self.hostDir = self.mkdtemp(prefix=self.prefix, + suffix=self.suffix) + return self + + def __exit__(self, type, value, tb): + if self.path: self.rmtree(self.hostDir) + return False + +class MountContext(SubprocessMixin): + + def __init__(self, device=None, chroot=None, label=None, fsType=None, log=None): + self.device = device + self.chroot = chroot + self.label = label + self.fsType = fsType + self.dir = None + self.hostDir = None + self.mounted = False + self.log = log or logging.getLogger("mount") + + if self.device and self.label: + raise ValueError("cannot specify device and label") + if not self.device and not self.label: + raise ValueError("no device or label specified") + + def __enter__(self): + dev = self.device + if dev is None: + try: + dev = self.check_output(('blkid', '-L', self.label,)).strip() + except subprocess.CalledProcessError, what: + raise ValueError("cannot find label %s: %s" + % (self.label, str(what),)) + + if self.chroot is not None: + self.hostDir = self.mkdtemp(prefix="mount-", + suffix=".d", + dir=self.chroot + "/tmp") + self.dir = self.hostDir[len(self.chroot):] + else: + self.dir = self.hostDir = self.mkdtemp(prefix="mount-", + suffix=".d") + + if self.fsType is not None: + cmd = ('mount', '-t', self.fsType, dev, self.hostDir,) + else: + cmd = ('mount', dev, self.hostDir,) + self.check_call(cmd, vmode=self.V1) + self.mounted = True + return self + + def __exit__(self, type, value, tb): + + mounted = False + if self.mounted: + p = ProcMountsParser() + for e in p.mounts: + if e.dir == self.hostDir: + mounted = True + break + # really mounted? + # maybe unmounted e.g. if inside a chroot + if mounted: + cmd = ('umount', self.hostDir,) + self.check_call(cmd, vmode=self.V1) + + self.rmdir(self.hostDir) + return False + +class BlkidEntry: + + def __init__(self, device, **kwargs): + + self.device = device + + kwargs = dict(kwargs) + self.label = kwargs.pop('label', None) + self.uuid = kwargs.pop('uuid', None) + self.fsType = kwargs.pop('fsType', None) + + @classmethod + def fromLine(cls, line): + line = line.strip() + p = line.find(':') + if p < 0: + raise ValueError("invalid blkid output %s" + % line) + dev, line = line[:p], line[p+1:].strip() + + attrs = {} + while line: + p = line.find('=') + if p < 0: + raise ValueError("invalid blkid output %s" + % line) + key = line[:p].lower() + if line[p+1:p+2] == "'": + q = line.find("'", p+2) + if q < 0: + val, line = line[p+1:], "" + else: + val, line = line[p+2:q], line[q+1:].strip() + elif line[p+1:p+2] == '"': + q = line.find('"', p+2) + if q < 0: + val, line = line[p+1:], "" + else: + val, line = line[p+2:q], line[q+1:].strip() + else: + q = line.find(" ", p+1) + if q < 0: + val, line = line[p+1:], "" + else: + val, line = line[p+1:], line[:q].strip() + + if key == 'type': key = 'fsType' + attrs[key] = val + + return cls(dev, **attrs) + + def splitDev(self): + dev, part = self.device, "" + while dev[-1:] in string.digits: + dev, part = dev[:-1], dev[-1] + part + return dev, part + + def isOnieReserved(self): + if self.label is None: return False + + if 'GRUB' in self.label: return True + if 'ONIE-BOOT' in self.label: return True + if 'DIAG' in self.label: return True + + return False + +class BlkidParser(SubprocessMixin): + + def __init__(self, log=None): + self.log = log or logging.getLogger("blkid") + self.parse() + + def parse(self): + cmd = ('blkid',) + lines = self.check_output(cmd).splitlines() + self.parts = [BlkidEntry.fromLine(line) for line in lines] + + def __getitem__(self, idxOrName): + if type(idxOrName) == int: + return self.parts[idxOrName] + for part in self.parts: + if part.label == idxOrName: return part + if part.uuid == idxOrName: return part + raise IndexError("cannot find partition %s" % repr(idxOrName)) + + def __len__(self): + return len(self.parts) + +class ProcMtdEntry: + + def __init__(self, + charDevice, blockDevice, + offset, size, eraseSize, + label=None): + + self.charDevice = charDevice + self.blockDevice = blockDevice + self.offset = offset + self.size = size + self.eraseSize = eraseSize + self.label = label + + @classmethod + def fromLine(cls, line, offset=0): + buf = line.strip() + p = buf.find(':') + if p < 0: + raise ValueError("invalid /proc/mtd entry %s" + % line) + dev, buf = buf[:p], buf[p+1:].strip() + dev = '/dev/' + dev + if not os.path.exists(dev): + raise ValueError("invalid /proc/mtd entry %s (missing device)" + % line) + st = os.stat(dev) + if stat.S_ISBLK(st.st_mode): + cdev, bdev = None, dev + elif stat.S_ISCHR(st.st_mode): + cdev, bdev = dev, None + else: + cdev, bdev = None, None + + if cdev and not bdev: + if cdev.startswith("/dev/mtd") and not cdev.startswith("/dev/mtdblock"): + bdev = "/dev/mtdblock" + cdev[8:] + if not os.path.exists(bdev): + raise ValueError("invalid /proc/mtd entry %s (cannot find block device)" + % line) + st = os.stat(bdev) + if not stat.S_ISBLK(st.st_mode): + raise ValueError("invalid /proc/mtd entry %s (cannot find block device)" + % line) + else: + raise ValueError("invalid /proc/mtd entry %s (cannot find block device)" + % line) + elif not bdev: + raise ValueError("invalid /proc/mtd entry %s (not a block or char device)" + % line) + + p = buf.find(" ") + if p < 0: + raise ValueError("invalid /proc/mtd entry %s (missing size)" + % line) + sz, buf = buf[:p], buf[p+1:].strip() + sz = int(sz, 16) + + if not buf: + raise ValueError("invalid /proc/mtd entry %s (missing erase size)" + % line) + p = buf.find(" ") + if p < 0: + esz, buf = buf, "" + else: + esz, buf = buf[:p], buf[p+1:].strip() + esz = int(esz, 16) + + if not buf: + label = None + elif len(buf) > 1 and buf[0:1] == "'" and buf[-1:] == "'": + label = buf[1:-1] + elif len(buf) > 1 and buf[0:1] == '"' and buf[-1:] == '"': + label = buf[1:-1] + else: + label = buf + + return cls(cdev, bdev, offset, sz, esz, label=label) + +class ProcMtdParser(): + + def __init__(self, log=None): + self.log = log or logging.getLogger("blkid") + self.parse() + + def parse(self): + self.parts = [] + offset = 0 + if os.path.exists("/proc/mtd"): + with open("/proc/mtd") as fd: + for line in fd.xreadlines(): + if line.startswith("dev:"): + pass + else: + part = ProcMtdEntry.fromLine(line, offset=offset) + offset += part.size + self.parts.append(part) + + def __getitem__(self, idxOrName): + if type(idxOrName) == int: + return self.parts[idxOrName] + for part in self.parts: + if part.label == idxOrName: return part + raise IndexError("cannot find MTD partition %s" % repr(idxOrName)) + + def __len__(self): + return len(self.parts) + +class PartedDiskEntry: + + def __init__(self, device, blocks, lbsz, pbsz, + model=None, typ=None, flags=[]): + self.device = device + + self.blocks = blocks + self.lbsz = lbsz + self.pbsz = pbsz + + self.model = model + self.typ = typ + self.flags = flags + + @classmethod + def fromLine(cls, line): + + line = line.strip() + if not line.endswith(';'): + raise ValueError("invalid parted line %s" % line) + line = line[:-1] + rec = line.split(':') + + def _s(): + secs = rec.pop(0) + if secs[-1:] != 's': + raise ValueError("invalid sector count %s" % secs) + return int(secs[:-1]) + + dev = rec.pop(0) + blocks = _s() + model = rec.pop(0) or None + lbsz = int(rec.pop(0), 10) + pbsz = int(rec.pop(0), 10) + typ = rec.pop(0) + label = rec.pop(0) or None + flags = rec.pop(0) + flags = [x.strip() for x in flags.split(',')] + + if rec: + raise ValueError("invalid parted line %s" % line) + + return cls(dev, blocks, lbsz, pbsz, + model=model, typ=typ, + flags=flags) + +class PartedPartEntry: + + def __init__(self, part, start, end, sz, + fs=None, label=None, flags=[]): + self.part = part + self.start = start + self.end = end + self.sz = sz + self.fs = fs + self.label = label + self.flags = flags + + @classmethod + def fromLine(cls, line): + + line = line.strip() + if not line.endswith(';'): + raise ValueError("invalid parted line %s" % line) + line = line[:-1] + rec = line.split(':') + + def _s(): + secs = rec.pop(0) + if secs[-1:] != 's': + raise ValueError("invalid sector count %s" % secs) + return int(secs[:-1]) + + part = int(rec.pop(0), 10) + if part < 1: + raise ValueError("invalid partition %d" % part) + start = _s() + end = _s() + sz = _s() + fs = rec.pop(0) or None + label = rec.pop(0) or None + flags = rec.pop(0) + flags = [x.strip() for x in flags.split(',')] + + if rec: + raise ValueError("invalid parted line %s" % line) + + return cls(part, start, end, sz, + fs=fs, label=label, + flags=flags) + +class PartedParser(SubprocessMixin): + + def __init__(self, device, log=None): + self.device = device + self.log = log or logging.getLogger("parted") + self.parse() + + def parse(self): + + cmd = ('parted', '-m', self.device, + 'unit', 's', + 'print',) + lines = self.check_output(cmd).splitlines() + self.disk = None + parts = {} + for line in lines: + if line.startswith('/dev/'): + self.disk = PartedDiskEntry.fromLine(line) + elif line[0:1] in string.digits: + ent = PartedPartEntry.fromLine(line) + if ent.part in parts: + raise ValueError("duplicate partition") + parts[ent.part] = ent + + self.parts = [] + for partno in sorted(parts.keys()): + self.parts.append(parts[partno]) + + if self.disk is None: + raise ValueError("no partition table found") + + def __len__(self): + return len(self.parts) + +class ProcMountsEntry: + + def __init__(self, device, dir, fsType, flags={}): + self.device = device + self.dir = dir + self.fsType = fsType + self.flags = flags + + @classmethod + def fromLine(cls, line): + buf = line.strip() + + idx = buf.find(' ') + if idx < 0: + raise ValueError("invalid /proc/mounts line %s", line) + + device, buf = buf[:idx], buf[idx+1:].strip() + + idx = buf.find(' ') + if idx < 0: + raise ValueError("invalid /proc/mounts line %s", line) + + dir, buf = buf[:idx], buf[idx+1:].strip() + + idx = buf.find(' ') + if idx < 0: + raise ValueError("invalid /proc/mounts line %s", line) + + fsType, buf = buf[:idx], buf[idx+1:].strip() + + idx = buf.rfind(' ') + if idx < 0: + raise ValueError("invalid /proc/mounts line %s", line) + + buf, _ = buf[:idx], buf[idx+1:].strip() + + idx = buf.rfind(' ') + if idx < 0: + buf = "" + else: + buf, _ = buf[:idx], buf[idx+1:].strip() + + flags = {} + if buf: + for flag in buf.split(','): + idx = flag.find('=') + if idx > -1: + key, val = flag[:idx], flag[idx+1:] + else: + key, val = flag, True + flags[key] = val + + return cls(device, dir, fsType, flags) + +class ProcMountsParser: + + def __init__(self): + self.parse() + + def parse(self): + self.mounts = [] + with open("/proc/mounts") as fd: + for line in fd.readlines(): + self.mounts.append(ProcMountsEntry.fromLine(line)) + +class InitrdContext(SubprocessMixin): + + def __init__(self, initrd=None, dir=None, log=None): + if initrd is None and dir is None: + raise ValueError("missing initrd or initrd dir") + if initrd and dir: + raise ValueError("cannot specify initrd and initrd dir") + self.initrd = initrd + self.dir = dir + self.hlog = log or logging.getLogger("mount") + self.ilog = self.hlog.getChild("initrd") + self.ilog.setLevel(logging.INFO) + self.log = self.hlog + + def _unpack(self): + self.dir = self.mkdtemp(prefix="chroot-", + suffix=".d") + with open(self.initrd) as fd: + mbuf = fd.read(1024) + if mbuf[0:2] == "\x1f\x8b": + c1 = ('gzip', '-dc', self.initrd,) + elif mbuf[0:2] == "BZ": + c1 = ('bzip2', '-dc', self.initrd,) + elif mbuf[0:6] == "\xfd7zXZ\x00": + c1 = ('xz', '-dc', self.initrd,) + else: + raise ValueError("cannot decode initrd") + c2 = ('cpio', '-imd',) + self.log.debug("+ %s | %s", + " ".join(c1), " ".join(c2)) + p1 = subprocess.Popen(c1, + stdout=subprocess.PIPE) + if self.log.isEnabledFor(logging.DEBUG): + p2 = subprocess.Popen(c2, + cwd=self.dir, + stdin=p1.stdout) + else: + p2 = subprocess.Popen(c2, + cwd=self.dir, + stdin=p1.stdout, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + c1 = p1.wait() + out, _ = p2.communicate() + c2 = p2.wait() + if c2 and out: + sys.stderr.write(out) + if c1 or c2: + raise ValueError("initrd unpack failed") + + def _prepDirs(self): + + dev2 = os.path.join(self.dir, "dev") + if not os.path.exists(dev2): + self.mkdir(dev2) + + for e in os.listdir(dev2): + dst = os.path.join(dev2, e) + if os.path.islink(dst): + self.unlink(dst) + elif os.path.isdir(dst): + self.rmtree(dst) + else: + self.unlink(dst) + + for e in os.listdir("/dev"): + src = os.path.join("/dev", e) + dst = os.path.join(dev2, e) + if os.path.islink(src): + self.symlink(os.readlink(src), dst) + elif os.path.isdir(src): + self.mkdir(dst) + elif os.path.isfile(src): + self.copy2(src, dst) + else: + st = os.stat(src) + if stat.S_ISBLK(st.st_mode): + maj, min = os.major(st.st_rdev), os.minor(st.st_rdev) + self.log.debug("+ mknod %s b %d %d", dst, maj, min) + os.mknod(dst, st.st_mode, st.st_rdev) + elif stat.S_ISCHR(st.st_mode): + maj, min = os.major(st.st_rdev), os.minor(st.st_rdev) + self.log.debug("+ mknod %s c %d %d", dst, maj, min) + os.mknod(dst, st.st_mode, st.st_rdev) + else: + self.log.debug("skipping device %s", src) + + dst = os.path.join(self.dir, "dev/pts") + if not os.path.exists(dst): + self.mkdir(dst) + + if 'TMPDIR' in os.environ: + dst = self.dir + os.environ['TMPDIR'] + if not os.path.exists(dst): + self.makedirs(dst) + + def __enter__(self): + + if self.initrd is not None: + + self.log.debug("extracting initrd %s", self.initrd) + self._unpack() + + self.log.debug("preparing chroot in %s", self.dir) + try: + self.log = self.ilog + self._prepDirs() + finally: + self.log = self.hlog + + dst = os.path.join(self.dir, "proc") + cmd = ('mount', '-t', 'proc', 'proc', dst,) + self.check_call(cmd, vmode=self.V1) + + dst = os.path.join(self.dir, "sys") + cmd = ('mount', '-t', 'sysfs', 'sysfs', dst,) + self.check_call(cmd, vmode=self.V1) + + dst = os.path.join(self.dir, "dev/pts") + cmd = ('mount', '-t', 'devpts', 'devpts', dst,) + self.check_call(cmd, vmode=self.V1) + + return self + + def __exit__(self, type, value, tb): + + p = ProcMountsParser() + dirs = [e.dir for e in p.mounts if e.dir.startswith(self.dir)] + + # XXX probabaly also kill files here + + # umount any nested mounts + self.log.debug("un-mounting mounts points in chroot %s", self.dir) + dirs.sort(reverse=True) + for p in dirs: + cmd = ('umount', p,) + self.check_call(cmd, vmode=self.V1) + + if self.initrd is not None: + self.log.debug("cleaning up chroot in %s", self.dir) + self.rmtree(self.dir) + else: + self.log.debug("saving chroot in %s", self.dir) + + return False + + @classmethod + def mkChroot(self, initrd, log=None): + with InitrdContext(initrd=initrd, log=log) as ctx: + initrdDir = ctx.dir + ctx.initrd = None + # save the unpacked directory, do not clean it up + # (it's inside this chroot anyway) + return initrdDir + +class ChrootSubprocessMixin: + + chrootDir = None + mounted = False + # initialize this in a concrete class + + def check_call(self, *args, **kwargs): + args = list(args) + kwargs = dict(kwargs) + + cwd = kwargs.pop('cwd', None) + if cwd is not None: + self.log.debug("+ cd " + cwd) + + if args: + cmd = args.pop(0) + else: + cmd = kwargs.pop('cmd') + if isinstance(cmd, basestring): + cmd = ('chroot', self.chrootDir, + '/bin/sh', '-c', 'IFS=;' + cmd,) + else: + cmd = ['chroot', self.chrootDir,] + list(cmd) + + if not self.mounted: + with InitrdContext(dir=self.chrootDir, log=self.log) as ctx: + self.log.debug("+ " + " ".join(cmd)) + subprocess.check_call(cmd, *args, cwd=cwd, **kwargs) + else: + self.log.debug("+ " + " ".join(cmd)) + subprocess.check_call(cmd, *args, cwd=cwd, **kwargs) + + def check_output(self, *args, **kwargs): + args = list(args) + kwargs = dict(kwargs) + + cwd = kwargs.pop('cwd', None) + if cwd is not None: + self.log.debug("+ cd " + cwd) + + if args: + cmd = args.pop(0) + else: + cmd = kwargs.pop('cmd') + if isinstance(cmd, basestring): + cmd = ('chroot', self.chrootDir, + '/bin/sh', '-c', 'IFS=;' + cmd,) + else: + cmd = ['chroot', self.chrootDir,] + list(cmd) + + if not self.mounted: + with InitrdContext(self.chrootDir, log=self.log) as ctx: + self.log.debug("+ " + " ".join(cmd)) + return subprocess.check_output(cmd, *args, cwd=cwd, **kwargs) + else: + self.log.debug("+ " + " ".join(cmd)) + return subprocess.check_output(cmd, *args, cwd=cwd, **kwargs) diff --git a/packages/base/all/vendor-config-onl/src/python/onl/install/RecoverApp.py b/packages/base/all/vendor-config-onl/src/python/onl/install/RecoverApp.py new file mode 100644 index 00000000..2a4abf4b --- /dev/null +++ b/packages/base/all/vendor-config-onl/src/python/onl/install/RecoverApp.py @@ -0,0 +1,81 @@ +"""RecoverApp.py + +Application-level code for Switch Light recovery. +""" + +import os, sys +import imp +import logging +from ConfUtils import UbootEnv + +class App: + + def __init__(self, log=None): + + if log is not None: + self.log = log + else: + self.log = logging.getLogger(self.__class__.__name__) + + self.recovery = None + + def run(self): + + if os.path.exists(UbootEnv.SETENV): + self.ubootEnv = UbootEnv(log=self.log.getChild("u-boot")) + else: + self.ubootEnv = None + + # load the platform-specific blob + if os.path.exists("/etc/onl/platform"): + with open("/etc/onl/platform") as fd: + plat = fd.read().strip() + else: + self.log.error("cannot recover non-ONL platform") + return 1 + + p = ("/lib/platform-config/%s/python/recover.py" + % (plat,)) + if not os.path.exists(p): + self.log.error("missing recover profile %s", p) + return 1 + mod = imp.load_source("platform_recover", p) + + # run the platform-specific installer + self.recovery = mod.Recovery(ubootEnv=self.ubootEnv, + log=self.log) + try: + code = self.recovery.run() + except: + self.log.exception("recovery failed") + code = 1 + if code: return code + + return 0 + + def shutdown(self): + + recovery, self.recovery = self.recovery, None + if recovery is not None: + recovery.shutdown() + + @classmethod + def main(cls): + + logging.basicConfig() + logger = logging.getLogger("recover") + logger.setLevel(logging.DEBUG) + + app = cls(log=logger) + try: + code = app.run() + except: + logger.exception("runner failed") + code = 1 + app.shutdown() + sys.exit(code) + +main = App.main + +if __name__ == "__main__": + main() diff --git a/packages/base/all/vendor-config-onl/src/python/onl/install/ShellApp.py b/packages/base/all/vendor-config-onl/src/python/onl/install/ShellApp.py new file mode 100644 index 00000000..add79f67 --- /dev/null +++ b/packages/base/all/vendor-config-onl/src/python/onl/install/ShellApp.py @@ -0,0 +1,251 @@ +"""ShellApp.py +""" + +import os, sys +import glob +import tempfile +import logging +import subprocess +import argparse +import string +import struct +from InstallUtils import InitrdContext, MountContext +from InstallUtils import SubprocessMixin +from InstallUtils import ProcMountsParser, ProcMtdParser +import Fit + +class AppBase(SubprocessMixin): + + @property + def PROG(self): + raise NotImplementedError + + def __init__(self, command=None, log=None): + + if log is not None: + self.log = log + else: + self.log = logging.getLogger(self.__class__.__name__) + self.command = command + + def _runInitrdShell(self, initrd): + with InitrdContext(initrd=initrd, log=self.log) as ctx: + if self.command is not None: + cmd = ('chroot', ctx.dir, + '/bin/sh', '-c', 'IFS=;' + self.command) + else: + cmd = ('chroot', ctx.dir, + '/bin/sh', '-i') + try: + self.check_call(cmd) + except subprocess.CalledProcessError, what: + pass + return 0 + + def _runMtdShell(self, device): + self.log.debug("parsing FIT image in %s", device) + p = Fit.Parser(path=device, log=self.log) + node = p.getInitrdNode() + if node is None: + self.log.error("cannot find initrd node in FDT") + return 1 + prop = node.properties.get('data', None) + if prop is None: + self.log.error("cannot find initrd data property in FDT") + return 1 + with open(device) as fd: + self.log.debug("reading initrd at [%x:%x]", + prop.offset, prop.offset+prop.sz) + fd.seek(prop.offset, 0) + buf = fd.read(prop.sz) + try: + fno, initrd = tempfile.mkstemp(prefix="initrd-", + suffix=".img") + self.log.debug("+ cat > %s", initrd) + with os.fdopen(fno, "w") as fd: + fd.write(buf) + return self._runInitrdShell(initrd) + finally: + self.unlink(initrd) + + def shutdown(self): + pass + + @classmethod + def main(cls): + + logging.basicConfig() + logger = logging.getLogger(cls.PROG) + logger.setLevel(logging.INFO) + + ap = argparse.ArgumentParser(prog=cls.PROG) + ap.add_argument('-v', '--verbose', action='store_true', + help='Enable verbose logging') + ap.add_argument('-q', '--quiet', action='store_true', + help='Suppress logging') + ap.add_argument('-c', type=str, dest='command', + help='Run a batch command') + + try: + args = ap.parse_args() + except SystemExit, what: + sys.exit(what.code) + + if args.verbose: + logger.setLevel(logging.DEBUG) + if args.quiet: + logger.setLevel(logging.ERROR) + + app = cls(command=args.command, log=logger) + try: + code = app.run() + except: + logger.exception("runner failed") + code = 1 + app.shutdown() + sys.exit(code) + +class Onie(AppBase): + + PROG = "onie-shell" + + def run(self): + + def _g(d): + pat = os.path.join(d, "onie/initrd.img*") + l = glob.glob(pat) + if l: return l[0] + return None + + # try to find onie initrd on a mounted fs (GRUB) + initrd = _g("/mnt/onie-boot") + if initrd is not None: + self.log.debug("found ONIE initrd at %s", initrd) + return self._runInitrdShell(initrd) + + # try to find the onie boot partition elsewhere + pm = ProcMountsParser() + try: + dev = self.check_output(('blkid', '-L', 'ONIE-BOOT',)).strip() + except subprocess.CalledProcessError, what: + dev = None + if dev is not None: + self.log.debug("found ONIE boot device %s", dev) + parts = [p for p in pm.mounts if p.device == dev] + if parts: + onieDir = parts[0] + self.log.debug("found ONIE boot mounted at %s", onieDir) + initrd = _g(onieDir) + if initrd is not None: + self.log.debug("found ONIE initrd at %s", initrd) + return _runInitrdShell(initrd) + else: + self.log.error("cannot find ONIE initrd") + return 1 + else: + with MountContext(dev, fsType='ext4', log=self.log) as ctx: + initrd = _g(ctx.dir) + if initrd is not None: + self.log.debug("found ONIE initrd at %s", initrd) + return self._runInitrdShell(initrd) + else: + self.log.error("cannot find ONIE initrd") + return 1 + + # grovel through MTD devices (u-boot) + pm = ProcMtdParser(log=self.log) + parts = [p for p in pm.parts if p.label == "onie"] + if parts: + part = parts[0] + self.log.debug("found ONIE MTD device %s", + part.charDevice or part.blockDevice) + return self._runMtdShell(part.blockDevice) + elif pm.parts: + self.log.error("cannot find ONIE MTD device") + return 1 + + self.log.error("cannot find ONIE initrd") + return 1 + +class Loader(AppBase): + + PROG = "loader-shell" + + def run(self): + + def _g(d): + pat = os.path.join(d, "initrd-*") + l = glob.glob(pat) + if l: return l[0] + return None + + # try to find the loader boot partition as a formatted block device + pm = ProcMountsParser() + try: + dev = self.check_output(('blkid', '-L', 'SL-BOOT',)).strip() + except subprocess.CalledProcessError, what: + dev = None + if dev is not None: + self.log.debug("found loader device %s", dev) + parts = [p for p in pm.mounts if p.device == dev] + if parts: + loaderDir = parts[0] + self.log.debug("found loader device mounted at %s", loaderDir) + initrd = _g(loaderDir) + if initrd is not None: + self.log.debug("found loader initrd at %s", initrd) + return _runInitrdShell(initrd) + else: + self.log.error("cannot find loader initrd") + return 1 + else: + with MountContext(dev, fsType='ext4', log=self.log) as ctx: + initrd = _g(ctx.dir) + if initrd is not None: + self.log.debug("found loader initrd at %s", initrd) + return self._runInitrdShell(initrd) + else: + self.log.error("cannot find loader initrd") + return 1 + + # try to find the loader partition on the same desk as /mnt/flash + try: + flashDev = self.check_output(('blkid', '-L', 'FLASH',)).strip() + except subprocess.CalledProcessError, what: + flashDev = None + if flashDev is not None: + self.log.debug("found flash device hint %s", flashDev) + loaderDev = flashDev + while loaderDev and loaderDev[-1] in string.digits: + loaderDev = loaderDev[:-1] + loaderDev = loaderDev + '1' + with open(loaderDev) as fd: + buf = fd.read(4) + magic = struct.unpack(">I", buf)[0] + if magic == Fit.Parser.FDT_MAGIC: + self.log.debug("found loader device %s", loaderDev) + return self._runMtdShell(loaderDev) + else: + self.log.error("bad FDT signature on %s %x", + loaderDev, magic) + return 1 + + # grovel through MTD devices (u-boot) + pm = ProcMtdParser(log=self.log) + parts = [p for p in pm.parts if p.label == "sl-boot"] + if parts: + part = parts[0] + self.log.debug("found loader MTD device %s", + part.charDevice or part.blockDevice) + return self._runMtdShell(part.blockDevice) + elif pm.parts: + self.log.error("cannot find loader MTD device") + return 1 + + self.log.error("cannot find loader initrd") + return 1 + +main = Onie.main + +if __name__ == "__main__": + main() diff --git a/packages/base/all/vendor-config-onl/src/python/onl/install/__init__.py b/packages/base/all/vendor-config-onl/src/python/onl/install/__init__.py new file mode 100644 index 00000000..584287a7 --- /dev/null +++ b/packages/base/all/vendor-config-onl/src/python/onl/install/__init__.py @@ -0,0 +1,4 @@ +"""__init__.py + +Module setup for switchlight.install +""" From 90a45eff50deb97ed84d64018fea3e0e6298dd7a Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Mon, 2 May 2016 12:52:13 -0700 Subject: [PATCH 005/113] Yaml helper module - util for loading the mongrel YAML platform definitons --- .../src/python/onl/YamlUtils.py | 107 ++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 packages/base/all/vendor-config-onl/src/python/onl/YamlUtils.py diff --git a/packages/base/all/vendor-config-onl/src/python/onl/YamlUtils.py b/packages/base/all/vendor-config-onl/src/python/onl/YamlUtils.py new file mode 100644 index 00000000..44822148 --- /dev/null +++ b/packages/base/all/vendor-config-onl/src/python/onl/YamlUtils.py @@ -0,0 +1,107 @@ +"""YamlUtils.py + +""" + +import yaml +try: + import onlyaml + def load(stream): + return yaml.load(stream, Loader=onlyaml.Loader) +except ImportError: + load = yaml.load + +def merge(p1, p2): + """Merge two YAML files. + + y1 is the 'default' source; leaf values from y2 will override. + Return the merged tree. + + y1 should be a dict with a single top-level key, 'default'. + y2 should be a dict with a single top-level key, not 'default'. + + Set a leaf in y2 to nil ('~') to create a tombstone (discard any key + from y1). + + if a (sub) key in y1, y2 differ in type (dict vs. non-dict) then + the merge will proceed with the non-dict promoted to a dict using + the default-key schema ('='). Consumers of this function should be + prepared to handle such keys. + """ + + with open(p1) as fd: + buf1 = fd.read() + with open(p2) as fd: + buf2 = fd.read() + + # read p1 as-is, make sure it looks like a 'default' YAML + c1 = load(buf1) + k1 = list(c1.keys()) + if k1 != ['default']: + raise ValueError("%s: invalid top-level keys for default mapping: %s" + % (p1, k1,)) + + # read p2 with the default YAML as a sub-key (to resolve anchors) + lines = buf2.splitlines(False) + lines = [x for x in lines if x != '---'] + buf3 = buf1 + "\n" + "\n".join(lines) + c2 = load(buf3) + c2.pop('default', None) + + k2 = list(c2.keys()) + if len(k2) != 1: + raise ValueError("invalid format for target mapping") + tgtKey = k2[0] + + merged = { tgtKey : {} } + q = [(c1['default'], c2[tgtKey], merged[tgtKey])] + while True: + if not q: break + c1, c2, c3 = q.pop(0) + # add in non-overlapping keys + # 'None' keys from p2 are tombstones + s1 = set(c1.keys()) + s2 = set(c2.keys()) + + for k in s1.difference(s2): + v = c1[k] + if type(v) == dict: + c3.setdefault(k, {}) + q.append((v, {}, c3[k],)) + else: + c3.setdefault(k, v) + + for k in s2.difference(s1): + v = c2[k] + if v is None: continue + if type(v) == dict: + c3.setdefault(k, {}) + q.append(({}, v, c3[k],)) + else: + c3.setdefault(k, v) + + # handle overlapping keys + for k in s1.intersection(s2): + v1 = c1[k] + v2 = c2[k] + + if v2 is None: continue + + # two dicts, key-by-key reconciliation required + if type(v1) == dict and type(v2) == dict: + c3.setdefault(k, {}) + q.append((v1, v2, c3[k],)) + continue + + # two non-dicts, p2 wins + if type(v1) != dict and type(v2) != dict: + c3[k] = v2 + continue + + if type(v1) != dict: + v1 = { '=' : v1, } + if type(v2) != dict: + v2 = { '=' : v2, } + c3.setdefault(k, {}) + q.append((v1, v2, c3[k],)) + + return merged From 972f2cdf6f0bc112858b4de9ac0003bccfca1e57 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Mon, 2 May 2016 12:53:01 -0700 Subject: [PATCH 006/113] Update the YAML loader for platform configs --- .../src/python/onl/platform/base.py | 35 ++++++++++++++++--- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/packages/base/all/vendor-config-onl/src/python/onl/platform/base.py b/packages/base/all/vendor-config-onl/src/python/onl/platform/base.py index 8bf9a2a2..874782a4 100644 --- a/packages/base/all/vendor-config-onl/src/python/onl/platform/base.py +++ b/packages/base/all/vendor-config-onl/src/python/onl/platform/base.py @@ -10,11 +10,13 @@ ############################################################ import pprint -import yaml import json import os import re +import yaml +import onl.YamlUtils + class OnlInfoObject(object): DEFAULT_INDENT=" " @@ -99,18 +101,41 @@ class OnlPlatformBase(object): CONFIG_DIR='/lib/platform-config' CURRENT_DIR=os.path.join(CONFIG_DIR, 'current') + CONFIG_DEFAULT_GRUB = "/lib/vendor-config/onl/platform-config-defaults-x86-64.yml" + CONFIG_DEFAULT_UBOOT = "/lib/vendor-config/onl/platform-config-defaults-uboot.yml" + def __init__(self): self.add_info_json("onie_info", "%s/onie-info.json" % self.basedir_onl(), OnieInfo, required=False) self.add_info_json("platform_info", "%s/platform-info.json" % self.basedir_onl(), required=False) - # Load the platform config yaml file - y = os.path.join(self.basedir_onl(), "%s.yml" % self.platform()) - if os.path.exists(y): - self.platform_config = yaml.load(open(y)) + # Find the base platform config + if self.platform().startswith('x86-64'): + y1 = self.CONFIG_DEFAULT_GRUB + elif self.platform().startswith('powerpc'): + y1 = self.CONFIG_DEFAULT_UBOOT + elif self.platform().startswith('arm'): + y1 = self.CONFIG_DEFAULT_UBOOT + else: + y1 = None + + # Find and load the platform config yaml file + y2 = os.path.join(self.basedir_onl(), "%s.yml" % self.platform()) + if os.path.exists(y1) and os.path.exists(y2): + self.platform_config = onl.YamlUtils.merge(y1, y2) if self.platform() in self.platform_config: self.platform_config = self.platform_config[self.platform()] + elif os.path.exists(y2): + with open(y2) as fd: + self.platform_config = yaml.load(fd) + if self.platform() in self.platform_config: + self.platform_config = self.platform_config[self.platform()] + elif os.path.exists(y1): + with open(y1) as fd: + self.platform_config = yaml.load(fd) + if 'default' in self.platform_config: + self.platform_config = self.platform_config['default'] else: self.platform_config = {} From 15c7af3999280aa9ed2475387455b866412f9bf1 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Mon, 2 May 2016 12:53:33 -0700 Subject: [PATCH 007/113] Platform config updates - get the platform type from /etc/machine.conf if run from ONIE --- .../src/python/onl/platform/current.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/packages/base/all/vendor-config-onl/src/python/onl/platform/current.py b/packages/base/all/vendor-config-onl/src/python/onl/platform/current.py index 68606154..545fac04 100644 --- a/packages/base/all/vendor-config-onl/src/python/onl/platform/current.py +++ b/packages/base/all/vendor-config-onl/src/python/onl/platform/current.py @@ -14,12 +14,23 @@ # platform-config packages. # ############################################################ +import os import importlib def import_subsystem_platform_class(subsystem='onl', klass='OnlPlatform'): # Determine the current platform name. - with open("/etc/onl/platform", 'r') as f: - platform=f.read().strip() + platform = None + if os.path.exists("/etc/onl/platform"): + with open("/etc/onl/platform", 'r') as f: + platform=f.read().strip() + elif os.path.exists("/etc/machine.conf"): + with open("/etc/machine.conf", 'r') as f: + lines = f.readlines(False) + lines = [x for x in lines if x.startswith('onie_platform=')] + if lines: + platform = lines[0].partition('=')[2].strip() + if platform is None: + raise RuntimeError("cannot find a platform declaration") platform_module = platform.replace('-', '_') From a780c0b5ebabd350c55ca424b9c98500243c42f9 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Mon, 2 May 2016 12:55:05 -0700 Subject: [PATCH 008/113] Userland tools for new installer --- .../base/all/vendor-config-onl/src/bin/loader-shell | 11 +++++++++++ .../base/all/vendor-config-onl/src/bin/onie-shell | 11 +++++++++++ .../base/all/vendor-config-onl/src/bin/onl-install | 11 +++++++++++ .../base/all/vendor-config-onl/src/bin/onl-recover | 11 +++++++++++ packages/base/all/vendor-config-onl/src/bin/pyfit | 11 +++++++++++ 5 files changed, 55 insertions(+) create mode 100755 packages/base/all/vendor-config-onl/src/bin/loader-shell create mode 100755 packages/base/all/vendor-config-onl/src/bin/onie-shell create mode 100755 packages/base/all/vendor-config-onl/src/bin/onl-install create mode 100755 packages/base/all/vendor-config-onl/src/bin/onl-recover create mode 100755 packages/base/all/vendor-config-onl/src/bin/pyfit diff --git a/packages/base/all/vendor-config-onl/src/bin/loader-shell b/packages/base/all/vendor-config-onl/src/bin/loader-shell new file mode 100755 index 00000000..0ee08028 --- /dev/null +++ b/packages/base/all/vendor-config-onl/src/bin/loader-shell @@ -0,0 +1,11 @@ +#!/usr/bin/python + +"""Run native ONIE tools +""" + +import sys +import distutils.sysconfig +sys.path.append("/usr/lib/python%s/dist-packages" + % distutils.sysconfig.get_python_version()) +import onl.install.ShellApp +onl.install.ShellApp.Loader.main() diff --git a/packages/base/all/vendor-config-onl/src/bin/onie-shell b/packages/base/all/vendor-config-onl/src/bin/onie-shell new file mode 100755 index 00000000..ecf8b7a3 --- /dev/null +++ b/packages/base/all/vendor-config-onl/src/bin/onie-shell @@ -0,0 +1,11 @@ +#!/usr/bin/python + +"""Run native ONIE tools +""" + +import sys +import distutils.sysconfig +sys.path.append("/usr/lib/python%s/dist-packages" + % distutils.sysconfig.get_python_version()) +import onl.install.ShellApp +onl.install.ShellApp.Onie.main() diff --git a/packages/base/all/vendor-config-onl/src/bin/onl-install b/packages/base/all/vendor-config-onl/src/bin/onl-install new file mode 100755 index 00000000..6d961e6e --- /dev/null +++ b/packages/base/all/vendor-config-onl/src/bin/onl-install @@ -0,0 +1,11 @@ +#!/usr/bin/python + +"""Install switch light +""" + +import sys +import distutils.sysconfig +sys.path.append("/usr/lib/python%s/dist-packages" + % distutils.sysconfig.get_python_version()) +import onl.install.App +onl.install.App.main() diff --git a/packages/base/all/vendor-config-onl/src/bin/onl-recover b/packages/base/all/vendor-config-onl/src/bin/onl-recover new file mode 100755 index 00000000..f7b6f0c0 --- /dev/null +++ b/packages/base/all/vendor-config-onl/src/bin/onl-recover @@ -0,0 +1,11 @@ +#!/usr/bin/python + +"""Recover switch light +""" + +import sys +import distutils.sysconfig +sys.path.append("/usr/lib/python%s/dist-packages" + % distutils.sysconfig.get_python_version()) +import onl.install.RecoverApp +onl.install.RecoverApp.main() diff --git a/packages/base/all/vendor-config-onl/src/bin/pyfit b/packages/base/all/vendor-config-onl/src/bin/pyfit new file mode 100755 index 00000000..ea644d72 --- /dev/null +++ b/packages/base/all/vendor-config-onl/src/bin/pyfit @@ -0,0 +1,11 @@ +#!/usr/bin/python + +"""Swiss-army-knife FIT decoder +""" + +import sys +import distutils.sysconfig +sys.path.append("/usr/lib/python%s/dist-packages" + % distutils.sysconfig.get_python_version()) +import onl.install.Fit +onl.install.Fit.App.main() From 2a1bb49f18b8f75f605c19af57cfd5597e452bad Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Mon, 2 May 2016 12:55:53 -0700 Subject: [PATCH 009/113] Helper shell code for new installer --- .../vendor-config-onl/src/lib/install/lib.sh | 101 ++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 packages/base/all/vendor-config-onl/src/lib/install/lib.sh diff --git a/packages/base/all/vendor-config-onl/src/lib/install/lib.sh b/packages/base/all/vendor-config-onl/src/lib/install/lib.sh new file mode 100644 index 00000000..5537de43 --- /dev/null +++ b/packages/base/all/vendor-config-onl/src/lib/install/lib.sh @@ -0,0 +1,101 @@ +#!/bin/sh +# +###################################################################### +# +# helper functions for install +# +###################################################################### + +installer_reboot() { + local dummy sts timeout trapsts + if test $# -gt 0; then + timeout=$1; shift + else + timeout=3 + fi + + installer_say "Rebooting in ${timeout}s" + + unset dummy trapsts + # ha ha, 'local' auto-binds the variables + + trap "trapsts=130" 2 + if read -t $timeout -r -p "Hit CR to continue, CTRL-D or CTRL-C to stop... " dummy; then + sts=0 + else + sts=$? + fi + trap - 2 + test "$trapsts" && sts=$trapsts + + if test ${dummy+set}; then + if test $sts -eq 0; then + installer_say "CR, rebooting" + exit + else + installer_say "CTRL-D, stopped" + exit + fi + fi + + # ha ha, busybox does not report SIGALRM + if test "${trapsts+set}"; then + : + else + installer_say "timeout, rebooting" + reboot + fi + + signo=$(( $sts - 128 )) + if test $signo -eq 14; then + # SIGALRM, possibly irrelevant for busybox + installer_say "timeout, rebooting" + reboot + fi + + # e.g. SIGQUIT + installer_say "signal $signo, stopped" + exit +} + +installer_mkchroot() { + local rootdir + rootdir=$1 + + # special handling for /dev, which usually already has nested mounts + installer_say "Setting up /dev" + rm -fr "${rootdir}/dev"/* + for dev in /dev/*; do + if test -d "$dev"; then + mkdir "${rootdir}${dev}" + else + cp -a "$dev" "${rootdir}${dev}" + fi + done + mkdir -p "${rootdir}/dev/pts" + + installer_say "Setting up mounts" + mount -t proc proc "${rootdir}/proc" + mount -t sysfs sysfs "${rootdir}/sys" + mount -t devpts devpts "${rootdir}/dev/pts" + + if test ${TMPDIR+set}; then + # make the tempdir available to the chroot + mkdir -p "${rootdir}${TMPDIR}" + fi + + # export ONIE defines to the installer + if test -r /etc/machine.conf; then + cp /etc/machine.conf "${rootdir}/etc/machine.conf" + fi + + # export firmware config + if test -r /etc/fw_env.config; then + cp /etc/fw_env.config "${rootdir}/etc/fw_env.config" + fi +} + +# Local variables +# mode: sh +# sh-basic-offset: 2 +# End: From 87fbe5d56febd4ae6f6956ffb24ca1dbe09dc14a Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Mon, 2 May 2016 12:56:59 -0700 Subject: [PATCH 010/113] Sample templates for platform configs --- .../lib/platform-config-defaults-uboot.yml | 62 ++++++++++ .../lib/platform-config-defaults-x86-64.yml | 106 ++++++++++++++++++ 2 files changed, 168 insertions(+) create mode 100644 packages/base/all/vendor-config-onl/src/lib/platform-config-defaults-uboot.yml create mode 100644 packages/base/all/vendor-config-onl/src/lib/platform-config-defaults-x86-64.yml diff --git a/packages/base/all/vendor-config-onl/src/lib/platform-config-defaults-uboot.yml b/packages/base/all/vendor-config-onl/src/lib/platform-config-defaults-uboot.yml new file mode 100644 index 00000000..c23835c8 --- /dev/null +++ b/packages/base/all/vendor-config-onl/src/lib/platform-config-defaults-uboot.yml @@ -0,0 +1,62 @@ +--- + +###################################################################### +# +# platform-config-defaults-uboot.yml +# +# Configuration for u-boot systems (powerpc and arm) +# +###################################################################### + +default: + + flat_image_tree: + + ############################## + # + # Default kernel packages provided by ONL + # + ############################## + + e500v-kernel-package: &e500v-kernel-package + package: onl-kernel-3.9.6-powerpc-e500v:powerpc + + e500v-kernel: &e500v-kernel + =: kernel-3.9.6-powerpc-e500v.bin.gz + <<: *e500v-kernel-package + + e500mc-kernel-package: &e500mc-kernel-package + package: onl-kernel-3.8.13-powerpc-e500mc:powerpc + + e500mc-kernel: + =: kernel-3.8.13-powerpc-e500mc.bin.gz + <<: *e500mc-kernel-package + + arm-iproc-kernel-package: &arm-iproc-kernel-package + package: onl-kernel-3.2-deb7-arm-iproc-all:armel + + arm-iproc-kernel: + =: kernel-3.2-deb7-arm-iproc-all.bin.gz + <<: *arm-iproc-kernel-package + + ############################## + # + # For your system, pick from the above list + # to compose a 'kernel' and 'dtb' key + # + ############################## + + ### Example, pick one kernel and one DTB + ##kernel: + ## <<: *e500v-kernel + ##dtb: + ## =: powerpc-quanta-lb9-r0.dtb + ## <<: *e500v-kernel-package + + loader: + + partition: /dev/sda1 + ##partition: /dev/mmcblk0p1 + + ### True for raw partitions + ##raw: True diff --git a/packages/base/all/vendor-config-onl/src/lib/platform-config-defaults-x86-64.yml b/packages/base/all/vendor-config-onl/src/lib/platform-config-defaults-x86-64.yml new file mode 100644 index 00000000..2b188f5c --- /dev/null +++ b/packages/base/all/vendor-config-onl/src/lib/platform-config-defaults-x86-64.yml @@ -0,0 +1,106 @@ +--- + +###################################################################### +# +# platform-config-defaults-x86-64.yml +# +# Default settings for x86-64 platform-config YAML declarations +# +# X86 platforms assume a GPT partition table and ext4 partitions +# +###################################################################### + +default: + + grub: + + label: gpt + # default, use a GPT (not msdos) label + # this is mostly to *reject* invalid disk labels, + # since we will never create our own + + initrd-amd64: &initrd-amd64 + =: onl-loader-initrd-amd64.cpio.gz + package: onl-loader-initrd:amd64 + + initrd: + <<: *initrd-amd64 + + kernel-3.2: &kernel-3-2 + =: kernel-3.2-deb7-x86_64-all + package: onl-kernel-3.2-deb7-x86-64-all:amd64 + + kernel-3.9.6: &kernel-3-9-6 + =: kernel-3.9.6-x86-64-all + package: onl-kernel-3.9.6-x86-64-all:amd64 + + kernel-3.18: &kernel-3-18 + =: kernel-3.18-x86_64-all + package: onl-kernel-3.18-x86-64-all:amd64 + + # pick one of the above kernels + kernel: + <<: *kernel-3-2 + + # GRUB command line arguments for 'serial' declaration + # this is equivalent to, but not in the same format as, + # the linux 'console=' arguments below + # Default for ttyS1 + serial: >- + --port=0x2f8 + --speed=115200 + --word=8 + --parity=no + --stop=1 + + # supplemental kernel arguments + # (not including kernel, initrd and ONL-specific options) + # Default for ttyS1 + args: >- + nopat + console=ttyS1,115200n8 + + ### Defaults for ttyS0 + ##serial: >- + ## --port=0x3f8 + ## --speed=115200 + ## --word=8 + ## --parity=no + ## --stop=1 + ##args: >- + ## nopat + ## console=ttyS0,115200n8 + + ##device: /dev/vda + ### install to a specific block device + + device: ONIE-BOOT + # install to the device that contains the ONIE-BOOT partition + # (query using parted and/or blkid) + + # Default partitioning scheme + # boot, config --> 128MiB + # images --> 1GiB + # data --> rest of disk + # default format (as shown) is ext4 + installer: + - ONL-BOOT: + =: 128MiB + format: ext4 + - ONL-CONFIG: + =: 128MiB + format: ext4 + - ONL-IMAGES: + =: 1GiB + format: ext4 + - ONL-DATA: + =: 100% + format: ext4 + + ### Sample partitioning scheme experiencing disk space pressure + ##installer: + ##- ONL-BOOT: 128MiB + ##- ONL-CONFIG: 128MiB + ##- ONL-IMAGES: 384MiB + ##- ONL-DATA: 100% + From a5e443274f165f2d3be78c0c9a22d2e25ef4dcd4 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Mon, 2 May 2016 12:58:47 -0700 Subject: [PATCH 011/113] Platform configs for x86-64 systems --- .../src/lib/x86-64-accton-as5712-54x-r0.yml | 27 ++++++++++++++++++ .../src/lib/x86-64-accton-as5812-54t-r0.yml | 25 +++++++++++++++++ .../src/lib/x86-64-accton-as5812-54x-r0.yml | 23 +++++++++++++++ .../src/lib/x86-64-accton-as6712-32x-r0.yml | 25 +++++++++++++++++ .../src/lib/x86-64-accton-as6812-32x-r0.yml | 26 +++++++++++++++++ .../src/lib/x86-64-accton-as7512-32x-r0.yml | 25 +++++++++++++++++ .../src/lib/x86-64-accton-as7712-32x-r0.yml | 25 +++++++++++++++++ .../src/lib/x86-64-accton-as7716-32x-r0.yml | 25 +++++++++++++++++ .../r0/src/lib/x86-64-accton-wedge-16x-r0.yml | 28 +++++++++++++++++++ .../r0/src/lib/x86-64-cel-redstone-xp-r0.yml | 25 +++++++++++++++++ .../r0/src/lib/x86-64-kvm-x86-64-r0.yml | 26 +++++++++++++++++ .../src/lib/x86-64-quanta-ly6-rangeley-r0.yml | 25 +++++++++++++++++ .../src/lib/x86-64-quanta-ly8-rangeley-r0.yml | 25 +++++++++++++++++ 13 files changed, 330 insertions(+) create mode 100644 packages/platforms/accton/x86-64/x86-64-accton-as5712-54x/platform-config/r0/src/lib/x86-64-accton-as5712-54x-r0.yml create mode 100644 packages/platforms/accton/x86-64/x86-64-accton-as5812-54t/platform-config/r0/src/lib/x86-64-accton-as5812-54t-r0.yml create mode 100644 packages/platforms/accton/x86-64/x86-64-accton-as5812-54x/platform-config/r0/src/lib/x86-64-accton-as5812-54x-r0.yml create mode 100644 packages/platforms/accton/x86-64/x86-64-accton-as6712-32x/platform-config/r0/src/lib/x86-64-accton-as6712-32x-r0.yml create mode 100644 packages/platforms/accton/x86-64/x86-64-accton-as6812-32x/platform-config/r0/src/lib/x86-64-accton-as6812-32x-r0.yml create mode 100644 packages/platforms/accton/x86-64/x86-64-accton-as7512-32x/platform-config/r0/src/lib/x86-64-accton-as7512-32x-r0.yml create mode 100644 packages/platforms/accton/x86-64/x86-64-accton-as7712-32x/platform-config/r0/src/lib/x86-64-accton-as7712-32x-r0.yml create mode 100644 packages/platforms/accton/x86-64/x86-64-accton-as7716-32x/platform-config/r0/src/lib/x86-64-accton-as7716-32x-r0.yml create mode 100644 packages/platforms/accton/x86-64/x86-64-accton-wedge-16x/platform-config/r0/src/lib/x86-64-accton-wedge-16x-r0.yml create mode 100644 packages/platforms/celestica/x86-64/x86-64-cel-redstone-xp/platform-config/r0/src/lib/x86-64-cel-redstone-xp-r0.yml create mode 100644 packages/platforms/kvm/x86-64/x86-64-kvm-x86-64/platform-config/r0/src/lib/x86-64-kvm-x86-64-r0.yml create mode 100644 packages/platforms/quanta/x86-64/x86-64-quanta-ly6-rangeley/platform-config/r0/src/lib/x86-64-quanta-ly6-rangeley-r0.yml create mode 100644 packages/platforms/quanta/x86-64/x86-64-quanta-ly8-rangeley/platform-config/r0/src/lib/x86-64-quanta-ly8-rangeley-r0.yml diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as5712-54x/platform-config/r0/src/lib/x86-64-accton-as5712-54x-r0.yml b/packages/platforms/accton/x86-64/x86-64-accton-as5712-54x/platform-config/r0/src/lib/x86-64-accton-as5712-54x-r0.yml new file mode 100644 index 00000000..7820c773 --- /dev/null +++ b/packages/platforms/accton/x86-64/x86-64-accton-as5712-54x/platform-config/r0/src/lib/x86-64-accton-as5712-54x-r0.yml @@ -0,0 +1,27 @@ +--- + +###################################################################### +# +# platform-config for AS5712 +# +###################################################################### + +x86-64-accton-as5712-54x-r0: + + grub: + + serial: >- + --port=0x2f8 + --speed=115200 + --word=8 + --parity=no + --stop=1 + + kernel: + <<: *kernel-3-2 + + args: >- + nopat + console=ttyS1,115200n8 + + \ No newline at end of file diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as5812-54t/platform-config/r0/src/lib/x86-64-accton-as5812-54t-r0.yml b/packages/platforms/accton/x86-64/x86-64-accton-as5812-54t/platform-config/r0/src/lib/x86-64-accton-as5812-54t-r0.yml new file mode 100644 index 00000000..35fdeeda --- /dev/null +++ b/packages/platforms/accton/x86-64/x86-64-accton-as5812-54t/platform-config/r0/src/lib/x86-64-accton-as5812-54t-r0.yml @@ -0,0 +1,25 @@ +--- + +###################################################################### +# +# platform-config for AS5812 +# +###################################################################### + +x86-64-accton-as5812-54t-r0: + + grub: + + serial: >- + --port=0x2f8 + --speed=115200 + --word=8 + --parity=no + --stop=1 + + kernel: + <<: *kernel-3-2 + + args: >- + nopat + console=ttyS1,115200n8 diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as5812-54x/platform-config/r0/src/lib/x86-64-accton-as5812-54x-r0.yml b/packages/platforms/accton/x86-64/x86-64-accton-as5812-54x/platform-config/r0/src/lib/x86-64-accton-as5812-54x-r0.yml new file mode 100644 index 00000000..b9f49b96 --- /dev/null +++ b/packages/platforms/accton/x86-64/x86-64-accton-as5812-54x/platform-config/r0/src/lib/x86-64-accton-as5812-54x-r0.yml @@ -0,0 +1,23 @@ +--- + +###################################################################### +# +# platform-config for AS5812 +# +###################################################################### + +x86-64-accton-as5812-54x-r0: + + serial: >- + --port=0x2f8 + --speed=115200 + --word=8 + --parity=no + --stop=1 + + kernel: + <<: *kernel-3-2 + + args: >- + nopat + console=ttyS1,115200n8 diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as6712-32x/platform-config/r0/src/lib/x86-64-accton-as6712-32x-r0.yml b/packages/platforms/accton/x86-64/x86-64-accton-as6712-32x/platform-config/r0/src/lib/x86-64-accton-as6712-32x-r0.yml new file mode 100644 index 00000000..e6274083 --- /dev/null +++ b/packages/platforms/accton/x86-64/x86-64-accton-as6712-32x/platform-config/r0/src/lib/x86-64-accton-as6712-32x-r0.yml @@ -0,0 +1,25 @@ +--- + +###################################################################### +# +# platform-config for AS6712 +# +###################################################################### + +x86-64-accton-as6712-32x-r0: + + grub: + + serial: >- + --port=0x2f8 + --speed=115200 + --word=8 + --parity=no + --stop=1 + + kernel: + <<: *kernel-3-2 + + args: >- + nopat + console=ttyS1,115200n8 diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as6812-32x/platform-config/r0/src/lib/x86-64-accton-as6812-32x-r0.yml b/packages/platforms/accton/x86-64/x86-64-accton-as6812-32x/platform-config/r0/src/lib/x86-64-accton-as6812-32x-r0.yml new file mode 100644 index 00000000..6a6c75d0 --- /dev/null +++ b/packages/platforms/accton/x86-64/x86-64-accton-as6812-32x/platform-config/r0/src/lib/x86-64-accton-as6812-32x-r0.yml @@ -0,0 +1,26 @@ +--- + +###################################################################### +# +# platform-config for AS6812 +# +###################################################################### + +x86-64-accton-as6812-32x-r0: + + grub: + + serial: >- + --port=0x2f8 + --speed=115200 + --word=8 + --parity=no + --stop=1 + + kernel: + <<: *kernel-3-2 + + args: >- + nopat + console=ttyS1,115200n8 + diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as7512-32x/platform-config/r0/src/lib/x86-64-accton-as7512-32x-r0.yml b/packages/platforms/accton/x86-64/x86-64-accton-as7512-32x/platform-config/r0/src/lib/x86-64-accton-as7512-32x-r0.yml new file mode 100644 index 00000000..2c83eb0d --- /dev/null +++ b/packages/platforms/accton/x86-64/x86-64-accton-as7512-32x/platform-config/r0/src/lib/x86-64-accton-as7512-32x-r0.yml @@ -0,0 +1,25 @@ +--- + +###################################################################### +# +# platform-config for AS7512 +# +###################################################################### + +x86-64-accton-as5712-32x-r0: + + grub: + + serial: >- + --port=0x2f8 + --speed=115200 + --word=8 + --parity=no + --stop=1 + + kernel: + <<: *kernel-3-2 + + args: >- + nopat + console=ttyS1,115200n8 diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as7712-32x/platform-config/r0/src/lib/x86-64-accton-as7712-32x-r0.yml b/packages/platforms/accton/x86-64/x86-64-accton-as7712-32x/platform-config/r0/src/lib/x86-64-accton-as7712-32x-r0.yml new file mode 100644 index 00000000..9630c73f --- /dev/null +++ b/packages/platforms/accton/x86-64/x86-64-accton-as7712-32x/platform-config/r0/src/lib/x86-64-accton-as7712-32x-r0.yml @@ -0,0 +1,25 @@ +--- + +###################################################################### +# +# platform-config for AS7712 +# +###################################################################### + +x86-64-accton-as7712-32x-r0: + + grub: + + serial: >- + --port=0x2f8 + --speed=115200 + --word=8 + --parity=no + --stop=1 + + kernel: + <<: *kernel-3-2 + + args: >- + nopat + console=ttyS1,115200n8 diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as7716-32x/platform-config/r0/src/lib/x86-64-accton-as7716-32x-r0.yml b/packages/platforms/accton/x86-64/x86-64-accton-as7716-32x/platform-config/r0/src/lib/x86-64-accton-as7716-32x-r0.yml new file mode 100644 index 00000000..c528084b --- /dev/null +++ b/packages/platforms/accton/x86-64/x86-64-accton-as7716-32x/platform-config/r0/src/lib/x86-64-accton-as7716-32x-r0.yml @@ -0,0 +1,25 @@ +--- + +###################################################################### +# +# platform-config for AS7716 +# +###################################################################### + +x86-64-accton-as7716-32x-r0: + + grub: + + serial: >- + --port=0x3f8 + --speed=115200 + --word=8 + --parity=no + --stop=1 + + kernel: + <<: *kernel-3-2 + + args: >- + nopat + console=ttyS0,115200n8 diff --git a/packages/platforms/accton/x86-64/x86-64-accton-wedge-16x/platform-config/r0/src/lib/x86-64-accton-wedge-16x-r0.yml b/packages/platforms/accton/x86-64/x86-64-accton-wedge-16x/platform-config/r0/src/lib/x86-64-accton-wedge-16x-r0.yml new file mode 100644 index 00000000..bc55cd86 --- /dev/null +++ b/packages/platforms/accton/x86-64/x86-64-accton-wedge-16x/platform-config/r0/src/lib/x86-64-accton-wedge-16x-r0.yml @@ -0,0 +1,28 @@ +--- + +###################################################################### +# +# platform-config for WEDGE +# +###################################################################### + +x86-64-accton-wedge-16x-r0: + + grub: + + serial: >- + --unit=0 + --speed=57600 + --word=8 + --parity=0 + --stop=1 + + kernel: + <<: *kernel-3-2 + + args: >- + nopat + console=ttyS1,57600n8 + rd_NO_MD + rd_NO_LUKS + intel_iommu=off diff --git a/packages/platforms/celestica/x86-64/x86-64-cel-redstone-xp/platform-config/r0/src/lib/x86-64-cel-redstone-xp-r0.yml b/packages/platforms/celestica/x86-64/x86-64-cel-redstone-xp/platform-config/r0/src/lib/x86-64-cel-redstone-xp-r0.yml new file mode 100644 index 00000000..69652363 --- /dev/null +++ b/packages/platforms/celestica/x86-64/x86-64-cel-redstone-xp/platform-config/r0/src/lib/x86-64-cel-redstone-xp-r0.yml @@ -0,0 +1,25 @@ +--- + +###################################################################### +# +# platform-config for REDSTONE +# +###################################################################### + +x86-64-cel-redstone-xp-r0: + + grub: + + serial: >- + --port=0x3f8 + --speed=115200 + --word=8 + --parity=no + --stop=1 + + kernel: + <<: *kernel-3-2 + + args: >- + nopat + console=ttyS0,115200n8 diff --git a/packages/platforms/kvm/x86-64/x86-64-kvm-x86-64/platform-config/r0/src/lib/x86-64-kvm-x86-64-r0.yml b/packages/platforms/kvm/x86-64/x86-64-kvm-x86-64/platform-config/r0/src/lib/x86-64-kvm-x86-64-r0.yml new file mode 100644 index 00000000..83133bce --- /dev/null +++ b/packages/platforms/kvm/x86-64/x86-64-kvm-x86-64/platform-config/r0/src/lib/x86-64-kvm-x86-64-r0.yml @@ -0,0 +1,26 @@ +--- + +###################################################################### +# +# platform-config for KVM +# +###################################################################### + +x86-64-kvm-x86-64-r0: + + grub: + + serial: >- + --port=0x3f8 + --speed=115200 + --word=8 + --parity=no + --stop=1 + + kernel: + <<: *kernel-3-9-6 + + args: >- + nopat + console=ttyS0,115200n8 + \ No newline at end of file diff --git a/packages/platforms/quanta/x86-64/x86-64-quanta-ly6-rangeley/platform-config/r0/src/lib/x86-64-quanta-ly6-rangeley-r0.yml b/packages/platforms/quanta/x86-64/x86-64-quanta-ly6-rangeley/platform-config/r0/src/lib/x86-64-quanta-ly6-rangeley-r0.yml new file mode 100644 index 00000000..cf0815d2 --- /dev/null +++ b/packages/platforms/quanta/x86-64/x86-64-quanta-ly6-rangeley/platform-config/r0/src/lib/x86-64-quanta-ly6-rangeley-r0.yml @@ -0,0 +1,25 @@ +--- + +###################################################################### +# +# platform-config for LY6 +# +###################################################################### + +x86-64-quanta-ly6-rangeley-r0: + + grub: + + serial: >- + --port=0x2f8 + --speed=115200 + --word=8 + --parity=no + --stop=1 + + kernel: + <<: *kernel-3-9-6 + + args: >- + console=ttyS1,115200n8 + \ No newline at end of file diff --git a/packages/platforms/quanta/x86-64/x86-64-quanta-ly8-rangeley/platform-config/r0/src/lib/x86-64-quanta-ly8-rangeley-r0.yml b/packages/platforms/quanta/x86-64/x86-64-quanta-ly8-rangeley/platform-config/r0/src/lib/x86-64-quanta-ly8-rangeley-r0.yml new file mode 100644 index 00000000..2fa1247a --- /dev/null +++ b/packages/platforms/quanta/x86-64/x86-64-quanta-ly8-rangeley/platform-config/r0/src/lib/x86-64-quanta-ly8-rangeley-r0.yml @@ -0,0 +1,25 @@ +--- + +###################################################################### +# +# platform-config for LY8 +# +###################################################################### + +x86-64-quanta-ly8-rangeley-r0: + + grub: + + serial: >- + --port=0x2f8 + --speed=115200 + --word=8 + --parity=no + --stop=1 + + kernel: + <<: *kernel-3-9-6 + + args: >- + console=ttyS1,115200n8 + \ No newline at end of file From 672e8d656dfd94c02229f06637b5364694ea9d16 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Mon, 2 May 2016 13:00:02 -0700 Subject: [PATCH 012/113] Handle dict values in kernel and dtb --- tools/flat-image-tree.py | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/tools/flat-image-tree.py b/tools/flat-image-tree.py index 06afa1f9..32865a6f 100755 --- a/tools/flat-image-tree.py +++ b/tools/flat-image-tree.py @@ -20,15 +20,22 @@ class Image(object): self.entry = None self.os = None - if ',' in data: - # Shorthand for tuple specifier - data = tuple([ x.strip() for x in data.split(',') ]) + if type(data) == str: + if ',' in data: + pkg, fname = [x.strip() for x in data.split(',')] + else: + pkg, fname = None, data + elif type(data) == list: + pkg, fname = data + elif type(data) == dict: + fname = data['='] + pkg = data.get('package', None) + else: + raise ValueError("invalid image specifier: %s" % repr(data)) - if(isinstance(data, tuple)): - # - # The data specifies an ONLPM (package,file) pair. - # - self.data = subprocess.check_output("onlpm --quiet --find-file %s %s" % data, shell=True).strip() + if pkg is not None: + cmd = ('onlpm', '--quiet', '--find-file', pkg, fname,) + self.data = subprocess.check_output(cmd).strip() else: self.data = data From 9fefb7955d6730af78480e070df50f91f23b6ea2 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Mon, 2 May 2016 13:00:23 -0700 Subject: [PATCH 013/113] Helper script to pull out kernel/initrd/vendor --- tools/onlplatform.py | 82 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 tools/onlplatform.py diff --git a/tools/onlplatform.py b/tools/onlplatform.py new file mode 100644 index 00000000..4348cb85 --- /dev/null +++ b/tools/onlplatform.py @@ -0,0 +1,82 @@ +#!/usr/bin/python + +"""onlplatform.py + +Extract install file requirements from the platform YAML file and/or +the platform package metadata. +""" + +import sys, os +import itertools + +toolsdir = os.path.dirname(os.path.abspath(__file__)) +sys.path.append(toolsdir) + +onldir = os.path.dirname(toolsdir) +onlpydir = os.path.join(onldir, "packages/base/all/vendor-config-onl/src/python") +sys.path.append(onlpydir) + +import onl.YamlUtils + +from onlpm import * +# glob import is required here so pickle load load properly + +pm = defaultPm() + +platform = sys.argv[1] +arch = sys.argv[2] +key = sys.argv[3] + +def extractKey(platform, arch, key): + + pkg = "onl-platform-config-%s:%s" % (platform, arch,) + basename = "%s.yml" % platform + pm.require(pkg, force=False, build_missing=False) + platformConfigPath = pm.opr.get_file(pkg, basename) + + if arch in ('amd64',): + pkg = "onl-vendor-config-onl:all" + basename = "platform-config-defaults-x86-64.yml" + subkey = 'grub' + else: + pkg = "onl-vendor-config-onl:all" + basename = "platform-config-defaults-uboot.yml" + subkey = 'flat_image_tree' + pm.require(pkg, force=False, build_missing=False) + defaultConfigPath = pm.opr.get_file(pkg, basename) + + platformConf = onl.YamlUtils.merge(defaultConfigPath, platformConfigPath) + resource = platformConf[platform][subkey][key] + if type(resource) == dict: + pkg = resource['package'] + basename = resource['='] + else: + pkg, sep, basename = resource.partition(',') + if not sep: + raise ValueError("resource missing package declaration: %s" % resource) + pkg = pkg.strip() + basename = basename.strip() + pm.require(pkg, force=False, build_missing=False) + resourcePath = pm.opr.get_file(pkg, basename) + return resourcePath + +def extractVendor(platform, arch): + pkg = "onl-platform-config-%s:%s" % (platform, arch,) + l = pm.opr.lookup_all(pkg) + if not l: + raise SystemExit("cannot find package %s:%s" + % (platform, arch,)) + l = [x for x in pm.package_groups if pkg in x] + l = list(itertools.chain(*[x.prerequisite_packages() for x in l])) + l = [x for x in l if x.startswith('onl-vendor-config-')] + return "\n".join(l) + +if key in ('kernel', 'initrd',): + print extractKey(platform, arch, key) + sys.exit(0) + +if key == 'vendor': + print extractVendor(platform, arch) + sys.exit(0) + +raise SystemExit("invalid key %s" % key) From 7c2bb91b7ccc71f91f17b9cd7c10213e027339fd Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Mon, 2 May 2016 13:00:55 -0700 Subject: [PATCH 014/113] Clean up onlpm and make it embeddable --- tools/onlpm.py | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/tools/onlpm.py b/tools/onlpm.py index 62aff9c8..d00e74d3 100755 --- a/tools/onlpm.py +++ b/tools/onlpm.py @@ -765,8 +765,8 @@ class OnlPackageManager(object): self.package_groups = [] self.opr = None - def set_repo(self, repodir): - self.opr = OnlPackageRepo(repodir, ops.repo_package_dir) + def set_repo(self, repodir, packagedir='packages'): + self.opr = OnlPackageRepo(repodir, packagedir=packagedir) def filter(self, subdir=None, arches=None, substr=None): @@ -999,6 +999,32 @@ class OnlPackageManager(object): def pkg_info(self): return "\n".join([ pg.pkg_info() for pg in self.package_groups if not pg.filtered ]) +def defaultPm(): + repo = os.environ.get('ONLPM_OPTION_REPO', None) + envJson = os.environ.get('ONLPM_OPTION_INCLUDE_ENV_JSON', None) + packagedirs = os.environ['ONLPM_OPTION_PACKAGEDIRS'].split(':') + repoPackageDir = os.environ.get('ONLPM_OPTION_REPO_PACKAGE_DIR', 'packages') + subdir = os.getcwd() + arches = ['amd64', 'powerpc', 'armel', 'all',] + + if envJson: + for j in envJson.split(':'): + data = json.load(open(j)) + for (k, v) in data.iteritems(): + try: + v = v.encode('ascii') + except UnicodeEncodeError: + pass + os.environ[k] = v + + pm = OnlPackageManager() + pm.set_repo(repo, packagedir=repoPackageDir) + for pdir in packagedirs: + pm.load(pdir, usecache=True, rebuildcache=False) + pm.filter(subdir = subdir, arches=arches) + + return pm + if __name__ == '__main__': ap = argparse.ArgumentParser("onlpm") @@ -1090,7 +1116,7 @@ if __name__ == '__main__': pm = OnlPackageManager() if ops.repo: logger.debug("Setting repo as '%s'..." % ops.repo) - pm.set_repo(ops.repo) + pm.set_repo(ops.repo, packagedir=ops.repo_package_dir) if ops.in_repo: for p in ops.in_repo: From 5f12eb0f1e57507eddf638fc6174322cb914ccc1 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Mon, 2 May 2016 13:07:28 -0700 Subject: [PATCH 015/113] New installer common files --- builds/any/installer/new-hotness/APKG.yml | 35 ++ .../any/installer/new-hotness/installer.sh.in | 308 ++++++++++++++++++ 2 files changed, 343 insertions(+) create mode 100644 builds/any/installer/new-hotness/APKG.yml create mode 100644 builds/any/installer/new-hotness/installer.sh.in diff --git a/builds/any/installer/new-hotness/APKG.yml b/builds/any/installer/new-hotness/APKG.yml new file mode 100644 index 00000000..62ad5191 --- /dev/null +++ b/builds/any/installer/new-hotness/APKG.yml @@ -0,0 +1,35 @@ + +prerequisites: + broken: true + packages: [ "onl-swi:$ARCH" ] + +common: + arch: $ARCH + version: $FNAME_RELEASE_ID + copyright: Copyright 2016 Big Switch Networks + maintainer: support@bigswitch.com + +packages: + - name: onl-installer + summary: Open Network Linux $ARCH Installer + + files: + builds/*INSTALLER : $$PKG_INSTALL/ + builds/*.md5sum : $$PKG_INSTALL/ + + changelog: Change changes changes., + + +release: + - builds/*INSTALLER : $ARCH/ + - builds/*.md5sum : $ARCH/ + + + + + + + + + + diff --git a/builds/any/installer/new-hotness/installer.sh.in b/builds/any/installer/new-hotness/installer.sh.in new file mode 100644 index 00000000..1f5a70ad --- /dev/null +++ b/builds/any/installer/new-hotness/installer.sh.in @@ -0,0 +1,308 @@ +#!/bin/sh +############################################################ +# +# +# Copyright 2013, 2014 BigSwitch Networks, Inc. +# +# +# +# +############################################################ +# +# SwitchLight Installation Script for PPC. +# +# The purpose of this script is to automatically install SwitchLight +# on the target system. +# +# This script is ONIE-compatible. +# +# This script is can be run under a manual boot of the SwitchLight +# Loader as the execution environment for platforms that do not +# support ONIE. +# +############################################################ + +IARCH="@ARCH@" +ARCH=`uname -m` +if test "$ARCH" != "$IARCH"; then + echo + echo "------------------------------------" + echo "Installer Architecture: $IARCH" + echo "Target Architecture: $ARCH" + echo + echo "This installer cannot be used on this" + echo "target." + echo + echo "------------------------------------" + sleep 5 + exit 1 +fi +case "$ARCH" in + ppc|powerpc) + ARCH_PPC=$ARCH + ;; + x86*|amd*|i?86*) + ARCH_X86=$ARCH + ;; + *) + echo "Invalid Architecture: $ARCH" + sleep 5 + exit 1 + ;; +esac + +############################################################ +# +# Installation Main +# +# Installation is performed as follows: +# +# 1. Detect whether we are running under ONIE or SwitchLight +# and perform the appropriate setup. +# +# 2. Unpack the installer files. +# +# 3. Source the installer scriptlet for the current platform. +# 4. Run the installer function from the platform scriptlet. +# +# The platform scriptlet determines the entire installation +# sequence. +# +# Most platforms will just call the installation +# utilities in this script with the approprate platform settings. +# +############################################################ + +set -e +cd $(dirname $0) + +installer_script=${0##*/} +installer_zip=$1 + +BOOTDIR=/mnt/onie-boot +# initial boot partition (onie) + +has_grub_env() +{ + local tag + tag=$1; shift + test -f $BOOTDIR/grub/grubenv || return 1 + case "`grub-editenv $BOOTDIR/grubenv list` 2>/dev/null" in + *${tag}*) return 0 ;; + esac + return 1 +} + +has_uboot_env() +{ + local tag + tag=$1; shift + test -x /usr/sbin/fw_printenv || return 1 + test -f /etc/fw_env.config || return 1 + /usr/sbin/fw_printenv $tag 1>/dev/null 2>&1 && return 0 + return 1 +} + +has_boot_env() +{ + local tag + tag=$1; shift + has_grub_env $tag && return 0 + has_uboot_env $tag && return 0 + return 1 +} + +# Check installer debug option from the boot environment +if has_boot_env onl_installer_debug; then installer_debug=1; fi + +if test "$installer_debug"; then + echo "Debug mode" + set -x +fi + +# Pickup ONIE defines for this machine. +if test -r /etc/machine.conf; then + . /etc/machine.conf +fi + +# +# Installation environment setup. +# + +installer_umount() { + egrep "/tmp/..*" /proc/mounts | cut -d' ' -f2 | sort -r | xargs -n 1 umount +} + +if test "${onie_platform}"; then + # Running under ONIE, most likely in the background in installer mode. + # Our messages have to be sent to the console directly, not to stdout. + installer_say() + { + echo "$@" > /dev/console + } + + # Installation failure message. + installer_cleanup() + { + installer_say "Install failed." + cat /var/log/onie.log > /dev/console + installer_say "Install failed. See log messages above for details" + + installer_umount + + if installer_reboot; then + : + else + sync + sleep 3 + reboot + fi + } +else + if test "$ARCH_X86"; then + echo "Missing onie_platform (invalid /etc/machine.conf)" 1>&2 + exit 1 + fi + # + # Assume we are running in an interactive environment + # + installer_say() + { + echo + echo "* $@" + echo + } + + installer_cleanup() + { + installer_say "Install failed." + installer_umount + exit 1 + } +fi + +trap "installer_cleanup" 0 1 + +# +# Remount tmpfs larger if possible. +# We will be doing all of our work out of /tmp +# +mount -o remount,size=1024M /tmp || true + +# Unpack our distribution +installer_say "Unpacking SwitchLight installer files..." +installer_dir=`pwd` +if test "$SFX_PAD"; then + # ha ha, busybox cannot exclude multiple files + unzip $installer_zip -x $SFX_PAD +elif test "$SFX_UNZIP"; then + unzip $installer_zip -x $installer_script +else + dd if=$installer_zip bs=$SFX_BLOCKSIZE skip=$SFX_BLOCKS \ + | unzip - -x $installer_script +fi + +# Developer debugging +if has_boot_env onl_installer_unpack_only; then installer_unpack_only=1; fi +if test "${installer_unpack_only}"; then + installer_say "Unpack only requested." + exit 1 +fi + +# Replaced during build packaging with the current version. +onl_version="@ONLVERSION@" +initrd_archive="@INITRD_ARCHIVE@" +initrd_offset="@INITRD_OFFSET@" +initrd_size="@INITRD_SIZE@" + +TMPDIR=${TMPDIR-"${installer_dir}"} +export TMPDIR + +rootdir=$(mktemp -d -t "initrd-XXXXXX") +installer_say "Extracting initrd to $rootdir" +if test "$initrd_offset"; then + tmprd=$(mktemp -t initrd-XXXXXX) + dd if="$initrd_archive" of="$tmprd" bs="$initrd_offset" skip=1 + dd if=/dev/null of="$tmprd" bs="$initrd_size" seek=1 + initrd=$tmprd +else + initrd="${installer_dir}/$initrd_archive" +fi +gzip -dc "$initrd" | ( cd "$rootdir" && cpio -imd ) + +# get common installer functions +. "${rootdir}/lib/vendor-config/onl/install/lib.sh" + +installer_mkchroot "${rootdir}" + +# make the installer available to the chroot +mkdir -p "${rootdir}/mnt/installer" +mount -o ro,bind "${installer_dir}" "${rootdir}/mnt/installer" + +# make the onie boot files available to the chroot +mkdir -p "${rootdir}/mnt/onie-boot" +if test -d "/mnt/onie-boot"; then + mount -o ro,bind "/mnt/onie-boot" "${rootdir}/mnt/onie-boot" +fi + +# generate config for installer environment +mkdir -p "${rootdir}/etc/onl" +cp /dev/null "${rootdir}/etc/onl/installer.conf" +echo "onl_version=\"$onl_version\"" >> "${rootdir}/etc/onl/installer.conf" + +# Generate the MD5 signature for ourselves for future reference. +installer_md5=$(md5sum "$0" | awk '{print $1}') +echo "installer_md5=\"$installer_md5\"" >> "${rootdir}/etc/onl/installer.conf" + +# Cache our install URL if available +if test -f "$0.url"; then + installer_url=$(cat "$0.url") + echo "installer_url=\"$installer_url\"" >> "${rootdir}/etc/onl/installer.conf" +fi + +echo "installer_dir=/mnt/installer" >> "${rootdir}/etc/onl/installer.conf" + +# include access details for the initrd +if test "$initrd_offset"; then + echo "initrd_archive=\"$initrd_archive\"" >> "${rootdir}/etc/onl/installer.conf" + echo "initrd_offset=\"$initrd_offset\"" >> "${rootdir}/etc/onl/installer.conf" + echo "initrd_size=\"$initrd_size\"" >> "${rootdir}/etc/onl/installer.conf" +fi + +postinst=$(mktemp -t postinst-XXXXXX) +b=${postinst##*/} +echo "installer_chroot=${rootdir}" >> "${rootdir}/etc/onl/installer.conf" +echo "installer_postinst=/mnt/installer/$b" >> "${rootdir}/etc/onl/installer.conf" + +# for now, skip the other dot-files in /etc/onl, we do not need them +# to enable initial install + +# no special handling for /tmp or /run, since this is all in /tmp +# anyway + +installer_say "Launching Switch Light installer" +installer_shell=${installer_shell-"/usr/bin/onl-install"} +chroot "${rootdir}" $installer_shell +: chroot "${rootdir}" /usr/bin/onl-install + +if test -f "$postinst"; then + installer_say "Invoking post-install actions" + set -x + . "$postinst" + set +x +fi + +trap - 0 1 +installer_umount + +if test "${onie_platform}"; then + installer_reboot +fi + +exit + +# Local variables: +# mode: sh +# sh-basic-offset: 2 +# End: +# Do not add any additional whitespace after this point. From 760c3c779206ae6d29118f0f4da46268d3958e70 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Mon, 2 May 2016 13:30:29 -0700 Subject: [PATCH 016/113] x64 build of the new installer --- builds/amd64/installer/new-hotness/Makefile | 1 + builds/amd64/installer/new-hotness/PKG.yml | 2 + .../installer/new-hotness/builds/.gitignore | 1 + .../installer/new-hotness/builds/Makefile | 82 +++++++++++++++++++ .../installer/new-hotness/builds/boot-config | 4 + 5 files changed, 90 insertions(+) create mode 100644 builds/amd64/installer/new-hotness/Makefile create mode 100644 builds/amd64/installer/new-hotness/PKG.yml create mode 100644 builds/amd64/installer/new-hotness/builds/.gitignore create mode 100644 builds/amd64/installer/new-hotness/builds/Makefile create mode 100644 builds/amd64/installer/new-hotness/builds/boot-config diff --git a/builds/amd64/installer/new-hotness/Makefile b/builds/amd64/installer/new-hotness/Makefile new file mode 100644 index 00000000..003238cf --- /dev/null +++ b/builds/amd64/installer/new-hotness/Makefile @@ -0,0 +1 @@ +include $(ONL)/make/pkg.mk \ No newline at end of file diff --git a/builds/amd64/installer/new-hotness/PKG.yml b/builds/amd64/installer/new-hotness/PKG.yml new file mode 100644 index 00000000..55693e33 --- /dev/null +++ b/builds/amd64/installer/new-hotness/PKG.yml @@ -0,0 +1,2 @@ +!include $ONL/builds/any/installer/new-hotness/APKG.yml ARCH=amd64 + diff --git a/builds/amd64/installer/new-hotness/builds/.gitignore b/builds/amd64/installer/new-hotness/builds/.gitignore new file mode 100644 index 00000000..fbd18542 --- /dev/null +++ b/builds/amd64/installer/new-hotness/builds/.gitignore @@ -0,0 +1 @@ +*INSTALLER diff --git a/builds/amd64/installer/new-hotness/builds/Makefile b/builds/amd64/installer/new-hotness/builds/Makefile new file mode 100644 index 00000000..3ec17a99 --- /dev/null +++ b/builds/amd64/installer/new-hotness/builds/Makefile @@ -0,0 +1,82 @@ +include $(ONL)/make/config.amd64.mk + +ONLPLATFORM = python $(ONL)/tools/onlplatform.py +PLATFORMS := $(shell $(ONLPM) --platform-manifest onl-loader-initrd:amd64) + +MKSHAR = $(ONL)/tools/mkshar +MKSHAR_OPTS = --lazy --unzip-pad --fixup-perms autoperms.sh +MKSHAR_PERMS = autoperms.sh + +# Hardcoded to match ONL File naming conventions. +include $(ONL)/make/version-onl.mk +INSTALLER_NAME=$(FNAME_PRODUCT_VERSION)_ONL-OS_$(FNAME_BUILD_ID)_$(UARCH)_INSTALLER + + +__installer: __installer_platform_files __installer_swi_files + $(ONL_V_at)rm -rf *INSTALLER* *.md5sum + $(ONL_V_at)cp /dev/null installer.sh + $(ONL_V_at): ;\ + set -e ;\ + if $(ONL_V_P); then set -x; fi ;\ + set dummy *.cpio.gz; initrd="$$2" ;\ + sed \ + -e 's^@ONLVERSION@^$(VERSION_STRING)^g' \ + -e "s^@INITRD_ARCHIVE@^$$initrd^g" \ + -e 's^@INITRD_OFFSET@^^g' \ + -e 's^@INITRD_SIZE@^^g' \ + -e 's^@ARCH@^x86_64^g' \ + $(ONL)/builds/any/installer/new-hotness/installer.sh.in \ + >> installer.sh + $(ONL_V_at)echo "PAYLOAD_FOLLOWS" >> installer.sh + $(ONL_V_at)cp /dev/null $(MKSHAR_PERMS) + $(ONL_V_at)cp $(ONL)/make/version-onl.sh . + $(ONL_V_at)echo "#!/bin/sh" >> $(MKSHAR_PERMS) + $(ONL_V_at)echo "set -e" >> $(MKSHAR_PERMS) + $(ONL_V_at)echo "set -x" >> $(MKSHAR_PERMS) + $(MKSHAR) $(MKSHAR_OPTS) "$(INSTALLER_NAME)" $(ONL)/tools/scripts/sfx.sh.in installer.sh kernel-* onl-loader-initrd-* *.swi version-onl.sh boot-config + $(ONL_V_at)rm -rf installer.sh kernel-* onl-loader-initrd-* $(ZTN_MANIFEST) *.swi version-onl.sh autoperms.sh + md5sum "$(INSTALLER_NAME)" | awk '{ print $$1 }' > "$(INSTALLER_NAME).md5sum" + +__installer_platform_files: + $(ONL_V_GEN): ;\ + set -e ;\ + if $(ONL_V_P); then set -x; fi ;\ + l="$(PLATFORMS)"; for p in $$l; do \ + src=$$($(ONLPLATFORM) $$p amd64 kernel 2>/dev/null) || : ;\ + if test "$$src"; then \ + dst=$${src##*/} ;\ + if test "$dst" -ot Makefile; then \ + : ;\ + else \ + echo "Staging $$dst for $$p" ;\ + cp "$$src" "$$dst" ;\ + fi ;\ + fi ;\ + src=$$($(ONLPLATFORM) $$p amd64 initrd 2>/dev/null) || : ;\ + if test "$$src"; then \ + dst=$${src##*/} ;\ + if test "$dst" -ot Makefile; then \ + : ;\ + else \ + echo "Staging $$dst for $$p" ;\ + cp "$$src" "$$dst" ;\ + fi ;\ + fi ;\ + done ;\ + : + +__installer_swi_files: + $(ONL_V_GEN): ;\ + set -e ;\ + if $(ONL_V_P); then set -x; fi ;\ + swidir=$$(mktemp -d $(PWD)/swi-d-XXXXXX) ;\ + $(ONLPM) --extract-dir onl-swi:amd64 $$swidir ;\ + mv $$swidir/usr/share/onl/packages/amd64/onl-swi/*.swi . ;\ + rm -fr $$swidir ;\ + : + +shar installer: installer + +clean: + rm -f *.swi *.installer $(notdir $(KERNELS)) *initrd*.cpio.gz + diff --git a/builds/amd64/installer/new-hotness/builds/boot-config b/builds/amd64/installer/new-hotness/builds/boot-config new file mode 100644 index 00000000..40fb0d31 --- /dev/null +++ b/builds/amd64/installer/new-hotness/builds/boot-config @@ -0,0 +1,4 @@ +NETDEV=ma1 +NETAUTO=dhcp +BOOTMODE=SWI +SWI=images::latest From 8c138c6e4d0ad9a8599fb9d7d0094cc68f162520 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Mon, 2 May 2016 14:00:13 -0700 Subject: [PATCH 017/113] Update ignore rules --- .gitignore | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.gitignore b/.gitignore index 108062fa..7ccdfdf1 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ dependmodules.x *.cpio.gz *.sqsh *.pyc +*.pyo # Package cache and lock files .lock @@ -18,3 +19,7 @@ RELEASE/ .bash_history .buildroot-ccache + +# temporary files +*~ +.#* From 08a3f3b5fc18482e90f4ef2906be86a6e7f55e60 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Fri, 6 May 2016 11:02:51 -0700 Subject: [PATCH 018/113] Added arm support --- builds/any/installer/new-hotness/installer.sh.in | 3 +++ 1 file changed, 3 insertions(+) diff --git a/builds/any/installer/new-hotness/installer.sh.in b/builds/any/installer/new-hotness/installer.sh.in index 1f5a70ad..6cc81460 100644 --- a/builds/any/installer/new-hotness/installer.sh.in +++ b/builds/any/installer/new-hotness/installer.sh.in @@ -44,6 +44,9 @@ case "$ARCH" in x86*|amd*|i?86*) ARCH_X86=$ARCH ;; + arm*) + ARCH_ARM=$ARCH + ;; *) echo "Invalid Architecture: $ARCH" sleep 5 From a6c36afee2d24adf711c3c020df92ae32b869f4e Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Fri, 6 May 2016 11:04:54 -0700 Subject: [PATCH 019/113] Relax arch rules for powerpc and arm installer --- .../amd64/installer/new-hotness/builds/Makefile | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/builds/amd64/installer/new-hotness/builds/Makefile b/builds/amd64/installer/new-hotness/builds/Makefile index 3ec17a99..c3e85267 100644 --- a/builds/amd64/installer/new-hotness/builds/Makefile +++ b/builds/amd64/installer/new-hotness/builds/Makefile @@ -1,7 +1,7 @@ include $(ONL)/make/config.amd64.mk ONLPLATFORM = python $(ONL)/tools/onlplatform.py -PLATFORMS := $(shell $(ONLPM) --platform-manifest onl-loader-initrd:amd64) +PLATFORMS := $(shell $(ONLPM) --platform-manifest onl-loader-initrd:$(ARCH)) MKSHAR = $(ONL)/tools/mkshar MKSHAR_OPTS = --lazy --unzip-pad --fixup-perms autoperms.sh @@ -42,7 +42,7 @@ __installer_platform_files: set -e ;\ if $(ONL_V_P); then set -x; fi ;\ l="$(PLATFORMS)"; for p in $$l; do \ - src=$$($(ONLPLATFORM) $$p amd64 kernel 2>/dev/null) || : ;\ + src=$$($(ONLPLATFORM) $$p $(ARCH) kernel 2>/dev/null) || : ;\ if test "$$src"; then \ dst=$${src##*/} ;\ if test "$dst" -ot Makefile; then \ @@ -52,7 +52,7 @@ __installer_platform_files: cp "$$src" "$$dst" ;\ fi ;\ fi ;\ - src=$$($(ONLPLATFORM) $$p amd64 initrd 2>/dev/null) || : ;\ + src=$$($(ONLPLATFORM) $$p $(ARCH) initrd 2>/dev/null) || : ;\ if test "$$src"; then \ dst=$${src##*/} ;\ if test "$dst" -ot Makefile; then \ @@ -65,15 +65,20 @@ __installer_platform_files: done ;\ : +ifndef NO_SWI __installer_swi_files: $(ONL_V_GEN): ;\ set -e ;\ if $(ONL_V_P); then set -x; fi ;\ swidir=$$(mktemp -d $(PWD)/swi-d-XXXXXX) ;\ - $(ONLPM) --extract-dir onl-swi:amd64 $$swidir ;\ - mv $$swidir/usr/share/onl/packages/amd64/onl-swi/*.swi . ;\ + $(ONLPM) --extract-dir onl-swi:$(ARCH) $$swidir ;\ + mv $$swidir/usr/share/onl/packages/$(ARCH)/onl-swi/*.swi . ;\ rm -fr $$swidir ;\ : +else +__installer_swi_files: + $(ONL_V_GEN): +endif shar installer: installer From 9127a94cf53713e8d730c475fb20fe21c0b405bf Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Fri, 6 May 2016 11:05:37 -0700 Subject: [PATCH 020/113] Add python compatibility path for debian-derived installs --- packages/base/all/initrds/loader-initrd-files/PKG.yml | 3 ++- .../all/initrds/loader-initrd-files/src/python/debcompat.pth | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 packages/base/all/initrds/loader-initrd-files/src/python/debcompat.pth diff --git a/packages/base/all/initrds/loader-initrd-files/PKG.yml b/packages/base/all/initrds/loader-initrd-files/PKG.yml index 2fc41557..3ae21ef7 100644 --- a/packages/base/all/initrds/loader-initrd-files/PKG.yml +++ b/packages/base/all/initrds/loader-initrd-files/PKG.yml @@ -14,10 +14,11 @@ packages: - src/etc : /etc - src/lib : /lib - src/bootmodes : /bootmodes + - src/python: /usr/lib/python2.7/site-packages - $ONL/make/version-onl.sh : /etc/onl/loader/versions.sh - $ONL/make/version-onl.json : /etc/onl/loader/versions.json - $ONL/make/version-onl.mk : /etc/onl/loader/versions.mk - + changelog: Change changes changes., diff --git a/packages/base/all/initrds/loader-initrd-files/src/python/debcompat.pth b/packages/base/all/initrds/loader-initrd-files/src/python/debcompat.pth new file mode 100644 index 00000000..5c1cb274 --- /dev/null +++ b/packages/base/all/initrds/loader-initrd-files/src/python/debcompat.pth @@ -0,0 +1 @@ +/usr/lib/python2.7/dist-packages From 161b8e48d893db3d6b911cab03fd936b60f121e8 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Fri, 6 May 2016 11:07:10 -0700 Subject: [PATCH 021/113] Revert dumb python path hack --- packages/base/all/vendor-config-onl/src/bin/loader-shell | 4 ---- packages/base/all/vendor-config-onl/src/bin/onie-shell | 4 ---- packages/base/all/vendor-config-onl/src/bin/onl-install | 4 ---- packages/base/all/vendor-config-onl/src/bin/onl-recover | 4 ---- packages/base/all/vendor-config-onl/src/bin/pyfit | 4 ---- 5 files changed, 20 deletions(-) diff --git a/packages/base/all/vendor-config-onl/src/bin/loader-shell b/packages/base/all/vendor-config-onl/src/bin/loader-shell index 0ee08028..e006aef4 100755 --- a/packages/base/all/vendor-config-onl/src/bin/loader-shell +++ b/packages/base/all/vendor-config-onl/src/bin/loader-shell @@ -3,9 +3,5 @@ """Run native ONIE tools """ -import sys -import distutils.sysconfig -sys.path.append("/usr/lib/python%s/dist-packages" - % distutils.sysconfig.get_python_version()) import onl.install.ShellApp onl.install.ShellApp.Loader.main() diff --git a/packages/base/all/vendor-config-onl/src/bin/onie-shell b/packages/base/all/vendor-config-onl/src/bin/onie-shell index ecf8b7a3..8ff8343e 100755 --- a/packages/base/all/vendor-config-onl/src/bin/onie-shell +++ b/packages/base/all/vendor-config-onl/src/bin/onie-shell @@ -3,9 +3,5 @@ """Run native ONIE tools """ -import sys -import distutils.sysconfig -sys.path.append("/usr/lib/python%s/dist-packages" - % distutils.sysconfig.get_python_version()) import onl.install.ShellApp onl.install.ShellApp.Onie.main() diff --git a/packages/base/all/vendor-config-onl/src/bin/onl-install b/packages/base/all/vendor-config-onl/src/bin/onl-install index 6d961e6e..4505eee5 100755 --- a/packages/base/all/vendor-config-onl/src/bin/onl-install +++ b/packages/base/all/vendor-config-onl/src/bin/onl-install @@ -3,9 +3,5 @@ """Install switch light """ -import sys -import distutils.sysconfig -sys.path.append("/usr/lib/python%s/dist-packages" - % distutils.sysconfig.get_python_version()) import onl.install.App onl.install.App.main() diff --git a/packages/base/all/vendor-config-onl/src/bin/onl-recover b/packages/base/all/vendor-config-onl/src/bin/onl-recover index f7b6f0c0..6a9a8589 100755 --- a/packages/base/all/vendor-config-onl/src/bin/onl-recover +++ b/packages/base/all/vendor-config-onl/src/bin/onl-recover @@ -3,9 +3,5 @@ """Recover switch light """ -import sys -import distutils.sysconfig -sys.path.append("/usr/lib/python%s/dist-packages" - % distutils.sysconfig.get_python_version()) import onl.install.RecoverApp onl.install.RecoverApp.main() diff --git a/packages/base/all/vendor-config-onl/src/bin/pyfit b/packages/base/all/vendor-config-onl/src/bin/pyfit index ea644d72..4ee57728 100755 --- a/packages/base/all/vendor-config-onl/src/bin/pyfit +++ b/packages/base/all/vendor-config-onl/src/bin/pyfit @@ -3,9 +3,5 @@ """Swiss-army-knife FIT decoder """ -import sys -import distutils.sysconfig -sys.path.append("/usr/lib/python%s/dist-packages" - % distutils.sysconfig.get_python_version()) import onl.install.Fit onl.install.Fit.App.main() From 71e0cc65c2e07095ffe7c82da8433cb2b8e7761d Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Fri, 6 May 2016 11:07:54 -0700 Subject: [PATCH 022/113] Added list_platforms api call --- tools/onlpm.py | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/tools/onlpm.py b/tools/onlpm.py index d00e74d3..62ef67bc 100755 --- a/tools/onlpm.py +++ b/tools/onlpm.py @@ -561,7 +561,6 @@ class OnlPackageGroup(object): with onlu.Lock(os.path.join(self._pkgs['__directory'], '.lock')): self.gmake_locked("clean", 'Clean') - class OnlPackageRepo(object): """Package Repository and Interchange Class @@ -999,6 +998,17 @@ class OnlPackageManager(object): def pkg_info(self): return "\n".join([ pg.pkg_info() for pg in self.package_groups if not pg.filtered ]) + def list_platforms(self, arch): + platforms = [] + for pg in self.package_groups: + for p in pg.packages: + (name, pkgArch) = OnlPackage.idparse(p.id()) + m = re.match(r'onl-platform-config-(?P.*)', name) + if m: + if arch in [ pkgArch, "all", None ]: + platforms.append(m.groups('platform')[0]) + return platforms + def defaultPm(): repo = os.environ.get('ONLPM_OPTION_REPO', None) envJson = os.environ.get('ONLPM_OPTION_INCLUDE_ENV_JSON', None) @@ -1139,15 +1149,10 @@ if __name__ == '__main__': print if ops.list_platforms: - platforms = [] - for pg in pm.package_groups: - for p in pg.packages: - (name, arch) = OnlPackage.idparse(p.id()) - m = re.match(r'onl-platform-config-(?P.*)', name) - if m: - if ops.arch in [ arch, "all", None ]: - platforms.append(m.groups('platform')[0]) - + if not ops.arch: + logger.error("missing --arch with --list-platforms") + sys.exit(1) + platforms = pm.list_platforms(ops.arch) if ops.csv: print ','.join(platforms) else: From c5a8d943b292113357f3dca8427bacc7014faf3c Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Fri, 6 May 2016 11:08:06 -0700 Subject: [PATCH 023/113] Support dtb and itb extraction --- tools/onlplatform.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/onlplatform.py b/tools/onlplatform.py index 4348cb85..633bc722 100644 --- a/tools/onlplatform.py +++ b/tools/onlplatform.py @@ -71,7 +71,7 @@ def extractVendor(platform, arch): l = [x for x in l if x.startswith('onl-vendor-config-')] return "\n".join(l) -if key in ('kernel', 'initrd',): +if key in ('kernel', 'initrd', 'dtb', 'itb',): print extractKey(platform, arch, key) sys.exit(0) From 0c7b466bcd4591da38ba588aa7c608d3a695238d Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Fri, 6 May 2016 11:08:29 -0700 Subject: [PATCH 024/113] Refactor to use onlpm as a module --- tools/flat-image-tree.py | 95 ++++++++++++++++++++++++++-------------- 1 file changed, 63 insertions(+), 32 deletions(-) diff --git a/tools/flat-image-tree.py b/tools/flat-image-tree.py index 32865a6f..fe95dab8 100755 --- a/tools/flat-image-tree.py +++ b/tools/flat-image-tree.py @@ -7,7 +7,16 @@ import subprocess import yaml import tempfile -import json + +import os, sys +toolsdir = os.path.dirname(os.path.abspath(__file__)) +onldir = os.path.dirname(toolsdir) +pydir = os.path.join(onldir, "packages/base/all/vendor-config-onl/src/python") +sys.path.append(pydir) +import onl.YamlUtils + +from onlpm import * +pm = defaultPm() class Image(object): """Base ITS Image Class""" @@ -34,12 +43,17 @@ class Image(object): raise ValueError("invalid image specifier: %s" % repr(data)) if pkg is not None: - cmd = ('onlpm', '--quiet', '--find-file', pkg, fname,) - self.data = subprocess.check_output(cmd).strip() + pm.require(pkg, force=False, build_missing=False) + self.data = pm.opr.get_file(pkg, fname) else: self.data = data - self.name = os.path.basename(self.data) + try: + self.name = os.path.basename(fname) + except: + import pdb + pdb.set_trace() + raise self.description = self.name @@ -73,8 +87,8 @@ class Image(object): class KernelImage(Image): """Kernel image entry""" - def __init__(self, fname, arch): - Image.__init__(self, "kernel", fname, compression='gzip') + def __init__(self, fdata, arch): + Image.__init__(self, "kernel", fdata, compression='gzip') self.os = '"linux"' # Fixme -- thse should be parameterized @@ -94,8 +108,8 @@ class KernelImage(Image): class InitrdImage(Image): """Initrd image entry""" - def __init__(self, fname, arch): - Image.__init__(self, "ramdisk", fname, compression='gzip') + def __init__(self, fdata, arch): + Image.__init__(self, "ramdisk", fdata, compression='gzip') # Fixme -- thse should be parameterized if arch == 'powerpc': @@ -115,8 +129,8 @@ class InitrdImage(Image): class DtbImage(Image): """DTB Image Entry""" - def __init__(self, fname): - Image.__init__(self, "flat_dt", fname, compression="none") + def __init__(self, fdata): + Image.__init__(self, "flat_dt", fdata, compression="none") def write(self, f): self.start_image(f) @@ -176,18 +190,31 @@ class FlatImageTree(object): initrd = d.get('initrd', None) + sys.stderr.write("*** platform %s kernel %s\n" + % (name, kernel,)) self.add_config(name, kernel, dtb, initrd) - def add_yaml(self, name, fname): - d = yaml.load(open(fname)) + def add_yaml(self, name, fname, defaults=None): + if defaults is not None: + d = onl.YamlUtils.merge(defaults, fname) + else: + with open(fname) as fd: + d = yaml.load(fd) self.add_dict(name, d) def add_platform_package(self, package): print package platform = package.replace(":%s" % ops.arch, "").replace("onl-platform-config-", "") - y = subprocess.check_output("onlpm --quiet --find-file %s %s.yml" % (package, platform), shell=True).strip() - self.add_yaml(platform, y) + + vpkg = "onl-vendor-config-onl:all" + pm.require(vpkg, force=False, build_missing=False) + y1 = pm.opr.get_file(vpkg, "platform-config-defaults-uboot.yml") + + pm.require(package, force=False, build_missing=False) + y2 = pm.opr.get_file(package, platform + '.yml') + + self.add_yaml(platform, y2, defaults=y1) def add_platform(self, platform): if (":%s" % ops.arch) in platform: @@ -202,17 +229,19 @@ class FlatImageTree(object): def writef(self, f): kdict = {} - for k in set(self.kernels): - kdict[k] = KernelImage(k, ops.arch) + for k in self.kernels: + ki = KernelImage(k, ops.arch) + kdict[ki.name] = ki ddict = {} - for d in set(self.dtbs): - ddict[d] = DtbImage(d) + for d in self.dtbs: + di = DtbImage(d) + ddict[di.name] = di idict = {} - for i in set(self.initrds): - idict[i] = InitrdImage(i, ops.arch) - + for i in self.initrds: + ii = InitrdImage(i, ops.arch) + idict[ii.name] = ii f.write("""/* \n""") @@ -227,27 +256,27 @@ class FlatImageTree(object): f.write(""" images {\n\n""") f.write(""" /* Kernel Images */\n""") - for k in set(self.kernels): - KernelImage(k, ops.arch).write(f) + for k in kdict.values(): + k.write(f) f.write("""\n""") f.write(""" /* DTB Images */\n""") - for d in set(self.dtbs): - DtbImage(d).write(f) + for d in ddict.values(): + d.write(f) f.write("""\n""") f.write(""" /* Initrd Images */\n""") - for i in set(self.initrds): - InitrdImage(i, ops.arch).write(f) + for i in idict.values(): + i.write(f) f.write(""" };\n""") f.write(""" configurations {\n""") for (name, (kernel, dtb, initrd)) in self.configurations.iteritems(): f.write(""" %s {\n""" % name) f.write(""" description = "%s";\n""" % name) - f.write(""" kernel = "%s";\n""" % (kdict[kernel].name)) - f.write(""" ramdisk = "%s";\n""" % (idict[initrd].name)) - f.write(""" fdt = "%s";\n""" % (ddict[dtb].name)) + f.write(""" kernel = "%s";\n""" % (KernelImage(kernel, ops.arch).name)) + f.write(""" ramdisk = "%s";\n""" % (InitrdImage(initrd, ops.arch).name)) + f.write(""" fdt = "%s";\n""" % (DtbImage(dtb).name)) f.write(""" };\n\n""") f.write(""" };\n""") f.write("""};\n""") @@ -298,12 +327,14 @@ if __name__ == '__main__': fit.add_yaml(y) if ops.add_platform == [['all']]: - ops.add_platform = [ subprocess.check_output("onlpm --list-platforms --arch %s" % (ops.arch), shell=True).split() ] + ops.add_platform = [ pm.list_platforms(ops.arch) ] if ops.add_platform == [['initrd']]: # Add support for the platforms listed in the initrd's platform manifest (package,f) = initrd.split(':') - mfile = subprocess.check_output("onlpm --find-file %s:%s manifest.json" % (package, ops.arch), shell=True).strip() + pkg = package + ':' + ops.arch + pm.require(pkg, force=False, build_missing=False) + mfile = pm.opr.get_file(pkg, "manifest.json") manifest = json.load(open(mfile)) ops.add_platform = [[ "%s" % p for p in manifest['platforms'] ]] From 07e68fe666ddc18b5a88960404ff4bcc81091129 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Fri, 6 May 2016 11:09:57 -0700 Subject: [PATCH 025/113] Working powerpc template, also include arm --- .../lib/platform-config-defaults-uboot.yml | 86 +++++++++++++++++-- 1 file changed, 80 insertions(+), 6 deletions(-) diff --git a/packages/base/all/vendor-config-onl/src/lib/platform-config-defaults-uboot.yml b/packages/base/all/vendor-config-onl/src/lib/platform-config-defaults-uboot.yml index c23835c8..4343389e 100644 --- a/packages/base/all/vendor-config-onl/src/lib/platform-config-defaults-uboot.yml +++ b/packages/base/all/vendor-config-onl/src/lib/platform-config-defaults-uboot.yml @@ -28,14 +28,14 @@ default: e500mc-kernel-package: &e500mc-kernel-package package: onl-kernel-3.8.13-powerpc-e500mc:powerpc - e500mc-kernel: + e500mc-kernel: &e500mc-kernel =: kernel-3.8.13-powerpc-e500mc.bin.gz <<: *e500mc-kernel-package arm-iproc-kernel-package: &arm-iproc-kernel-package package: onl-kernel-3.2-deb7-arm-iproc-all:armel - arm-iproc-kernel: + arm-iproc-kernel: &arm-iproc-kernel =: kernel-3.2-deb7-arm-iproc-all.bin.gz <<: *arm-iproc-kernel-package @@ -53,10 +53,84 @@ default: ## =: powerpc-quanta-lb9-r0.dtb ## <<: *e500v-kernel-package + ############################## + # + # pick an actual loader file, + # usually the 'all' image + # + ############################## + + powerpc-itb: &powerpc-itb + =: onl-loader-fit.itb + package: onl-loader-fit:powerpc + + arm-itb: &arm-itb + =: onl-loader-fit.itb + package: onl-loader-fit:armel + + itb: *powerpc-itb + loader: - partition: /dev/sda1 - ##partition: /dev/mmcblk0p1 + device: /dev/sda + ##device: /dev/mmcblk0 - ### True for raw partitions - ##raw: True + loadaddr: 0x10000000 + ##loadaddr: 70000000 + + # Add your own 'setenv' clauses, + # otherwise lean back and coast with these implicit ones + setenv: + ##- onl_loadaddr: @loadaddr@ + ### added automatically + ##- onl_platform: @platform@ + ### added automatically + ##- onl_itb: @itb@ + - bootargs: >- + console=$consoledev,$baudrate + onl_platform=$onl_platform + + ide_bootcmds: &ide_bootcmds + - ext2load ide 0:1 $onl_loadaddr $onl_itb + - "bootm $onl_loadaddr#$onl_platform" + + usb_bootcmds: &usb_bootcmds + - usb start + - ext2load usb 0:1 $onl_loadaddr $onl_itb + - "bootm $onl_loadaddr#$onl_platform" + + # XXX roth arm example includes the 'usbiddev' magic + usb2_bootcmds: &usb2_bootcmds + - usb start + - usbiddev + - ext2load usb 0:1 $onl_loadaddr $onl_itb + - "bootm $onl_loadaddr#$onl_platform" + + mmc_bootcmds: &mmc_bootcmds + - mmc part 0 + - ext2load mmc 0:1 $onl_loadaddr $onl_itb + - "bootm $onl_loadaddr#$onl_platform" + + nos_bootcmds: *ide_bootcmds + + # Default partitioning scheme + # boot, config --> 128MiB (ext2) + # images --> 1GiB + # data --> rest of disk + # default format (as shown) is ext4 + installer: + - ONL-BOOT: + =: 128MiB + # NOTE that u-boot wants the boot partition ext2, not ext4 + format: ext2 + ##format: raw + + - ONL-CONFIG: + =: 128MiB + format: ext4 + - ONL-IMAGES: + =: 1GiB + format: ext4 + - ONL-DATA: + =: 100% + format: ext4 From ef8c6e701a52c4eb8c394533b83ad097079fa803 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Fri, 6 May 2016 11:12:05 -0700 Subject: [PATCH 026/113] Update powerpc and arm profiles for new template --- .../r0/src/lib/arm-accton-as4610-54-r0.yml | 22 ++++++++++-- .../src/lib/powerpc-accton-as4600-54t-r0.yml | 33 ++++++++++++++++-- .../src/lib/powerpc-accton-as5610-52x-r0.yml | 34 +++++++++++++++++-- .../src/lib/powerpc-accton-as5710-54x-r0.yml | 34 ++++++++++++++++--- .../src/lib/powerpc-accton-as5710-54x-r0b.yml | 20 ++++++++--- .../src/lib/powerpc-accton-as6700-32x-r0.yml | 34 +++++++++++++++++-- .../src/lib/powerpc-accton-as6700-32x-r1.yml | 34 +++++++++++++++++-- .../r0/src/lib/arm-qemu-armv7a-r0.yml | 18 ++++++++-- .../r0/src/lib/powerpc-quanta-lb9-r0.yml | 21 +++++++++--- .../r0/src/lib/powerpc-quanta-ly2-r0.yml | 20 +++++++++-- 10 files changed, 238 insertions(+), 32 deletions(-) diff --git a/packages/platforms/accton/armel/arm-accton-as4610-54/platform-config/r0/src/lib/arm-accton-as4610-54-r0.yml b/packages/platforms/accton/armel/arm-accton-as4610-54/platform-config/r0/src/lib/arm-accton-as4610-54-r0.yml index b6df1308..010c3b7d 100644 --- a/packages/platforms/accton/armel/arm-accton-as4610-54/platform-config/r0/src/lib/arm-accton-as4610-54-r0.yml +++ b/packages/platforms/accton/armel/arm-accton-as4610-54/platform-config/r0/src/lib/arm-accton-as4610-54-r0.yml @@ -1,7 +1,23 @@ +--- + +###################################################################### +# +# platform-config for AS4610 +# +###################################################################### + arm-accton-as4610-54-r0: flat_image_tree: - kernel: onl-kernel-3.2-deb7-arm-iproc-all:armel, kernel-3.2-deb7-arm-iproc-all.bin.gz - dtb: onl-kernel-3.2-deb7-arm-iproc-all:armel, accton_as4610_54.dtb + kernel: + <<: *arm-iproc-kernel + dtb: + =: accton_as4610_54.dtb + <<: *arm-iproc-kernel-package + itb: + <<: *arm-itb loader: - partition: /dev/sda1 \ No newline at end of file + device: /dev/sda + ##partition: /dev/sda1 + loadaddr: 0x70000000 + nos_bootcmds: *usb2_bootcmds diff --git a/packages/platforms/accton/powerpc/powerpc-accton-as4600-54t/platform-config/r0/src/lib/powerpc-accton-as4600-54t-r0.yml b/packages/platforms/accton/powerpc/powerpc-accton-as4600-54t/platform-config/r0/src/lib/powerpc-accton-as4600-54t-r0.yml index 4e178c5e..b147cb47 100644 --- a/packages/platforms/accton/powerpc/powerpc-accton-as4600-54t/platform-config/r0/src/lib/powerpc-accton-as4600-54t-r0.yml +++ b/packages/platforms/accton/powerpc/powerpc-accton-as4600-54t/platform-config/r0/src/lib/powerpc-accton-as4600-54t-r0.yml @@ -1,7 +1,34 @@ +--- + +###################################################################### +# +# platform-config for AS4600 +# +###################################################################### + powerpc-accton-as4600-54t-r0: flat_image_tree: - kernel: onl-kernel-3.9.6-powerpc-e500v:powerpc, kernel-3.9.6-powerpc-e500v.bin.gz - dtb: onl-kernel-3.9.6-powerpc-e500v:powerpc, powerpc-as4600-54t.dtb + kernel: + <<: *e500v-kernel + dtb: + =: powerpc-as4600-54t.dtb + <<: *e500v-kernel-package loader: - partition: /dev/sda1 + device: /dev/sda + ##partition: /dev/sda1 + nos_bootcmds: *usb_bootcmds + + installer: + - ONL-BOOT: + =: 32MiB + format: ext2 + - ONL-CONFIG: + =: 32MiB + format: ext4 + - ONL-IMAGES: + =: 448MiB + format: ext4 + - ONL-DATA: + =: 100% + format: ext4 diff --git a/packages/platforms/accton/powerpc/powerpc-accton-as5610-52x/platform-config/r0/src/lib/powerpc-accton-as5610-52x-r0.yml b/packages/platforms/accton/powerpc/powerpc-accton-as5610-52x/platform-config/r0/src/lib/powerpc-accton-as5610-52x-r0.yml index 011674d7..a02ae482 100644 --- a/packages/platforms/accton/powerpc/powerpc-accton-as5610-52x/platform-config/r0/src/lib/powerpc-accton-as5610-52x-r0.yml +++ b/packages/platforms/accton/powerpc/powerpc-accton-as5610-52x/platform-config/r0/src/lib/powerpc-accton-as5610-52x-r0.yml @@ -1,7 +1,35 @@ +--- + +###################################################################### +# +# platform-config for AS5610 +# +###################################################################### + powerpc-accton-as5610-52x-r0: + flat_image_tree: - kernel: onl-kernel-3.9.6-powerpc-e500v:powerpc, kernel-3.9.6-powerpc-e500v.bin.gz - dtb: onl-kernel-3.9.6-powerpc-e500v:powerpc, powerpc-as5610-52x.dtb + kernel: + <<: *e500v-kernel + dtb: + =: powerpc-as5610-52x.dtb + <<: *e500v-kernel-package loader: - partition: /dev/sda1 \ No newline at end of file + device: /dev/sda + ##partition: /dev/sda1 + nos_bootcmds: *usb_bootcmds + + installer: + - ONL-BOOT: + =: 128MiB + format: ext2 + - ONL-CONFIG: + =: 128MiB + format: ext4 + - ONL-IMAGES: + =: 768MiB + format: ext4 + - ONL-DATA: + =: 100% + format: ext4 diff --git a/packages/platforms/accton/powerpc/powerpc-accton-as5710-54x/platform-config/r0/src/lib/powerpc-accton-as5710-54x-r0.yml b/packages/platforms/accton/powerpc/powerpc-accton-as5710-54x/platform-config/r0/src/lib/powerpc-accton-as5710-54x-r0.yml index 2e3bde00..91c166c8 100644 --- a/packages/platforms/accton/powerpc/powerpc-accton-as5710-54x/platform-config/r0/src/lib/powerpc-accton-as5710-54x-r0.yml +++ b/packages/platforms/accton/powerpc/powerpc-accton-as5710-54x/platform-config/r0/src/lib/powerpc-accton-as5710-54x-r0.yml @@ -1,9 +1,35 @@ +--- + +###################################################################### +# +# platform-config for AS5710 +# +###################################################################### + powerpc-accton-as5710-54x-r0: + flat_image_tree: - kernel: onl-kernel-3.8.13-powerpc-e500mc:powerpc, kernel-3.8.13-powerpc-e500mc.bin.gz - dtb: onl-kernel-3.8.13-powerpc-e500mc:powerpc, powerpc-accton-as5710-54x-r0.dtb + kernel: + <<: *e500mc-kernel + dtb: + =: powerpc-accton-as5710-54x-r0.dtb + <<: *e500mc-kernel-package loader: - partition: /dev/sda1 - raw: True + device: /dev/sda + nos_bootcmds: *usb_bootcmds + installer: + - ONL-BOOT: + =: 128MiB + format: ext2 + ##format: raw + - ONL-CONFIG: + =: 128MiB + format: ext4 + - ONL-IMAGES: + =: 1GiB + format: ext4 + - ONL-DATA: + =: 100% + format: ext4 diff --git a/packages/platforms/accton/powerpc/powerpc-accton-as5710-54x/platform-config/r0b/src/lib/powerpc-accton-as5710-54x-r0b.yml b/packages/platforms/accton/powerpc/powerpc-accton-as5710-54x/platform-config/r0b/src/lib/powerpc-accton-as5710-54x-r0b.yml index 1ceabcfe..72b71b5d 100644 --- a/packages/platforms/accton/powerpc/powerpc-accton-as5710-54x/platform-config/r0b/src/lib/powerpc-accton-as5710-54x-r0b.yml +++ b/packages/platforms/accton/powerpc/powerpc-accton-as5710-54x/platform-config/r0b/src/lib/powerpc-accton-as5710-54x-r0b.yml @@ -1,9 +1,21 @@ +--- + +###################################################################### +# +# platform-config for as5710 +# +###################################################################### + powerpc-accton-as5710-54x-r0b: + flat_image_tree: - kernel: onl-kernel-3.8.13-powerpc-e500mc:powerpc, kernel-3.8.13-powerpc-e500mc.bin.gz - dtb: onl-kernel-3.8.13-powerpc-e500mc:powerpc, powerpc-accton-as5710-54x-r0b.dtb + kernel: + <<: *e500mc-kernel + dtb: + =: powerpc-accton-as5710-54x-r0b.dtb + <<: *e500mc-kernel-package loader: - partition: /dev/sda1 - raw: True + device: /dev/sda + nos_bootcmds: *usb_bootcmds diff --git a/packages/platforms/accton/powerpc/powerpc-accton-as6700-32x/platform-config/r0/src/lib/powerpc-accton-as6700-32x-r0.yml b/packages/platforms/accton/powerpc/powerpc-accton-as6700-32x/platform-config/r0/src/lib/powerpc-accton-as6700-32x-r0.yml index a5287fe1..58f15076 100644 --- a/packages/platforms/accton/powerpc/powerpc-accton-as6700-32x/platform-config/r0/src/lib/powerpc-accton-as6700-32x-r0.yml +++ b/packages/platforms/accton/powerpc/powerpc-accton-as6700-32x/platform-config/r0/src/lib/powerpc-accton-as6700-32x-r0.yml @@ -1,8 +1,36 @@ +--- + +###################################################################### +# +# platform-config for AS6700 +# +###################################################################### + powerpc-accton-as6700-32x-r0: + flat_image_tree: - kernel: onl-kernel-3.8.13-powerpc-e500mc:powerpc, kernel-3.8.13-powerpc-e500mc.bin.gz - dtb: onl-kernel-3.8.13-powerpc-e500mc:powerpc, powerpc-accton-as6700-32x-r0.dtb + kernel: + <<: *e500mc-kernel + dtb: + =: powerpc-accton-as6700-32x-r0.dtb + <<: *e500mc-kernel-package loader: - partition: /dev/sda1 + device: /dev/sda + ##partition: /dev/sda1 + nos_bootcmds: *usb_bootcmds + + installer: + - ONL-BOOT: + =: 128MiB + format: ext2 + - ONL-CONFIG: + =: 128MiB + format: ext4 + - ONL-IMAGES: + =: 768MiB + format: ext4 + - ONL-DATA: + =: 100% + format: ext4 diff --git a/packages/platforms/accton/powerpc/powerpc-accton-as6700-32x/platform-config/r1/src/lib/powerpc-accton-as6700-32x-r1.yml b/packages/platforms/accton/powerpc/powerpc-accton-as6700-32x/platform-config/r1/src/lib/powerpc-accton-as6700-32x-r1.yml index dbb1187d..f35a9391 100644 --- a/packages/platforms/accton/powerpc/powerpc-accton-as6700-32x/platform-config/r1/src/lib/powerpc-accton-as6700-32x-r1.yml +++ b/packages/platforms/accton/powerpc/powerpc-accton-as6700-32x/platform-config/r1/src/lib/powerpc-accton-as6700-32x-r1.yml @@ -1,8 +1,36 @@ +--- + +###################################################################### +# +# platform-config for AS6700 +# +###################################################################### + powerpc-accton-as6700-32x-r1: + flat_image_tree: - kernel: onl-kernel-3.8.13-powerpc-e500mc:powerpc, kernel-3.8.13-powerpc-e500mc.bin.gz - dtb: onl-kernel-3.8.13-powerpc-e500mc:powerpc, powerpc-accton-as6700-32x-r1.dtb + kernel: + <<: *e500mc-kernel + dtb: + =: powerpc-accton-as6700-32x-r1.dtb + <<: *e500mc-kernel-package loader: - partition: /dev/sda1 + device: /dev/sda + ##partition: /dev/sda1 + nos_bootcmds: *usb_bootcmds + + installer: + - ONL-BOOT: + =: 128MiB + format: ext2 + - ONL-CONFIG: + =: 128MiB + format: ext4 + - ONL-IMAGES: + =: 768MiB + format: ext4 + - ONL-DATA: + =: 100% + format: ext4 diff --git a/packages/platforms/qemu/arm/arm-qemu-armv7a/platform-config/r0/src/lib/arm-qemu-armv7a-r0.yml b/packages/platforms/qemu/arm/arm-qemu-armv7a/platform-config/r0/src/lib/arm-qemu-armv7a-r0.yml index ce884b4a..dd31aaad 100644 --- a/packages/platforms/qemu/arm/arm-qemu-armv7a/platform-config/r0/src/lib/arm-qemu-armv7a-r0.yml +++ b/packages/platforms/qemu/arm/arm-qemu-armv7a/platform-config/r0/src/lib/arm-qemu-armv7a-r0.yml @@ -1,4 +1,18 @@ +--- + +###################################################################### +# +# platform-config for ARM/QEMU +# +###################################################################### + arm-qemu-armv7a-r0: + flat_image_tree: - kernel: onl-kernel-3.2-deb7-arm-iproc-all:armel, kernel-3.2-deb7-arm-iproc-all.bin.gz - dtb: onl-kernel-3.2-deb7-arm-iproc-all:armel, accton_as4610_54.dtb + kernel: + <<: *arm-iproc-kernel + dtb: + =: accton_as4610_54.dtb + <<: *arm-iproc-kernel-package + itb: + <<: *arm-itb diff --git a/packages/platforms/quanta/powerpc/powerpc-quanta-lb9/platform-config/r0/src/lib/powerpc-quanta-lb9-r0.yml b/packages/platforms/quanta/powerpc/powerpc-quanta-lb9/platform-config/r0/src/lib/powerpc-quanta-lb9-r0.yml index 309845f9..e21363f2 100644 --- a/packages/platforms/quanta/powerpc/powerpc-quanta-lb9/platform-config/r0/src/lib/powerpc-quanta-lb9-r0.yml +++ b/packages/platforms/quanta/powerpc/powerpc-quanta-lb9/platform-config/r0/src/lib/powerpc-quanta-lb9-r0.yml @@ -1,8 +1,21 @@ +--- + +###################################################################### +# +# platform definition for LB9 +# +###################################################################### + powerpc-quanta-lb9-r0: + flat_image_tree: - kernel: onl-kernel-3.9.6-powerpc-e500v:powerpc, kernel-3.9.6-powerpc-e500v.bin.gz - dtb: onl-kernel-3.9.6-powerpc-e500v:powerpc, powerpc-quanta-lb9-r0.dtb + + kernel: + <<: *e500v-kernel + dtb: + =: powerpc-quanta-lb9-r0.dtb + <<: *e500v-kernel-package loader: - partition: /dev/sda1 - raw: True + device: /dev/sda + nos_bootcmds: *ide_bootcmds diff --git a/packages/platforms/quanta/powerpc/powerpc-quanta-ly2/platform-config/r0/src/lib/powerpc-quanta-ly2-r0.yml b/packages/platforms/quanta/powerpc/powerpc-quanta-ly2/platform-config/r0/src/lib/powerpc-quanta-ly2-r0.yml index 95c591b1..80af8e38 100644 --- a/packages/platforms/quanta/powerpc/powerpc-quanta-ly2/platform-config/r0/src/lib/powerpc-quanta-ly2-r0.yml +++ b/packages/platforms/quanta/powerpc/powerpc-quanta-ly2/platform-config/r0/src/lib/powerpc-quanta-ly2-r0.yml @@ -1,7 +1,21 @@ +--- + +###################################################################### +# +# platform-config for LY2 +# +###################################################################### + powerpc-quanta-ly2-r0: + flat_image_tree: - kernel: onl-kernel-3.9.6-powerpc-e500v:powerpc, kernel-3.9.6-powerpc-e500v.bin.gz - dtb: onl-kernel-3.9.6-powerpc-e500v:powerpc, powerpc-quanta-ly2-r0.dtb + kernel: + <<: *e500v-kernel + dtb: + =: powerpc-quanta-ly2-r0.dtb + <<: *e500v-kernel-package loader: - partition: /dev/mmcblk0p1 + device: /dev/mmcblk0 + ##partition: /dev/mmcblk0p1 + nos_bootcmds: *mmc_bootcmds From f8c9f414842095df17533f91ff4d560de3536acd Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Fri, 6 May 2016 11:12:48 -0700 Subject: [PATCH 027/113] Added vendor config packages to loader --- .../base/any/initrds/loader/builds/Makefile | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/packages/base/any/initrds/loader/builds/Makefile b/packages/base/any/initrds/loader/builds/Makefile index dc39a03d..b117a086 100644 --- a/packages/base/any/initrds/loader/builds/Makefile +++ b/packages/base/any/initrds/loader/builds/Makefile @@ -13,6 +13,7 @@ PLATFORMS := $(shell onlpm --list-platforms --arch $(ARCH)) endif PLATFORM_PACKAGES := $(foreach p,$(PLATFORMS),onl-platform-config-$(p):$(ARCH)) +VENDOR_PACKAGES := $(foreach p,$(PLATFORMS),$(shell python $(ONL)/tools/onlplatform.py $(p) $(ARCH) vendor)) ROOT := root TARGET := onl-loader-initrd-$(ARCH).cpio.gz @@ -24,6 +25,7 @@ $(TARGET): $(ONLPM) --sudo --force --extract-dir onl-loader-initrd-files:all $(ROOT) $(ONLPM) --sudo --force --extract-dir onl-vendor-config-onl-loader:all $(ROOT) $(ONLPM) --sudo $(foreach p,$(PLATFORM_PACKAGES),--extract-dir $(p) $(ROOT)) + $(MAKE) __vendor_config_data $(ONLPM) --sudo --force --extract-dir onl-vendor-config-onl:all $(ROOT) $(ONL)/tools/sjson.py --kj version $(ONL)/make/version-onl.json --kl platforms $(PLATFORMS) --kv arch $(ARCH) --out manifest.json sudo mkdir -p $(ROOT)/etc/onl/loader && sudo cp manifest.json $(ROOT)/etc/onl/loader @@ -31,7 +33,14 @@ $(TARGET): sudo $(ONL)/tools/cpiomod.py --cpio onl-buildroot-initrd-$(ARCH).cpio.gz --add-directory $(ROOT) --out $@ sudo rm -rf $(ROOT) onl-buildroot-initrd-$(ARCH).cpio.gz - - - - +__vendor_config_data: + set -e ;\ + vpkgs= ;\ + l="$(PLATFORMS)"; for p in $$l; do \ + vpkg=$$(python $(ONL)/tools/onlplatform.py $$p $(ARCH) vendor) ;\ + case " $$vpkgs " in *" $$vpkg "*) continue ;; esac ;\ + vpkgs=$$vpkgs$${vpkgs:+" "}$$vpkg ;\ + echo "Adding vendor package $$vpkg" ;\ + $(ONLPM) --sudo --force --extract-dir $$vpkg $(ROOT) ;\ + done ;\ + : From 089f5be4d9f76b63338b7f46d7d531f21ac1aa80 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Fri, 6 May 2016 11:13:49 -0700 Subject: [PATCH 028/113] Added mkfs commands --- .../src/python/onl/install/InstallUtils.py | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/packages/base/all/vendor-config-onl/src/python/onl/install/InstallUtils.py b/packages/base/all/vendor-config-onl/src/python/onl/install/InstallUtils.py index 922aecef..4b8f1760 100644 --- a/packages/base/all/vendor-config-onl/src/python/onl/install/InstallUtils.py +++ b/packages/base/all/vendor-config-onl/src/python/onl/install/InstallUtils.py @@ -143,6 +143,40 @@ class SubprocessMixin: self.log.debug("+ /bin/ln -s %s %s", tgt, dst) os.symlink(tgt, dst) + def mkdosfs(self, dev, label=None): + if label is not None: + cmd = ('mkdosfs', '-n', label, dev,) + else: + cmd = ('mkdosfs', dev,) + self.check_call(cmd, vmode=self.V1) + + def mke2fs(self, dev, label=None): + if label is not None: + cmd = ('mkfs.ext2', '-L', label, dev,) + else: + cmd = ('mkfs.ext2', dev,) + self.check_call(cmd, vmode=self.V1) + + def mke4fs(self, dev, label=None, huge_file=True): + if label is not None: + cmd = ['mkfs.ext4', '-L', label, dev,] + else: + cmd = ['mkfs.ext4', dev,] + + if not huge_file: + cmd[1:1] = ['-O', '^huge_file',] + # hack needed for some old ONIE kernels + + self.check_call(cmd, vmode=self.V1) + + def mkfs(self, dev, fstype): + mkfs = 'mkfs.%s' % fstype + cmd = (mkfs, dev,) + + # 'mkfs -h' says to use '-V' for verbose, + # don't believe it + self.check_call(cmd, vmode=self.V1) + class TempdirContext(SubprocessMixin): def __init__(self, prefix=None, suffix=None, chroot=None, log=None): From 9c383236bb96c4b1e438c4767dfda373dae5d660 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Fri, 6 May 2016 11:26:54 -0700 Subject: [PATCH 029/113] Update/refactor, u-boot install is now a thing --- .../src/python/onl/install/App.py | 7 +- .../src/python/onl/install/BaseInstall.py | 636 +++++++++--------- 2 files changed, 329 insertions(+), 314 deletions(-) diff --git a/packages/base/all/vendor-config-onl/src/python/onl/install/App.py b/packages/base/all/vendor-config-onl/src/python/onl/install/App.py index 714fd182..79884203 100644 --- a/packages/base/all/vendor-config-onl/src/python/onl/install/App.py +++ b/packages/base/all/vendor-config-onl/src/python/onl/install/App.py @@ -14,11 +14,6 @@ from InstallUtils import InitrdContext from InstallUtils import SubprocessMixin import ConfUtils, BaseInstall -# locate the platform-config files using SWI path rules -sys.path.append("/usr/lib/python%s/dist-packages" - % (distutils.sysconfig.get_python_version(),)) - -import onl.platform.base import onl.platform.current class App(SubprocessMixin): @@ -33,7 +28,7 @@ class App(SubprocessMixin): self.installer = None self.machineConf = None self.installerConf = None - self.platform = None + self.onlPlatform = None def run(self): diff --git a/packages/base/all/vendor-config-onl/src/python/onl/install/BaseInstall.py b/packages/base/all/vendor-config-onl/src/python/onl/install/BaseInstall.py index 22ae8850..d85c1a8c 100644 --- a/packages/base/all/vendor-config-onl/src/python/onl/install/BaseInstall.py +++ b/packages/base/all/vendor-config-onl/src/python/onl/install/BaseInstall.py @@ -18,6 +18,10 @@ import onl.YamlUtils class Base: class installmeta: + + grub = False + uboot = False + def __init__(self, installerConf=None, machineConf=None, @@ -38,17 +42,30 @@ class Base: machineConf=None, installerConf=None, platformConf=None, grubEnv=None, ubootEnv=None, log=None): - self.machineConf = machineConf - self.installerConf = installerConf self.im = self.installmeta(installerConf=installerConf, machineConf=machineConf, platformConf=platformConf, grubEnv=grubEnv, ubootEnv = ubootEnv) - self.grubEnv = grubEnv - self.ubootEnv = ubootEnv self.log = log or logging.getLogger(self.__class__.__name__) + self.device = None + # target device, initialize this later + + self.minpart = None + self.nextBlock = None + # keep track of next partition/next block + + self.blkidParts = [] + # current scan of partitions and labels + + self.partedDevice = None + self.partedDisk = None + # parted state + + self.configArchive = None + # backup of ONL-CONFIG during re-partitioning + def run(self): self.log.error("not implemented") return 1 @@ -58,7 +75,7 @@ class Base: def installSwi(self): - swis = [x for x in os.listdir(self.installerConf.installer_dir) if x.endswith('.swi')] + swis = [x for x in os.listdir(self.im.installerConf.installer_dir) if x.endswith('.swi')] if not swis: self.log.info("No ONL Software Image available for installation.") self.log.info("Post-install ZTN installation will be required.") @@ -68,7 +85,7 @@ class Base: return base = swis[0] - src = os.path.join(self.installerConf.installer_dir, base) + src = os.path.join(self.im.installerConf.installer_dir, base) self.log.info("Installing ONL Software Image (%s)...", base) dev = self.blkidParts['ONL-IMAGES'] @@ -110,6 +127,159 @@ class Base: raise SystemExit("backup of ONL-CONFIG failed") self.unlink(archive) + def deletePartitions(self): + + nextBlock = -1 + dirty = False + for part in self.partedDisk.partitions: + self.log.info("examining %s part %d", + self.partedDisk.device.path, part.number) + if part.number < self.minpart: + self.log.info("skip this part") + nextBlock = max(part.geometry.start+part.geometry.length, + nextBlock) + else: + self.log.info("deleting this part") + self.partedDisk.removePartition(part) + dirty = True + + if dirty: + self.partedDisk.commit() + self.check_call(('partprobe', self.device,)) + + if nextBlock > -1: + self.nextBlock = nextBlock + else: + self.log.warn("no partitions, starting at block 1") + + return 0 + + def partitionParted(self): + """Build partitions according to the partition spec. + + XXX roth -- hopefully the GPT labels specified here + work correctly (that is, are ignored) on an msdos label + """ + + constraint = self.partedDevice.optimalAlignedConstraint + # default partition layout constraint + + devices = {} + + def _u2s(sz, u): + bsz = sz * u + bsz = bsz + self.partedDevice.physicalSectorSize - 1 + return bsz / self.partedDevice.physicalSectorSize + + UNITS = { + 'GiB' : 1024 * 1024 * 1024, + 'G' : 1000 * 1000 * 1000, + 'MiB' : 1024 * 1024, + 'M' : 1000 * 1000, + 'KiB' : 1024, + 'K' : 1000, + } + + for part in self.im.platformConf['installer']: + + label, partData = list(part.items())[0] + if type(partData) == dict: + sz, fmt = partData['='], partData.get('format', 'ext4') + else: + sz, fmt = partData, 'ext4' + + cnt = None + nextBlock = self.nextBlock or 1 + minpart = self.minpart or 1 + for ul, ub in UNITS.items(): + if sz.endswith(ul): + cnt = _u2s(int(sz[:-len(ul)], 10), ub) + break + if sz == '100%': + cnt = self.partedDevice.getLength() - nextBlock + if cnt is None: + self.log.error("invalid size (no units) for %s: %s", + part, sz) + return 1 + + start = nextBlock + end = start + cnt - 1 + if end <= self.partedDevice.getLength(): + self.log.info("Allocating %d sectors for %s", + cnt, label) + else: + self.log.warn("%s: start sector %d, end sector %d, max %d", + label, start, end, + self.partedDevice.getLength()) + self.log.error("invalid partition %s [%s] (too big)", + label, sz) + return 1 + + geom = parted.Geometry(device=self.partedDevice, + start=start, length=end-start+1) + fs = parted.FileSystem(type=fmt, geometry=geom) + part = parted.Partition(disk=self.partedDisk, + type=parted.PARTITION_NORMAL, + fs=fs, + geometry=geom) + if self.partedDisk.type == 'gpt': + part.getPedPartition().set_name(label) + self.partedDisk.addPartition(part, constraint=constraint) + self.partedDisk.commit() + self.check_call(('partprobe', self.device,)) + + if fmt == 'raw': + self.log.info("Leaving %s (%s) unformatted (raw)", + part.path, label) + else: + self.log.info("Formatting %s (%s) as %s", + part.path, label, fmt) + if fmt == 'msdos': + self.mkdosfs(part.path, label=label) + elif fmt == 'ext4': + self.mke4fs(part.path, label=label, huge_file=False) + elif fmt == 'ext2': + self.mke2fs(part.path, label=label) + else: + self.mkfs(part.path, fstype=fmt) + + self.nextBlock, self.minpart = end+1, minpart+1 + + devices[label] = part.path + + if label == 'ONL-CONFIG' and self.configArchive is not None: + self.restoreConfig(part.path) + + self.blkidParts = BlkidParser(log=self.log.getChild("blkid")) + # re-read the partitions + + return 0 + + def installBootConfig(self): + + try: + dev = self.blkidParts['ONL-BOOT'] + except IndexError as ex: + self.log.warn("cannot find ONL-BOOT partition (maybe raw?) : %s", str(ex)) + return 1 + + self.log.info("Installing boot-config to %s", dev.device) + + src = os.path.join(self.im.installerConf.installer_dir, 'boot-config') + ##src = os.path.join(self.im.installerConf.installer_platform_dir, 'boot-config') + with MountContext(dev.device, log=self.log) as ctx: + dst = os.path.join(ctx.dir, 'boot-config') + self.copy2(src, dst) + + with open(src) as fd: + ecf = fd.read().encode('base64', 'strict').strip() + if self.im.grub and self.im.grubEnv is not None: + setattr(self.im.grubEnv, 'boot_config_default', ecf) + if self.im.uboot and self.im.ubootEnv is not None: + setattr(self.im.ubootEnv, 'boot-config-default', ecf) + + return 0 + GRUB_TPL = """\ #serial --port=0x3f8 --speed=115200 --word=8 --parity=no --stop=1 serial %(serial)s @@ -144,18 +314,6 @@ class GrubInstaller(SubprocessMixin, Base): def __init__(self, *args, **kwargs): Base.__init__(self, *args, **kwargs) - self.device = None - self.minpart = None - self.nextBlock = None - - self.blkidParts = [] - - self.partedDevice = None - self.partedDisk = None - - self.configArchive = None - # backup of ONL-CONFIG during re-partitioning - def findGpt(self): self.blkidParts = BlkidParser(log=self.log.getChild("blkid")) @@ -234,127 +392,6 @@ class GrubInstaller(SubprocessMixin, Base): return 0 - def deletePartitions(self): - - nextBlock = -1 - for part in self.partedDisk.partitions: - self.log.info("examining %s part %d", - self.partedDisk.device.path, part.number) - if part.number < self.minpart: - self.log.info("skip this part") - nextBlock = max(part.geometry.start+part.geometry.length, - nextBlock) - else: - self.log.info("deleting this part") - self.partedDisk.removePartition(part) - - if nextBlock < 0: - self.log.error("cannot find a starting block") - return 1 - - self.nextBlock = nextBlock - return 0 - - def partitionGpt(self): - - constraint = self.partedDevice.optimalAlignedConstraint - # default partition layout constraint - - devices = {} - - def _u2s(sz, u): - bsz = sz * u - bsz = bsz + self.partedDevice.physicalSectorSize - 1 - return bsz / self.partedDevice.physicalSectorSize - - UNITS = { - 'GiB' : 1024 * 1024 * 1024, - 'G' : 1000 * 1000 * 1000, - 'MiB' : 1024 * 1024, - 'M' : 1000 * 1000, - 'KiB' : 1024, - 'K' : 1000, - } - - for part in self.im.platformConf['installer']: - - label, sz = list(part.items())[0] - if type(sz) == dict: - sz, fmt = sz['='], sz.get('format', 'ext4') - else: - fmt = 'ext4' - - cnt = None - for ul, ub in UNITS.items(): - if sz.endswith(ul): - cnt = _u2s(int(sz[:-len(ul)], 10), ub) - break - if sz == '100%': - cnt = self.partedDevice.getLength() - self.nextBlock - if cnt is None: - self.log.error("invalid size (no units) for %s: %s", - part, sz) - return 1 - - start = self.nextBlock - end = start + cnt - 1 - if end <= self.partedDevice.getLength(): - self.log.info("Allocating %d sectors for %s", - cnt, label) - else: - self.log.warn("%s: start sector %d, end sector %d, max %d", - label, start, end, - self.partedDevice.getLength()) - self.log.error("invalid partition %s [%s] (too big)", - label, sz) - return 1 - - geom = parted.Geometry(device=self.partedDevice, - start=start, length=end-start+1) - fs = parted.FileSystem(type=fmt, geometry=geom) - part = parted.Partition(disk=self.partedDisk, - type=parted.PARTITION_NORMAL, - fs=fs, - geometry=geom) - part.getPedPartition().set_name(label) - self.partedDisk.addPartition(part, constraint=constraint) - self.partedDisk.commit() - - self.log.info("Formatting %s (%s) as %s", - part.path, label, fmt) - if fmt == 'msdos': - cmd = ('mkdosfs', '-n', label, part.path,) - else: - cmd = ('mkfs.%s' % fmt, '-L', label, part.path,) - self.check_call(cmd, vmode=self.V1) - - self.nextBlock, self.minpart = end+1, self.minpart+1 - - devices[label] = part.path - - if label == 'ONL-CONFIG' and self.configArchive is not None: - self.restoreConfig(part.path) - - self.blkidParts = BlkidParser(log=self.log.getChild("blkid")) - # re-read the partitions - - return 0 - - def installBootConfig(self): - dev = self.blkidParts['ONL-BOOT'] - self.log.info("Installing boot-config to %s", dev.device) - - src = os.path.join(self.installerConf.installer_dir, 'boot-config') - with MountContext(dev.device, log=self.log) as ctx: - dst = os.path.join(ctx.dir, 'boot-config') - self.copy2(src, dst) - - with open(src) as fd: - ecf = fd.read().encode('base64', 'strict').strip() - setattr(self.grubEnv, 'boot_config_default', ecf) - - return 0 - def installLoader(self): ctx = {} @@ -366,7 +403,7 @@ class GrubInstaller(SubprocessMixin, Base): ctx['initrd'] = initrd['='] if type(initrd) == dict else initrd ctx['args'] = self.im.platformConf['grub']['args'] - ctx['platform'] = self.installerConf.installer_platform + ctx['platform'] = self.im.installerConf.installer_platform ctx['serial'] = self.im.platformConf['grub']['serial'] cf = GRUB_TPL % ctx @@ -375,12 +412,12 @@ class GrubInstaller(SubprocessMixin, Base): dev = self.blkidParts['ONL-BOOT'] with MountContext(dev.device, log=self.log) as ctx: def _cp(b): - src = os.path.join(self.installerConf.installer_dir, b) + src = os.path.join(self.im.installerConf.installer_dir, b) if not os.path.isfile(src): return if b.startswith('kernel-') or b.startswith('onl-loader-initrd-'): dst = os.path.join(ctx.dir, b) self.copy2(src, dst) - [_cp(e) for e in os.listdir(self.installerConf.installer_dir)] + [_cp(e) for e in os.listdir(self.im.installerConf.installer_dir)] d = os.path.join(ctx.dir, "grub") self.makedirs(d) @@ -392,7 +429,7 @@ class GrubInstaller(SubprocessMixin, Base): def installGrub(self): self.log.info("Installing GRUB to %s", self.partedDevice.path) - self.grubEnv.install(self.partedDevice.path) + self.im.grubEnv.install(self.partedDevice.path) return 0 def installGpt(self): @@ -423,14 +460,14 @@ class GrubInstaller(SubprocessMixin, Base): self.log.info("next usable block is %s", self.nextBlock) - code = self.partitionGpt() + code = self.partitionParted() if code: return code # once we assign the ONL-BOOT partition, # we can re-target the grub environment dev = self.blkidParts['ONL-BOOT'] - self.grubEnv.__dict__['bootPart'] = dev.device - self.grubEnv.__dict__['bootDir'] = None + self.im.grubEnv.__dict__['bootPart'] = dev.device + self.im.grubEnv.__dict__['bootDir'] = None code = self.installSwi() if code: return code @@ -466,207 +503,142 @@ class UbootInstaller(SubprocessMixin, Base): class installmeta(Base.installmeta): - device = None uboot = True - loaderBlocks = None - flashBlocks = None - flash2Blocks = None - # block count, or -1 for "rest" - - loaderRaw = True - # true for raw loader partition (FIT image) - - loaderSrc = None - # default loader source file (auto-detect) - - loaderDst = "onl-loader" - # destination path on ONL-BOOT for non-raw installs - - bootConf = None - # optional pre-formatted boot-config contents - # (string or list of strings) - - bootCmd = None - # pre-formatted string - - bootCmds = None - # ... or a list of strings + def getDevice(self): + loader = self.platformConf.get('loader', {}) + dev = loader.get('device', None) + return dev def str_bootcmd(self): - if self.bootCmd is not None: return self.bootCmd - if self.bootCmds: - return "; ".join(self.bootCmds) - raise ValueError("missing boot commands") + cmds = [] + cmds.append("setenv onl_loadaddr 0x%x" + % self.platformConf['loader']['loadaddr']) + cmds.append("setenv onl_platform %s" + % self.installerConf.installer_platform) + itb = self.platformConf['flat_image_tree']['itb'] + if type(itb) == dict: itb = itb['='] + cmds.append("setenv onl_itb %s" % itb) + for item in self.platformConf['loader']['setenv']: + k, v = list(item.items())[0] + cmds.append("setenv %s %s" % (k, v,)) + cmds.extend(self.platformConf['loader']['nos_bootcmds']) + return "; ".join(cmds) def __init__(self, *args, **kwargs): - kwargs = dict(kwargs) - installerConf = kwargs.pop('installerConf', None) - machineConf = kwargs.pop('machineConf', None) - platformConf = kwargs.pop('platformConf', None) - ubootEnv = kwargs.pop('ubootEnv', None) - self.im = self.installmeta(installerConf=installerConf, - machineConf=machineConf, - platformConf=platormConf, - ubootEnv=ubootEnv) - Base.__init__(self, *args, - machineConf=machineConf, installerConf=installerConf, platformConf=platformConf, - ubootEnv=ubootEnv, - **kwargs) + Base.__init__(self, *args, **kwargs) - # XXX roth - self.onlBootDev = None - self.onlConfigDev = None - self.onlDataDev = None + self.device = self.im.getDevice() - def formatBlockdev(self): + self.rawLoaderDevice = None + # set to a partition device for raw loader install, + # default to None for FS-based install - if self.im.loaderBlocks < 0: - self.log.error("no size defined for ONL-BOOT") - return 1 - if self.im.flashBlocks < 0: - self.log.error("no size defined for FLASH") - return 1 + def maybeCreateLabel(self): + """Set up an msdos label.""" - self.log.info("Formatting %s as %d:%d:%d", - self.im.device, - self.im.loaderBlocks, - self.im.flashBlocks, - self.im.flash2Blocks) + self.partedDevice = parted.getDevice(self.device) + try: + self.partedDisk = parted.newDisk(self.partedDevice) + if self.partedDisk.type == 'msdos': + self.log.info("disk %s is already msdos", self.device) + return 0 + self.log.warn("disk %s has wrong label %s", + self.device, self.partedDisk.type) + except parted._ped.PartedException as ex: + self.log.error("cannot get partition table from %s: %s", + self.device, str(ex)) - self.check_call(('parted', '-s', self.im.device, - 'mklabel', 'msdos',)) + self.log.info("creating msdos label on %s") + self.partedDisk = parted.freshDisk(self.partedDevice, 'msdos') - start = 1 - end = start + self.im.loaderBlocks-1 + return 0 - self.check_call(('parted', '-s', self.im.device, - 'unit', 's', - 'mkpart', 'primary', 'fat32', str(start)+'s', str(end)+'s',)) + def findMsdos(self): + """Backup any existing data. - self.onlBootDev = self.im.device + '1' - if not self.im.loaderRaw: - cmd = ('mkdosfs', '-n', 'ONL-BOOT', self.onlBootDev,) - self.check_call(cmd, vmode=self.V1) + The GPT version of this function is more tricky since it needs + to save some of the partitions. Here with and msdos label that + is on a different block device from u-boot or ONIE, we don't + really care. + """ - start = end + 1 - end = start + self.im.flashBlocks-1 + # optionally back up a config partition + # if it's on the boot device + for part in self.blkidParts: + dev, partno = part.splitDev() + if dev == self.device and part.label == 'ONL-CONFIG': + self.backupConfig(part.device) - self.check_call(('parted', '-s', self.im.device, - 'unit', 's', - 'mkpart', 'primary', 'fat32', str(start)+'s', str(end)+'s',)) - - self.onlConfigDev = self.im.device + '2' - cmd = ('mkdosfs', '-n', 'FLASH', self.onlConfigDev,) - self.check_call(cmd, vmode=self.V1) - - start = end + 1 - if self.im.flash2Blocks > -1: - end = start + self.im.flash2Blocks-1 - self.check_call(('parted', '-s', self.im.device, - 'unit', 's', - 'mkpart', 'primary', 'fat32', str(start)+'s', str(end)+'s',)) - else: - self.check_call(('parted', '-s', self.im.device, - 'unit', 's', - 'mkpart', 'primary', 'fat32', str(start)+'s', '100%',)) - - self.onlDataDev = self.im.device + '3' - cmd = ('mkdosfs', '-n', 'FLASH2', self.onlDataDev,) - self.check_call(cmd, vmode=self.V1) + self.minPart = -1 + # default, delete all partitions + # XXX roth -- tweak this if we intent to save e.g. + # a diag partition from the vendor return 0 def installLoader(self): loaderSrc = None - for cand in (("%s/%s.itb" - % (self.installerConf.installer_dir, - self.installerConf.installer_platform,)), - os.path.join(self.installerConf.installer_dir, 'powerpc-fit-all.itb'), - self.im.loaderSrc, - ("%s/onl.%s.loader" - % (self.installerConf.installer_dir, - self.installerConf.installer_platform,))): - if os.path.exists(cand): - loaderSrc = cand + c1 = self.im.platformConf['flat_image_tree'].get('itb', None) + if type(c1) == dict: c1 = c1.get('=', None) + c2 = ("%s.itb" + % (self.im.installerConf.installer_platform,)) + c3 = "onl-loader-fit.itb" + + loaderSrc = None + for c in (c1, c2, c3): + if c is None: continue + p = os.path.join(self.im.installerConf.installer_dir, c) + if os.path.exists(p): + loaderSrc = p break + if not loaderSrc: self.log.error("The platform loader file is missing.") - self.log.error("This is unexpected - %s", loaderSrc) return 1 - self.log.info("Installing the ONL loader...") + self.log.info("Installing the ONL loader from %s...", loaderSrc) - if self.im.loaderRaw: + if self.rawLoaderDevice is not None: + self.log.info("Installing ONL loader %s --> %s...", + loaderSrc, self.rawLoaderDevice) cmd = ('dd', 'if=' + loaderSrc, - 'of=' + self.onlBootDev,) + 'of=' + self.rawLoaderDevice,) self.check_call(cmd, vmode=self.V2) else: - with MountContext(self.onlBootDev, log=self.log) as ctx: - dst = os.path.join(ctx, self.im.loaderDst) + dev = self.blkidParts['ONL-BOOT'] + basename = os.path.split(loaderSrc)[1] + self.log.info("Installing ONL loader %s --> %s:%s...", + loaderSrc, dev.device, basename) + with MountContext(dev.device, log=self.log) as ctx: + dst = os.path.join(ctx.dir, basename) self.copy2(loaderSrc, dst) return 0 - def installBootconfig(self): - - cf = None - - p = os.path.join(self.installerConf.installer_dir, 'boot-config') - if cf is None and os.path.exists(p): - cf = open(p, "r").read() - - p = os.path.join(self.installerConf.installer_platform_dir, 'boot-config') - if cf is None and os.path.exists(p): - cf = open(p, "r").read() - - if cf is None and self.im.bootConf: - if isinstance(self.im.bootConf, basestring): - cf = self.im.bootConf - else: - cf = "\n".join(cf) + "\n" - - if cf is None: - buf = StringIO.StringIO() - buf.write("SWI=images:onl-%s.swi\n" - % (self.platformConf.installer_arch,)) - buf.write("NETDEV=ma1\n") - cf = buf.getvalue() - - self.log.info("Writing boot-config.") - with MountContext(self.onlConfigDev, log=self.log) as ctx: - dst = os.path.join(ctx.dir, "boot-config") - with open(dst, "w") as fd: - fd.write(cf) - - ecf = cf.encode('base64', 'strict').strip() - setattr(self.ubootEnv, 'boot-config-default', ecf) - - return 0 - def installUbootEnv(self): # Special access instructions for initrd - off = getattr(self.installerConf, 'initrd_offset', None) + off = getattr(self.im.installerConf, 'initrd_offset', None) if off is not None: - if self.im.loaderRaw: - a = self.onlBootDev + if self.rawLoaderDevice is not None: + a = self.rawLoaderDevice else: - a = self.installerConf.initrd_archive - s = int(self.installerConf.initrd_offset) - e = s + int(self.installerConf.initrd_size) - 1 - self.ubootEnv.onl_installer_initrd = ("%s:%x:%x" % (a, s, e,)) + a = self.im.installerConf.initrd_archive + s = int(self.im.installerConf.initrd_offset) + e = s + int(self.im.installerConf.initrd_size) - 1 + self.im.ubootEnv.onl_installer_initrd = ("%s:%x:%x" % (a, s, e,)) else: try: - del self.installerConf.onl_installer_initrd + del self.im.installerConf.onl_installer_initrd except AttributeError: pass if self.im.isOnie(): self.log.info("Setting ONIE nos_bootcmd to boot ONL") - self.ubootEnv.nos_bootcmd = self.im.str_bootcmd() + self.im.ubootEnv.nos_bootcmd = self.im.str_bootcmd() else: self.log.warn("U-boot boot setting is not changed") @@ -674,23 +646,66 @@ class UbootInstaller(SubprocessMixin, Base): def installUboot(self): - st = os.stat(self.im.device) + if self.device is None: + self.log.error("missing block device YAML config") + return 1 + st = os.stat(self.device) if not stat.S_ISBLK(st[stat.ST_MODE]): - self.log.error("not a block device: %s", - self.im.device) + self.log.error("not a block device: %s", self.device) return 1 - code = self.formatBlockdev() + code = self.maybeCreateLabel() + if code: return code + + self.log.info("Installing to %s", self.device) + + if self.partedDisk.type != 'msdos': + self.log.error("not an MSDOS partition table") + return 1 + if self.partedDevice.sectorSize != 512: + self.log.error("invalid logical block size") + return 1 + if self.partedDevice.physicalSectorSize != 512: + self.log.error("invalid physical block size") + return 1 + + self.log.info("found a disk with %d blocks", + self.partedDevice.getLength()) + + code = self.findMsdos() + if code: return code + + code = self.deletePartitions() + if code: return code + + self.log.info("next usable block is %s", self.nextBlock) + + code = self.partitionParted() + if code: return code + + # compute the path to the raw loader partition, + # if indicated by the configuration + + self.rawLoaderDevice = None + for item in self.im.platformConf['installer']: + partIdx, partData = list(item.items())[0] + label, part = list(partData.items())[0] + if label == 'ONL-BOOT' and part['format'] == 'raw': + self.rawLoaderDevice = self.device + str(partIdx+1) + break + + code = self.installSwi() if code: return code code = self.installLoader() if code: return code - code = self.installBootconfig() - if code: return code - - code = self.installSwi() - if code: return code + if self.rawLoaderDevice is None: + code = self.installBootConfig() + if code: return code + else: + self.log.info("ONL-BOOT is a raw partition (%s), skipping boot-config", + self.rawLoaderDevice) self.log.info("syncing block devices") self.check_call(('sync',)) @@ -702,6 +717,11 @@ class UbootInstaller(SubprocessMixin, Base): return 0 def run(self): + + if 'flat_image_tree' not in self.im.platformConf: + self.log.error("platform config is missing a FIT section") + return 1 + return self.installUboot() def shutdown(self): From 0cf41fd6d9b1917196437a20ab2e6ed9022950ab Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Fri, 6 May 2016 11:27:26 -0700 Subject: [PATCH 030/113] Re-write shell functions to use OnlPlatform data --- .../src/python/onl/install/ShellApp.py | 242 +++++++++++------- 1 file changed, 147 insertions(+), 95 deletions(-) diff --git a/packages/base/all/vendor-config-onl/src/python/onl/install/ShellApp.py b/packages/base/all/vendor-config-onl/src/python/onl/install/ShellApp.py index add79f67..c0ff2fa2 100644 --- a/packages/base/all/vendor-config-onl/src/python/onl/install/ShellApp.py +++ b/packages/base/all/vendor-config-onl/src/python/onl/install/ShellApp.py @@ -12,8 +12,11 @@ import struct from InstallUtils import InitrdContext, MountContext from InstallUtils import SubprocessMixin from InstallUtils import ProcMountsParser, ProcMtdParser +from InstallUtils import BlkidParser import Fit +import onl.platform.current + class AppBase(SubprocessMixin): @property @@ -42,7 +45,7 @@ class AppBase(SubprocessMixin): pass return 0 - def _runMtdShell(self, device): + def _runFitShell(self, device): self.log.debug("parsing FIT image in %s", device) p = Fit.Parser(path=device, log=self.log) node = p.getInitrdNode() @@ -111,56 +114,66 @@ class Onie(AppBase): def run(self): + self.pm = ProcMountsParser() + self.blkid = BlkidParser(log=self.log.getChild("blkid")) + self.mtd = ProcMtdParser(log=self.log.getChild("mtd")) + def _g(d): pat = os.path.join(d, "onie/initrd.img*") l = glob.glob(pat) if l: return l[0] return None - # try to find onie initrd on a mounted fs (GRUB) - initrd = _g("/mnt/onie-boot") - if initrd is not None: - self.log.debug("found ONIE initrd at %s", initrd) - return self._runInitrdShell(initrd) - - # try to find the onie boot partition elsewhere - pm = ProcMountsParser() + # try to find a mounted, labeled partition try: - dev = self.check_output(('blkid', '-L', 'ONIE-BOOT',)).strip() - except subprocess.CalledProcessError, what: + dev = self.blkid['ONIE-BOOT'].device + except IndexError: dev = None if dev is not None: self.log.debug("found ONIE boot device %s", dev) - parts = [p for p in pm.mounts if p.device == dev] + + parts = [p for p in self.pm.mounts if p.device == dev] if parts: onieDir = parts[0] self.log.debug("found ONIE boot mounted at %s", onieDir) initrd = _g(onieDir) - if initrd is not None: + if initrd is None: + self.log.warn("cannot find ONIE initrd on %s", onieDir) + else: self.log.debug("found ONIE initrd at %s", initrd) return _runInitrdShell(initrd) + + with MountContext(dev, log=self.log) as ctx: + initrd = _g(ctx.dir) + if initrd is None: + self.log.warn("cannot find ONIE initrd on %s", dev) else: - self.log.error("cannot find ONIE initrd") - return 1 + self.log.debug("found ONIE initrd at %s", initrd) + return self._runInitrdShell(initrd) + + self.log.warn("cannot find an ONIE initrd") + return 1 + + # try to find onie initrd on a mounted fs (GRUB); + # for ONIE images this is usually /mnt/onie-boot + for part in self.pm.mounts: + if not part.device.startswith('/dev/'): continue + initrd = _g(part.dir) + if initrd is None: + self.log.debug("cannot find ONIE initrd on %s (%s)", + part.device, part.dir) else: - with MountContext(dev, fsType='ext4', log=self.log) as ctx: - initrd = _g(ctx.dir) - if initrd is not None: - self.log.debug("found ONIE initrd at %s", initrd) - return self._runInitrdShell(initrd) - else: - self.log.error("cannot find ONIE initrd") - return 1 + self.log.debug("found ONIE initrd at %s", initrd) + return self._runInitrdShell(initrd) # grovel through MTD devices (u-boot) - pm = ProcMtdParser(log=self.log) - parts = [p for p in pm.parts if p.label == "onie"] + parts = [p for p in self.mtd.parts if p.label == "onie"] if parts: part = parts[0] self.log.debug("found ONIE MTD device %s", part.charDevice or part.blockDevice) - return self._runMtdShell(part.blockDevice) - elif pm.parts: + return self._runFitShell(part.blockDevice) + elif self.mtd.mounts: self.log.error("cannot find ONIE MTD device") return 1 @@ -171,78 +184,117 @@ class Loader(AppBase): PROG = "loader-shell" - def run(self): + def runGrub(self): - def _g(d): - pat = os.path.join(d, "initrd-*") - l = glob.glob(pat) - if l: return l[0] - return None - - # try to find the loader boot partition as a formatted block device - pm = ProcMountsParser() try: - dev = self.check_output(('blkid', '-L', 'SL-BOOT',)).strip() - except subprocess.CalledProcessError, what: - dev = None - if dev is not None: - self.log.debug("found loader device %s", dev) - parts = [p for p in pm.mounts if p.device == dev] - if parts: - loaderDir = parts[0] - self.log.debug("found loader device mounted at %s", loaderDir) - initrd = _g(loaderDir) - if initrd is not None: - self.log.debug("found loader initrd at %s", initrd) - return _runInitrdShell(initrd) - else: - self.log.error("cannot find loader initrd") - return 1 - else: - with MountContext(dev, fsType='ext4', log=self.log) as ctx: - initrd = _g(ctx.dir) - if initrd is not None: - self.log.debug("found loader initrd at %s", initrd) - return self._runInitrdShell(initrd) - else: - self.log.error("cannot find loader initrd") - return 1 - - # try to find the loader partition on the same desk as /mnt/flash - try: - flashDev = self.check_output(('blkid', '-L', 'FLASH',)).strip() - except subprocess.CalledProcessError, what: - flashDev = None - if flashDev is not None: - self.log.debug("found flash device hint %s", flashDev) - loaderDev = flashDev - while loaderDev and loaderDev[-1] in string.digits: - loaderDev = loaderDev[:-1] - loaderDev = loaderDev + '1' - with open(loaderDev) as fd: - buf = fd.read(4) - magic = struct.unpack(">I", buf)[0] - if magic == Fit.Parser.FDT_MAGIC: - self.log.debug("found loader device %s", loaderDev) - return self._runMtdShell(loaderDev) - else: - self.log.error("bad FDT signature on %s %x", - loaderDev, magic) - return 1 - - # grovel through MTD devices (u-boot) - pm = ProcMtdParser(log=self.log) - parts = [p for p in pm.parts if p.label == "sl-boot"] - if parts: - part = parts[0] - self.log.debug("found loader MTD device %s", - part.charDevice or part.blockDevice) - return self._runMtdShell(part.blockDevice) - elif pm.parts: - self.log.error("cannot find loader MTD device") + dev = self.blkid['ONL-BOOT'].device + except KeyError: + pass + if dev is None: + self.log.error("cannot find GRUB partition %s", dev) return 1 - self.log.error("cannot find loader initrd") + initrd = self.pc['grub']['initrd'] + if type(initrd) == dict: initrd = initrd['='] + + parts = [p for p in self.pm.mounts if p.device == dev] + if parts: + grubDir = parts[0] + self.log.debug("found loader device %s mounted at %s", + dev, grubDir) + p = os.path.join(grubDir, initrd) + if not os.path.exists(p): + self.log.error("cannot find initrd %s", p) + return 1 + self.log.debug("found loader initrd at %s", p) + return self._runInitrdShell(p) + + with MountContext(dev, log=self.log) as ctx: + p = os.path.join(ctx.dir, initrd) + if not os.path.exists(p): + self.log.error("cannot find initrd %s:%s", dev, p) + return 1 + self.log.debug("found loader initrd at %s:%s", dev, p) + return self._runInitrdShell(p) + + def runUboot(self): + + dev = self.pc['loader']['device'] + self.log.info("found loader device %s", dev) + + parts = self.pc['installer'] + bootPart = None + bootPartno = None + for idx, part in enumerate(self.pc['installer']): + label, pdata = list(part.items())[0] + if label == 'ONL-BOOT': + bootPart = pdata + bootPartno = idx + 1 + break + if bootPart is None: + self.log.info("cannot find ONL-BOOT declaration") + return 1 + + fmt = bootPart.get('format', 'ext2') + if fmt == 'raw': + bootDevice = dev + str(bootPartno) + else: + bootDevice = self.blkid['ONL-BOOT'].device + + # run from a raw partition + if fmt == 'raw': + self.log.info("found (raw) boot partition %s", bootDevice) + return self._runFitShell(bootDevice) + + l = [] + + p = self.pc['flat_image_tree']['itb'] + if type(p) == dict: p = p['='] + if p not in l: l.append(p) + + p = self.platform.platform() + '.itb' + if p not in l: l.append(p) + + p = 'onl-loader-fit.itb' + if p not in l: l.append(p) + + self.log.info("looking for loader images %s", ", ".join(l)) + + # run from a file in a mounted filesystem + parts = [p for p in self.pm.mounts if p.device == bootDevice] + if parts: + loaderDir = parts[0] + self.log.debug("found loader device mounted at %s", loaderDir) + for e in l: + p = os.path.join(loaderDir, e) + if os.path.exists(p): return self._runFitShell(p) + self.log.error("cannot find an ITB") + return 1 + + # run from a file in an umounted filesystem + with MountContext(bootDevice, log=self.log) as ctx: + self.log.info("found (%s) loader device %s", fmt, bootDevice) + for e in l: + p = os.path.join(ctx.dir, e) + if os.path.exists(p): return self._runFitShell(p) + self.log.error("cannot find an ITB") + return 1 + + def run(self): + + self.platform = onl.platform.current.OnlPlatform() + self.pc = self.platform.platform_config + + self.pm = ProcMountsParser() + self.blkid = BlkidParser(log=self.log.getChild("blkid")) + + if 'grub' in self.pc: + return self.runGrub() + + if 'flat_image_tree' in self.pc: + return self.runUboot() + + self.log.error("invalid platform-config") return 1 main = Onie.main From 385e78d350db02ecc184d963066b9c5f240921c5 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Fri, 6 May 2016 11:31:18 -0700 Subject: [PATCH 031/113] Added powerpc installer build --- builds/powerpc/installer/new-hotness/Makefile | 1 + builds/powerpc/installer/new-hotness/PKG.yml | 2 + .../installer/new-hotness/builds/.gitignore | 1 + .../installer/new-hotness/builds/Makefile | 109 ++++++++++++++++++ .../installer/new-hotness/builds/boot-config | 4 + 5 files changed, 117 insertions(+) create mode 100644 builds/powerpc/installer/new-hotness/Makefile create mode 100644 builds/powerpc/installer/new-hotness/PKG.yml create mode 100644 builds/powerpc/installer/new-hotness/builds/.gitignore create mode 100644 builds/powerpc/installer/new-hotness/builds/Makefile create mode 100644 builds/powerpc/installer/new-hotness/builds/boot-config diff --git a/builds/powerpc/installer/new-hotness/Makefile b/builds/powerpc/installer/new-hotness/Makefile new file mode 100644 index 00000000..003238cf --- /dev/null +++ b/builds/powerpc/installer/new-hotness/Makefile @@ -0,0 +1 @@ +include $(ONL)/make/pkg.mk \ No newline at end of file diff --git a/builds/powerpc/installer/new-hotness/PKG.yml b/builds/powerpc/installer/new-hotness/PKG.yml new file mode 100644 index 00000000..c7c734e7 --- /dev/null +++ b/builds/powerpc/installer/new-hotness/PKG.yml @@ -0,0 +1,2 @@ +!include $ONL/builds/any/installer/new-hotness/APKG.yml ARCH=powerpc + diff --git a/builds/powerpc/installer/new-hotness/builds/.gitignore b/builds/powerpc/installer/new-hotness/builds/.gitignore new file mode 100644 index 00000000..fbd18542 --- /dev/null +++ b/builds/powerpc/installer/new-hotness/builds/.gitignore @@ -0,0 +1 @@ +*INSTALLER diff --git a/builds/powerpc/installer/new-hotness/builds/Makefile b/builds/powerpc/installer/new-hotness/builds/Makefile new file mode 100644 index 00000000..5b24ae41 --- /dev/null +++ b/builds/powerpc/installer/new-hotness/builds/Makefile @@ -0,0 +1,109 @@ +include $(ONL)/make/config.powerpc.mk + +ONLPLATFORM = python $(ONL)/tools/onlplatform.py +PLATFORMS := $(shell $(ONLPM) --platform-manifest onl-loader-initrd:$(ARCH)) + +MKSHAR = $(ONL)/tools/mkshar +MKSHAR_OPTS = --lazy --unzip-pad --fixup-perms autoperms.sh +MKSHAR_PERMS = autoperms.sh + +VONLDIR = $(ONL)/packages/base/all/vendor-config-onl +PYFIT = $(VONLDIR)/src/bin/pyfit +PYFIT_ENVIRONMENT = PYTHONPATH=$(VONLDIR)/src/python + +# Hardcoded to match ONL File naming conventions. +include $(ONL)/make/version-onl.mk +INSTALLER_NAME=$(FNAME_PRODUCT_VERSION)_ONL-OS_$(FNAME_BUILD_ID)_$(UARCH)_INSTALLER + +# default fit image can be used as the canonical location for the initrd +FIT_IMAGE_ALL := $(shell $(ONLPM) --find-file onl-loader-fit:$(ARCH) onl-loader-fit.itb) +INITRD := $(shell $(ONLPM) --find-file onl-loader-initrd:$(ARCH) onl-loader-initrd-$(ARCH).cpio.gz) +INITRD_BOUNDS := $(shell $(PYFIT_ENVIRONMENT) $(PYFIT) -v offset $(FIT_IMAGE_ALL) --initrd) + +__installer: installer.sh __installer_fit_files __installer_platform_files __installer_swi_files + $(ONL_V_at)rm -rf *INSTALLER* *.md5sum + $(ONL_V_at)cp /dev/null $(MKSHAR_PERMS) + $(ONL_V_at)cp $(ONL)/make/version-onl.sh . + $(ONL_V_at)echo "#!/bin/sh" >> $(MKSHAR_PERMS) + $(ONL_V_at)echo "set -e" >> $(MKSHAR_PERMS) + $(ONL_V_at)echo "set -x" >> $(MKSHAR_PERMS) + $(MKSHAR) $(MKSHAR_OPTS) "$(INSTALLER_NAME)" $(ONL)/tools/scripts/sfx.sh.in installer.sh *.swi *.itb version-onl.sh boot-config + $(ONL_V_at)rm -rf installer.sh *.itb *.swi version-onl.sh autoperms.sh + md5sum "$(INSTALLER_NAME)" | awk '{ print $$1 }' > "$(INSTALLER_NAME).md5sum" + +installer.sh: Makefile $(ONL)/builds/any/installer/new-hotness/installer.sh.in + $(ONL_V_GEN)cp /dev/null $@ + $(ONL_V_at): ;\ + set -e ;\ + if $(ONL_V_P); then set -x; fi ;\ + if test "$(INITRD_BOUNDS)"; then \ + a="$(FIT_IMAGE_ALL)"; a=$${a##*/} ;\ + else \ + a="$(INITRD)"; i=$${a##*/} ;\ + fi ;\ + set dummy $(INITRD_BOUNDS); start=$$2; end=$$3; sz=$$(($$end - $$start + 1)) ;\ + sed \ + -e 's^@ONLVERSION@^$(VERSION_STRING)^g' \ + -e "s^@INITRD_ARCHIVE@^$${a}^g" \ + -e "s^@INITRD_OFFSET@^$$start^g" \ + -e "s^@INITRD_SIZE@^$$sz^g" \ + -e 's^@ARCH@^ppc^g' \ + $(ONL)/builds/any/installer/new-hotness/installer.sh.in \ + >> $@ + $(ONL_V_at)echo "PAYLOAD_FOLLOWS" >> $@ + +__installer_fit_files: + $(ONL_V_GEN): ;\ + set -e ;\ + if $(ONL_V_P); then set -x; fi ;\ + src=$(FIT_IMAGE_ALL) ;\ + dst=$${src##*/} ;\ + if test "$$dst" -nt Makefile; then \ + : ;\ + else \ + echo "Staging $$dst" ;\ + cp $$src $$dst ;\ + fi ;\ + : + +############################## +# +# optionally include custom itb files for each platform +# +############################## + +__installer_platform_files: + $(ONL_V_GEN): ;\ + set -e ;\ + if $(ONL_V_P); then set -x; fi ;\ + l="$(PLATFORMS)"; for p in $$l; do \ + echo "Looking for an ITB specific to $$p, ignore errors..." ;\ + src=$$($(ONLPLATFORM) $$p $(ARCH) itb) 2>/dev/null || : ;\ + if test "$$src"; then :; else continue; fi ;\ + dst=$${src##*/} ;\ + echo "Found $$dst" ;\ + if test "$$dst" -nt Makefile; then continue; fi ;\ + echo "Staging $$dst for $$p" ;\ + cp "$$src" "$$dst" ;\ + done ;\ + : + +__installer_swi_files: +ifndef NO_SWI + $(ONL_V_GEN): ;\ + set -e ;\ + if $(ONL_V_P); then set -x; fi ;\ + swidir=$$(mktemp -d $(PWD)/swi-d-XXXXXX) ;\ + $(ONLPM) --extract-dir onl-swi:$(ARCH) $$swidir ;\ + mv $$swidir/usr/share/onl/packages/$(ARCH)/onl-swi/*.swi . ;\ + rm -fr $$swidir ;\ + : +else + $(ONL_V_GEN): +endif + +shar installer: installer + +clean: + rm -f *.swi *.installer *.cpio.gz + diff --git a/builds/powerpc/installer/new-hotness/builds/boot-config b/builds/powerpc/installer/new-hotness/builds/boot-config new file mode 100644 index 00000000..40fb0d31 --- /dev/null +++ b/builds/powerpc/installer/new-hotness/builds/boot-config @@ -0,0 +1,4 @@ +NETDEV=ma1 +NETAUTO=dhcp +BOOTMODE=SWI +SWI=images::latest From 7a1a873985f3181b3751dec51281b6917bcac634 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Fri, 6 May 2016 16:37:10 -0700 Subject: [PATCH 032/113] Fixed whitespace in command args --- tools/onlpm.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/onlpm.py b/tools/onlpm.py index 62ef67bc..ef893912 100755 --- a/tools/onlpm.py +++ b/tools/onlpm.py @@ -366,12 +366,12 @@ class OnlPackage(object): if 'init' in self.pkg: if not os.path.exists(self.pkg['init']): raise OnlPackageError("Init script '%s' does not exist." % self.pkg['init']) - command = command + "--deb-init %s" % self.pkg['init'] + command = command + "--deb-init %s " % self.pkg['init'] if 'post-install' in self.pkg: if not os.path.exists(self.pkg['post-install']): raise OnlPackageError("Post-install script '%s' does not exist." % self.pkg['post-install']) - command = command + "--after-install %s" % self.pkg['post-install'] + command = command + "--after-install %s " % self.pkg['post-install'] if logger.level < logging.INFO: command = command + "--verbose " From f38e167b77fedd25ff153caf1b6c1a1033726754 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Fri, 6 May 2016 16:37:25 -0700 Subject: [PATCH 033/113] Remove deprecated files --- .../builds/patches/python-pyblkid.Config.in | 6 --- .../builds/patches/python-pyblkid.mk | 41 ------------------- 2 files changed, 47 deletions(-) delete mode 100644 packages/base/any/initrds/buildroot/builds/patches/python-pyblkid.Config.in delete mode 100644 packages/base/any/initrds/buildroot/builds/patches/python-pyblkid.mk diff --git a/packages/base/any/initrds/buildroot/builds/patches/python-pyblkid.Config.in b/packages/base/any/initrds/buildroot/builds/patches/python-pyblkid.Config.in deleted file mode 100644 index 6207230a..00000000 --- a/packages/base/any/initrds/buildroot/builds/patches/python-pyblkid.Config.in +++ /dev/null @@ -1,6 +0,0 @@ -config BR2_PACKAGE_PYTHON_PYBLKID - bool "python-pyblkid" - depends on BR2_PACKAGE_PYTHON - depends on BR2_PACKAGE_UTIL_LINUX - help - Include the 'pyblkid' Python library diff --git a/packages/base/any/initrds/buildroot/builds/patches/python-pyblkid.mk b/packages/base/any/initrds/buildroot/builds/patches/python-pyblkid.mk deleted file mode 100644 index 8299426b..00000000 --- a/packages/base/any/initrds/buildroot/builds/patches/python-pyblkid.mk +++ /dev/null @@ -1,41 +0,0 @@ -###################################################################### -## -## python-pyblkid.mk -## -###################################################################### - -PYTHON_PYBLKID_VERSION = 0.0.1 -PYTHON_PYBLKID_SOURCE = pyblkid-$(PYTHON_PYBLKID_VERSION).tar.bz2 -PYTHON_PYBLKID_INSTALL_STAGING = NO -PYTHON_PYBLKID_INSTALL_TARGET = YES -PYTHON_PYBLKID_LICENSE = GPL -PYTHON_PYBLKID_LICENSE_FILES = COPYING - -PYTHON_PYBLKID_DEPENDENCIES = python util-linux - -PYTHON_PYBLKID_INCLUDES = \ - --include-dirs $(STAGING_DIR)/usr/include:$(STAGING_DIR)/usr/include/python$(PYTHON_VERSION_MAJOR) \ - # THIS LINE INTENTIONALLY LEFT BLANK - -PYTHON_PYBLKID_LIBDIRS = \ - --library-dirs $(STAGING_DIR)/usr/lib \ - # THIS LINE INTENTIONALLY LEFT BLANK - -# see python-mad.mk -PYTHON_PYBLKID_ENVIRONMENT = \ - CC="$(TARGET_CC)" \ - CFLAGS="$(TARGET_CFLAGS)" \ - LDSHARED="$(TARGET_CC) -shared" \ - LDFLAGS="$(TARGET_LDFLAGS)" \ - # THIS LINE INTENTIONALLY LEFT BLANK - -define PYTHON_PYBLKID_BUILD_CMDS - (cd $(@D); $(HOST_DIR)/usr/bin/python setup.py build_py) - (cd $(@D); $(PYTHON_PYBLKID_ENVIRONMENT) $(HOST_DIR)/usr/bin/python setup.py build_ext $(PYTHON_PYBLKID_INCLUDES) $(PYTHON_PYBLKID_LIBDIRS)) -endef - -define PYTHON_PYBLKID_INSTALL_TARGET_CMDS - (cd $(@D); $(HOST_DIR)/usr/bin/python setup.py install --prefix=$(TARGET_DIR)/usr --install-scripts=$(TARGET_DIR)/usr/bin) -endef - -$(eval $(generic-package)) From 90990441208597201d2963530b80380bf740b773 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Fri, 6 May 2016 16:38:52 -0700 Subject: [PATCH 034/113] Refactor rules for installer --- .../installer/new-hotness/builds/Makefile | 87 +------------- .../new-hotness/grub/builds/Makefile | 94 +++++++++++++++ .../new-hotness/uboot/builds/Makefile | 111 ++++++++++++++++++ .../installer/new-hotness/builds/Makefile | 109 +---------------- 4 files changed, 207 insertions(+), 194 deletions(-) create mode 100644 builds/any/installer/new-hotness/grub/builds/Makefile create mode 100644 builds/any/installer/new-hotness/uboot/builds/Makefile diff --git a/builds/amd64/installer/new-hotness/builds/Makefile b/builds/amd64/installer/new-hotness/builds/Makefile index c3e85267..065c502a 100644 --- a/builds/amd64/installer/new-hotness/builds/Makefile +++ b/builds/amd64/installer/new-hotness/builds/Makefile @@ -1,87 +1,2 @@ include $(ONL)/make/config.amd64.mk - -ONLPLATFORM = python $(ONL)/tools/onlplatform.py -PLATFORMS := $(shell $(ONLPM) --platform-manifest onl-loader-initrd:$(ARCH)) - -MKSHAR = $(ONL)/tools/mkshar -MKSHAR_OPTS = --lazy --unzip-pad --fixup-perms autoperms.sh -MKSHAR_PERMS = autoperms.sh - -# Hardcoded to match ONL File naming conventions. -include $(ONL)/make/version-onl.mk -INSTALLER_NAME=$(FNAME_PRODUCT_VERSION)_ONL-OS_$(FNAME_BUILD_ID)_$(UARCH)_INSTALLER - - -__installer: __installer_platform_files __installer_swi_files - $(ONL_V_at)rm -rf *INSTALLER* *.md5sum - $(ONL_V_at)cp /dev/null installer.sh - $(ONL_V_at): ;\ - set -e ;\ - if $(ONL_V_P); then set -x; fi ;\ - set dummy *.cpio.gz; initrd="$$2" ;\ - sed \ - -e 's^@ONLVERSION@^$(VERSION_STRING)^g' \ - -e "s^@INITRD_ARCHIVE@^$$initrd^g" \ - -e 's^@INITRD_OFFSET@^^g' \ - -e 's^@INITRD_SIZE@^^g' \ - -e 's^@ARCH@^x86_64^g' \ - $(ONL)/builds/any/installer/new-hotness/installer.sh.in \ - >> installer.sh - $(ONL_V_at)echo "PAYLOAD_FOLLOWS" >> installer.sh - $(ONL_V_at)cp /dev/null $(MKSHAR_PERMS) - $(ONL_V_at)cp $(ONL)/make/version-onl.sh . - $(ONL_V_at)echo "#!/bin/sh" >> $(MKSHAR_PERMS) - $(ONL_V_at)echo "set -e" >> $(MKSHAR_PERMS) - $(ONL_V_at)echo "set -x" >> $(MKSHAR_PERMS) - $(MKSHAR) $(MKSHAR_OPTS) "$(INSTALLER_NAME)" $(ONL)/tools/scripts/sfx.sh.in installer.sh kernel-* onl-loader-initrd-* *.swi version-onl.sh boot-config - $(ONL_V_at)rm -rf installer.sh kernel-* onl-loader-initrd-* $(ZTN_MANIFEST) *.swi version-onl.sh autoperms.sh - md5sum "$(INSTALLER_NAME)" | awk '{ print $$1 }' > "$(INSTALLER_NAME).md5sum" - -__installer_platform_files: - $(ONL_V_GEN): ;\ - set -e ;\ - if $(ONL_V_P); then set -x; fi ;\ - l="$(PLATFORMS)"; for p in $$l; do \ - src=$$($(ONLPLATFORM) $$p $(ARCH) kernel 2>/dev/null) || : ;\ - if test "$$src"; then \ - dst=$${src##*/} ;\ - if test "$dst" -ot Makefile; then \ - : ;\ - else \ - echo "Staging $$dst for $$p" ;\ - cp "$$src" "$$dst" ;\ - fi ;\ - fi ;\ - src=$$($(ONLPLATFORM) $$p $(ARCH) initrd 2>/dev/null) || : ;\ - if test "$$src"; then \ - dst=$${src##*/} ;\ - if test "$dst" -ot Makefile; then \ - : ;\ - else \ - echo "Staging $$dst for $$p" ;\ - cp "$$src" "$$dst" ;\ - fi ;\ - fi ;\ - done ;\ - : - -ifndef NO_SWI -__installer_swi_files: - $(ONL_V_GEN): ;\ - set -e ;\ - if $(ONL_V_P); then set -x; fi ;\ - swidir=$$(mktemp -d $(PWD)/swi-d-XXXXXX) ;\ - $(ONLPM) --extract-dir onl-swi:$(ARCH) $$swidir ;\ - mv $$swidir/usr/share/onl/packages/$(ARCH)/onl-swi/*.swi . ;\ - rm -fr $$swidir ;\ - : -else -__installer_swi_files: - $(ONL_V_GEN): -endif - -shar installer: installer - -clean: - rm -f *.swi *.installer $(notdir $(KERNELS)) *initrd*.cpio.gz - +include $(ONL)/builds/any/installer/new-hotness/grub/builds/Makefile diff --git a/builds/any/installer/new-hotness/grub/builds/Makefile b/builds/any/installer/new-hotness/grub/builds/Makefile new file mode 100644 index 00000000..fabadf3b --- /dev/null +++ b/builds/any/installer/new-hotness/grub/builds/Makefile @@ -0,0 +1,94 @@ +ifndef ARCH +$(error $$ARCH not set) +endif + +ONLPLATFORM = python $(ONL)/tools/onlplatform.py +PLATFORMS := $(shell $(ONLPM) --platform-manifest onl-loader-initrd:$(ARCH)) + +MKSHAR = $(ONL)/tools/mkshar +MKSHAR_OPTS = --lazy --unzip-pad --fixup-perms autoperms.sh +MKSHAR_PERMS = autoperms.sh + +# Hardcoded to match ONL File naming conventions. +include $(ONL)/make/version-onl.mk +INSTALLER_NAME=$(FNAME_PRODUCT_VERSION)_ONL-OS_$(FNAME_BUILD_ID)_$(UARCH)_INSTALLER + +ifeq ($(ARCH), amd64) +INSTALLER_ARCH = x86_64 +else +INSTALLER_ARCH = $(ARCH) +endif + +__installer: __installer_platform_files __installer_swi_files + $(ONL_V_at)rm -rf *INSTALLER* *.md5sum + $(ONL_V_at)cp /dev/null installer.sh + $(ONL_V_at): ;\ + set -e ;\ + if $(ONL_V_P); then set -x; fi ;\ + set dummy *.cpio.gz; initrd="$$2" ;\ + sed \ + -e 's^@ONLVERSION@^$(VERSION_STRING)^g' \ + -e "s^@INITRD_ARCHIVE@^$$initrd^g" \ + -e 's^@INITRD_OFFSET@^^g' \ + -e 's^@INITRD_SIZE@^^g' \ + -e 's^@ARCH@^$(INSTALLER_ARCH)^g' \ + $(ONL)/builds/any/installer/new-hotness/installer.sh.in \ + >> installer.sh + $(ONL_V_at)echo "PAYLOAD_FOLLOWS" >> installer.sh + $(ONL_V_at)cp /dev/null $(MKSHAR_PERMS) + $(ONL_V_at)cp $(ONL)/make/version-onl.sh . + $(ONL_V_at)echo "#!/bin/sh" >> $(MKSHAR_PERMS) + $(ONL_V_at)echo "set -e" >> $(MKSHAR_PERMS) + $(ONL_V_at)echo "set -x" >> $(MKSHAR_PERMS) + $(MKSHAR) $(MKSHAR_OPTS) "$(INSTALLER_NAME)" $(ONL)/tools/scripts/sfx.sh.in installer.sh kernel-* onl-loader-initrd-* *.swi version-onl.sh boot-config + $(ONL_V_at)rm -rf installer.sh kernel-* onl-loader-initrd-* $(ZTN_MANIFEST) *.swi version-onl.sh autoperms.sh + md5sum "$(INSTALLER_NAME)" | awk '{ print $$1 }' > "$(INSTALLER_NAME).md5sum" + +__installer_platform_files: + $(ONL_V_GEN): ;\ + set -e ;\ + if $(ONL_V_P); then set -x; fi ;\ + l="$(PLATFORMS)"; for p in $$l; do \ + src=$$($(ONLPLATFORM) $$p $(ARCH) kernel 2>/dev/null) || : ;\ + if test "$$src"; then \ + dst=$${src##*/} ;\ + if test "$dst" -ot Makefile; then \ + : ;\ + else \ + echo "Staging $$dst for $$p" ;\ + cp "$$src" "$$dst" ;\ + fi ;\ + fi ;\ + src=$$($(ONLPLATFORM) $$p $(ARCH) initrd 2>/dev/null) || : ;\ + if test "$$src"; then \ + dst=$${src##*/} ;\ + if test "$dst" -ot Makefile; then \ + : ;\ + else \ + echo "Staging $$dst for $$p" ;\ + cp "$$src" "$$dst" ;\ + fi ;\ + fi ;\ + done ;\ + : + +ifndef NO_SWI +__installer_swi_files: + $(ONL_V_GEN): ;\ + set -e ;\ + if $(ONL_V_P); then set -x; fi ;\ + swidir=$$(mktemp -d $(PWD)/swi-d-XXXXXX) ;\ + $(ONLPM) --extract-dir onl-swi:$(ARCH) $$swidir ;\ + mv $$swidir/usr/share/onl/packages/$(ARCH)/onl-swi/*.swi . ;\ + rm -fr $$swidir ;\ + : +else +__installer_swi_files: + $(ONL_V_GEN): +endif + +shar installer: installer + +clean: + rm -f *.swi *.installer $(notdir $(KERNELS)) *initrd*.cpio.gz + diff --git a/builds/any/installer/new-hotness/uboot/builds/Makefile b/builds/any/installer/new-hotness/uboot/builds/Makefile new file mode 100644 index 00000000..4755bf30 --- /dev/null +++ b/builds/any/installer/new-hotness/uboot/builds/Makefile @@ -0,0 +1,111 @@ +ifndef ARCH +$(error $$ARCH not set) +endif + +ONLPLATFORM = python $(ONL)/tools/onlplatform.py +PLATFORMS := $(shell $(ONLPM) --platform-manifest onl-loader-initrd:$(ARCH)) + +MKSHAR = $(ONL)/tools/mkshar +MKSHAR_OPTS = --lazy --unzip-pad --fixup-perms autoperms.sh +MKSHAR_PERMS = autoperms.sh + +VONLDIR = $(ONL)/packages/base/all/vendor-config-onl +PYFIT = $(VONLDIR)/src/bin/pyfit +PYFIT_ENVIRONMENT = PYTHONPATH=$(VONLDIR)/src/python + +# Hardcoded to match ONL File naming conventions. +include $(ONL)/make/version-onl.mk +INSTALLER_NAME=$(FNAME_PRODUCT_VERSION)_ONL-OS_$(FNAME_BUILD_ID)_$(UARCH)_INSTALLER + +# default fit image can be used as the canonical location for the initrd +FIT_IMAGE_ALL := $(shell $(ONLPM) --find-file onl-loader-fit:$(ARCH) onl-loader-fit.itb) +INITRD := $(shell $(ONLPM) --find-file onl-loader-initrd:$(ARCH) onl-loader-initrd-$(ARCH).cpio.gz) +INITRD_BOUNDS := $(shell $(PYFIT_ENVIRONMENT) $(PYFIT) -v offset $(FIT_IMAGE_ALL) --initrd) + +__installer: installer.sh __installer_fit_files __installer_platform_files __installer_swi_files + $(ONL_V_at)rm -rf *INSTALLER* *.md5sum + $(ONL_V_at)cp /dev/null $(MKSHAR_PERMS) + $(ONL_V_at)cp $(ONL)/make/version-onl.sh . + $(ONL_V_at)echo "#!/bin/sh" >> $(MKSHAR_PERMS) + $(ONL_V_at)echo "set -e" >> $(MKSHAR_PERMS) + $(ONL_V_at)echo "set -x" >> $(MKSHAR_PERMS) + $(MKSHAR) $(MKSHAR_OPTS) "$(INSTALLER_NAME)" $(ONL)/tools/scripts/sfx.sh.in installer.sh *.swi *.itb version-onl.sh boot-config + $(ONL_V_at)rm -rf installer.sh *.itb *.swi version-onl.sh autoperms.sh + md5sum "$(INSTALLER_NAME)" | awk '{ print $$1 }' > "$(INSTALLER_NAME).md5sum" + +installer.sh: Makefile $(ONL)/builds/any/installer/new-hotness/installer.sh.in + $(ONL_V_GEN)cp /dev/null $@ + $(ONL_V_at): ;\ + set -e ;\ + if $(ONL_V_P); then set -x; fi ;\ + if test "$(INITRD_BOUNDS)"; then \ + a="$(FIT_IMAGE_ALL)"; a=$${a##*/} ;\ + else \ + a="$(INITRD)"; i=$${a##*/} ;\ + fi ;\ + set dummy $(INITRD_BOUNDS); start=$$2; end=$$3; sz=$$(($$end - $$start + 1)) ;\ + sed \ + -e 's^@ONLVERSION@^$(VERSION_STRING)^g' \ + -e "s^@INITRD_ARCHIVE@^$${a}^g" \ + -e "s^@INITRD_OFFSET@^$$start^g" \ + -e "s^@INITRD_SIZE@^$$sz^g" \ + -e 's^@ARCH@^ppc^g' \ + $(ONL)/builds/any/installer/new-hotness/installer.sh.in \ + >> $@ + $(ONL_V_at)echo "PAYLOAD_FOLLOWS" >> $@ + +__installer_fit_files: + $(ONL_V_GEN): ;\ + set -e ;\ + if $(ONL_V_P); then set -x; fi ;\ + src=$(FIT_IMAGE_ALL) ;\ + dst=$${src##*/} ;\ + if test "$$dst" -nt Makefile; then \ + : ;\ + else \ + echo "Staging $$dst" ;\ + cp $$src $$dst ;\ + fi ;\ + : + +############################## +# +# optionally include custom itb files for each platform +# +############################## + +__installer_platform_files: + $(ONL_V_GEN): ;\ + set -e ;\ + if $(ONL_V_P); then set -x; fi ;\ + l="$(PLATFORMS)"; for p in $$l; do \ + echo "Looking for an ITB specific to $$p, ignore errors..." ;\ + src=$$($(ONLPLATFORM) $$p $(ARCH) itb) 2>/dev/null || : ;\ + if test "$$src"; then :; else continue; fi ;\ + dst=$${src##*/} ;\ + echo "Found $$dst" ;\ + if test "$$dst" -nt Makefile; then continue; fi ;\ + echo "Staging $$dst for $$p" ;\ + cp "$$src" "$$dst" ;\ + done ;\ + : + +__installer_swi_files: +ifndef NO_SWI + $(ONL_V_GEN): ;\ + set -e ;\ + if $(ONL_V_P); then set -x; fi ;\ + swidir=$$(mktemp -d $(PWD)/swi-d-XXXXXX) ;\ + $(ONLPM) --extract-dir onl-swi:$(ARCH) $$swidir ;\ + mv $$swidir/usr/share/onl/packages/$(ARCH)/onl-swi/*.swi . ;\ + rm -fr $$swidir ;\ + : +else + $(ONL_V_GEN): +endif + +shar installer: installer + +clean: + rm -f *.swi *.installer *.cpio.gz + diff --git a/builds/powerpc/installer/new-hotness/builds/Makefile b/builds/powerpc/installer/new-hotness/builds/Makefile index 5b24ae41..e94db6bd 100644 --- a/builds/powerpc/installer/new-hotness/builds/Makefile +++ b/builds/powerpc/installer/new-hotness/builds/Makefile @@ -1,109 +1,2 @@ include $(ONL)/make/config.powerpc.mk - -ONLPLATFORM = python $(ONL)/tools/onlplatform.py -PLATFORMS := $(shell $(ONLPM) --platform-manifest onl-loader-initrd:$(ARCH)) - -MKSHAR = $(ONL)/tools/mkshar -MKSHAR_OPTS = --lazy --unzip-pad --fixup-perms autoperms.sh -MKSHAR_PERMS = autoperms.sh - -VONLDIR = $(ONL)/packages/base/all/vendor-config-onl -PYFIT = $(VONLDIR)/src/bin/pyfit -PYFIT_ENVIRONMENT = PYTHONPATH=$(VONLDIR)/src/python - -# Hardcoded to match ONL File naming conventions. -include $(ONL)/make/version-onl.mk -INSTALLER_NAME=$(FNAME_PRODUCT_VERSION)_ONL-OS_$(FNAME_BUILD_ID)_$(UARCH)_INSTALLER - -# default fit image can be used as the canonical location for the initrd -FIT_IMAGE_ALL := $(shell $(ONLPM) --find-file onl-loader-fit:$(ARCH) onl-loader-fit.itb) -INITRD := $(shell $(ONLPM) --find-file onl-loader-initrd:$(ARCH) onl-loader-initrd-$(ARCH).cpio.gz) -INITRD_BOUNDS := $(shell $(PYFIT_ENVIRONMENT) $(PYFIT) -v offset $(FIT_IMAGE_ALL) --initrd) - -__installer: installer.sh __installer_fit_files __installer_platform_files __installer_swi_files - $(ONL_V_at)rm -rf *INSTALLER* *.md5sum - $(ONL_V_at)cp /dev/null $(MKSHAR_PERMS) - $(ONL_V_at)cp $(ONL)/make/version-onl.sh . - $(ONL_V_at)echo "#!/bin/sh" >> $(MKSHAR_PERMS) - $(ONL_V_at)echo "set -e" >> $(MKSHAR_PERMS) - $(ONL_V_at)echo "set -x" >> $(MKSHAR_PERMS) - $(MKSHAR) $(MKSHAR_OPTS) "$(INSTALLER_NAME)" $(ONL)/tools/scripts/sfx.sh.in installer.sh *.swi *.itb version-onl.sh boot-config - $(ONL_V_at)rm -rf installer.sh *.itb *.swi version-onl.sh autoperms.sh - md5sum "$(INSTALLER_NAME)" | awk '{ print $$1 }' > "$(INSTALLER_NAME).md5sum" - -installer.sh: Makefile $(ONL)/builds/any/installer/new-hotness/installer.sh.in - $(ONL_V_GEN)cp /dev/null $@ - $(ONL_V_at): ;\ - set -e ;\ - if $(ONL_V_P); then set -x; fi ;\ - if test "$(INITRD_BOUNDS)"; then \ - a="$(FIT_IMAGE_ALL)"; a=$${a##*/} ;\ - else \ - a="$(INITRD)"; i=$${a##*/} ;\ - fi ;\ - set dummy $(INITRD_BOUNDS); start=$$2; end=$$3; sz=$$(($$end - $$start + 1)) ;\ - sed \ - -e 's^@ONLVERSION@^$(VERSION_STRING)^g' \ - -e "s^@INITRD_ARCHIVE@^$${a}^g" \ - -e "s^@INITRD_OFFSET@^$$start^g" \ - -e "s^@INITRD_SIZE@^$$sz^g" \ - -e 's^@ARCH@^ppc^g' \ - $(ONL)/builds/any/installer/new-hotness/installer.sh.in \ - >> $@ - $(ONL_V_at)echo "PAYLOAD_FOLLOWS" >> $@ - -__installer_fit_files: - $(ONL_V_GEN): ;\ - set -e ;\ - if $(ONL_V_P); then set -x; fi ;\ - src=$(FIT_IMAGE_ALL) ;\ - dst=$${src##*/} ;\ - if test "$$dst" -nt Makefile; then \ - : ;\ - else \ - echo "Staging $$dst" ;\ - cp $$src $$dst ;\ - fi ;\ - : - -############################## -# -# optionally include custom itb files for each platform -# -############################## - -__installer_platform_files: - $(ONL_V_GEN): ;\ - set -e ;\ - if $(ONL_V_P); then set -x; fi ;\ - l="$(PLATFORMS)"; for p in $$l; do \ - echo "Looking for an ITB specific to $$p, ignore errors..." ;\ - src=$$($(ONLPLATFORM) $$p $(ARCH) itb) 2>/dev/null || : ;\ - if test "$$src"; then :; else continue; fi ;\ - dst=$${src##*/} ;\ - echo "Found $$dst" ;\ - if test "$$dst" -nt Makefile; then continue; fi ;\ - echo "Staging $$dst for $$p" ;\ - cp "$$src" "$$dst" ;\ - done ;\ - : - -__installer_swi_files: -ifndef NO_SWI - $(ONL_V_GEN): ;\ - set -e ;\ - if $(ONL_V_P); then set -x; fi ;\ - swidir=$$(mktemp -d $(PWD)/swi-d-XXXXXX) ;\ - $(ONLPM) --extract-dir onl-swi:$(ARCH) $$swidir ;\ - mv $$swidir/usr/share/onl/packages/$(ARCH)/onl-swi/*.swi . ;\ - rm -fr $$swidir ;\ - : -else - $(ONL_V_GEN): -endif - -shar installer: installer - -clean: - rm -f *.swi *.installer *.cpio.gz - +include $(ONL)/builds/any/installer/new-hotness/uboot/builds/Makefile From 227a61b210f324364dc536416259783367083f87 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Mon, 9 May 2016 12:00:55 -0700 Subject: [PATCH 035/113] Clean up arch handling for ppc and arm --- .../any/installer/new-hotness/installer.sh.in | 30 ++++++++++++------- .../new-hotness/uboot/builds/Makefile | 4 +-- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/builds/any/installer/new-hotness/installer.sh.in b/builds/any/installer/new-hotness/installer.sh.in index 6cc81460..6a715a62 100644 --- a/builds/any/installer/new-hotness/installer.sh.in +++ b/builds/any/installer/new-hotness/installer.sh.in @@ -25,17 +25,25 @@ IARCH="@ARCH@" ARCH=`uname -m` if test "$ARCH" != "$IARCH"; then - echo - echo "------------------------------------" - echo "Installer Architecture: $IARCH" - echo "Target Architecture: $ARCH" - echo - echo "This installer cannot be used on this" - echo "target." - echo - echo "------------------------------------" - sleep 5 - exit 1 + : +else + # identify mappings between kernel arch and debian arch + case "$IARCH:$ARCH" in + armel:arm7l) ;; + *) + echo + echo "------------------------------------" + echo "Installer Architecture: $IARCH" + echo "Target Architecture: $ARCH" + echo + echo "This installer cannot be used on this" + echo "target." + echo + echo "------------------------------------" + sleep 5 + exit 1 + ;; + esac fi case "$ARCH" in ppc|powerpc) diff --git a/builds/any/installer/new-hotness/uboot/builds/Makefile b/builds/any/installer/new-hotness/uboot/builds/Makefile index 4755bf30..ebd2248e 100644 --- a/builds/any/installer/new-hotness/uboot/builds/Makefile +++ b/builds/any/installer/new-hotness/uboot/builds/Makefile @@ -31,7 +31,7 @@ __installer: installer.sh __installer_fit_files __installer_platform_files __ins $(ONL_V_at)echo "set -x" >> $(MKSHAR_PERMS) $(MKSHAR) $(MKSHAR_OPTS) "$(INSTALLER_NAME)" $(ONL)/tools/scripts/sfx.sh.in installer.sh *.swi *.itb version-onl.sh boot-config $(ONL_V_at)rm -rf installer.sh *.itb *.swi version-onl.sh autoperms.sh - md5sum "$(INSTALLER_NAME)" | awk '{ print $$1 }' > "$(INSTALLER_NAME).md5sum" + $(ONL_V_at)md5sum "$(INSTALLER_NAME)" | awk '{ print $$1 }' > "$(INSTALLER_NAME).md5sum" installer.sh: Makefile $(ONL)/builds/any/installer/new-hotness/installer.sh.in $(ONL_V_GEN)cp /dev/null $@ @@ -49,7 +49,7 @@ installer.sh: Makefile $(ONL)/builds/any/installer/new-hotness/installer.sh.in -e "s^@INITRD_ARCHIVE@^$${a}^g" \ -e "s^@INITRD_OFFSET@^$$start^g" \ -e "s^@INITRD_SIZE@^$$sz^g" \ - -e 's^@ARCH@^ppc^g' \ + -e 's^@ARCH@^$(ARCH)^g' \ $(ONL)/builds/any/installer/new-hotness/installer.sh.in \ >> $@ $(ONL_V_at)echo "PAYLOAD_FOLLOWS" >> $@ From b6e07b5bf7dac214366c0523b9ae192a945e6973 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Mon, 9 May 2016 12:04:37 -0700 Subject: [PATCH 036/113] Added armel installer --- builds/armel/installer/new-hotness/Makefile | 1 + builds/armel/installer/new-hotness/PKG.yml | 2 ++ builds/armel/installer/new-hotness/builds/.gitignore | 1 + builds/armel/installer/new-hotness/builds/Makefile | 2 ++ builds/armel/installer/new-hotness/builds/boot-config | 4 ++++ 5 files changed, 10 insertions(+) create mode 100644 builds/armel/installer/new-hotness/Makefile create mode 100644 builds/armel/installer/new-hotness/PKG.yml create mode 100644 builds/armel/installer/new-hotness/builds/.gitignore create mode 100644 builds/armel/installer/new-hotness/builds/Makefile create mode 100644 builds/armel/installer/new-hotness/builds/boot-config diff --git a/builds/armel/installer/new-hotness/Makefile b/builds/armel/installer/new-hotness/Makefile new file mode 100644 index 00000000..003238cf --- /dev/null +++ b/builds/armel/installer/new-hotness/Makefile @@ -0,0 +1 @@ +include $(ONL)/make/pkg.mk \ No newline at end of file diff --git a/builds/armel/installer/new-hotness/PKG.yml b/builds/armel/installer/new-hotness/PKG.yml new file mode 100644 index 00000000..8cf5ff66 --- /dev/null +++ b/builds/armel/installer/new-hotness/PKG.yml @@ -0,0 +1,2 @@ +!include $ONL/builds/any/installer/new-hotness/APKG.yml ARCH=armel + diff --git a/builds/armel/installer/new-hotness/builds/.gitignore b/builds/armel/installer/new-hotness/builds/.gitignore new file mode 100644 index 00000000..fbd18542 --- /dev/null +++ b/builds/armel/installer/new-hotness/builds/.gitignore @@ -0,0 +1 @@ +*INSTALLER diff --git a/builds/armel/installer/new-hotness/builds/Makefile b/builds/armel/installer/new-hotness/builds/Makefile new file mode 100644 index 00000000..e2eb47a8 --- /dev/null +++ b/builds/armel/installer/new-hotness/builds/Makefile @@ -0,0 +1,2 @@ +include $(ONL)/make/config.armel.mk +include $(ONL)/builds/any/installer/new-hotness/uboot/builds/Makefile diff --git a/builds/armel/installer/new-hotness/builds/boot-config b/builds/armel/installer/new-hotness/builds/boot-config new file mode 100644 index 00000000..40fb0d31 --- /dev/null +++ b/builds/armel/installer/new-hotness/builds/boot-config @@ -0,0 +1,4 @@ +NETDEV=ma1 +NETAUTO=dhcp +BOOTMODE=SWI +SWI=images::latest From bbd3184661d4fd81801298e495b229d77aa55ab7 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Mon, 9 May 2016 13:29:09 -0700 Subject: [PATCH 037/113] Added bzip2 and xz for unpacking ONIE images --- builds/any/rootfs/jessie/common/common-packages.yml | 2 ++ builds/any/rootfs/wheezy/common/common-packages.yml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/builds/any/rootfs/jessie/common/common-packages.yml b/builds/any/rootfs/jessie/common/common-packages.yml index 980a86b1..ec1d992c 100644 --- a/builds/any/rootfs/jessie/common/common-packages.yml +++ b/builds/any/rootfs/jessie/common/common-packages.yml @@ -72,3 +72,5 @@ - oom-shim - python-parted - python-yaml +- bzip2 +- xz-utils diff --git a/builds/any/rootfs/wheezy/common/common-packages.yml b/builds/any/rootfs/wheezy/common/common-packages.yml index b93183b1..7f29ba09 100644 --- a/builds/any/rootfs/wheezy/common/common-packages.yml +++ b/builds/any/rootfs/wheezy/common/common-packages.yml @@ -71,3 +71,5 @@ - oom-shim - python-parted - python-yaml +- bzip2 +- xz-utils From 0596237d1305ab0ebe5c9012e3b13cfd7cf56939 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Tue, 10 May 2016 12:01:39 -0700 Subject: [PATCH 038/113] Added unzip --- builds/any/rootfs/jessie/common/common-packages.yml | 1 + builds/any/rootfs/wheezy/common/common-packages.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/builds/any/rootfs/jessie/common/common-packages.yml b/builds/any/rootfs/jessie/common/common-packages.yml index ec1d992c..62f64b8e 100644 --- a/builds/any/rootfs/jessie/common/common-packages.yml +++ b/builds/any/rootfs/jessie/common/common-packages.yml @@ -74,3 +74,4 @@ - python-yaml - bzip2 - xz-utils +- unzip diff --git a/builds/any/rootfs/wheezy/common/common-packages.yml b/builds/any/rootfs/wheezy/common/common-packages.yml index 7f29ba09..193e002d 100644 --- a/builds/any/rootfs/wheezy/common/common-packages.yml +++ b/builds/any/rootfs/wheezy/common/common-packages.yml @@ -73,3 +73,4 @@ - python-yaml - bzip2 - xz-utils +- unzip From 51550a194e2a32fe448d8ad9fa8f7efd35d3cfa7 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Tue, 10 May 2016 12:02:45 -0700 Subject: [PATCH 039/113] Make sure onl directories are unmounted --- .../src/python/onl/install/BaseInstall.py | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/packages/base/all/vendor-config-onl/src/python/onl/install/BaseInstall.py b/packages/base/all/vendor-config-onl/src/python/onl/install/BaseInstall.py index d85c1a8c..895a0876 100644 --- a/packages/base/all/vendor-config-onl/src/python/onl/install/BaseInstall.py +++ b/packages/base/all/vendor-config-onl/src/python/onl/install/BaseInstall.py @@ -12,7 +12,10 @@ import StringIO import parted import yaml -from InstallUtils import MountContext, BlkidParser, PartedParser, SubprocessMixin +from InstallUtils import SubprocessMixin +from InstallUtils import MountContext, BlkidParser, PartedParser +from InstallUtils import ProcMountsParser + import onl.YamlUtils class Base: @@ -280,6 +283,16 @@ class Base: return 0 + def assertUnmounted(self): + """Make sure the install device does not have any active mounts.""" + pm = ProcMountsParser() + for m in pm.mounts: + if m.device.startswith(self.device): + self.log.error("mount %s on %s will be erased by install", + m.dir, m.device) + return 1 + return 0 + GRUB_TPL = """\ #serial --port=0x3f8 --speed=115200 --word=8 --parity=no --stop=1 serial %(serial)s @@ -351,6 +364,9 @@ class GrubInstaller(SubprocessMixin, Base): self.log.error("cannot find an install device") return 1 + code = self.assertUnmounted() + if code: return code + # optionally back up a config partition # if it's on the boot device for part in self.blkidParts: @@ -530,6 +546,9 @@ class UbootInstaller(SubprocessMixin, Base): self.device = self.im.getDevice() + code = self.assertUnmounted() + if code: return code + self.rawLoaderDevice = None # set to a partition device for raw loader install, # default to None for FS-based install From c640ddb751f639f99d15e2c688067d1915de2c96 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Tue, 10 May 2016 12:02:56 -0700 Subject: [PATCH 040/113] Handle install from within ONL --- .../src/python/onl/install/App.py | 37 +++++++++++++++---- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/packages/base/all/vendor-config-onl/src/python/onl/install/App.py b/packages/base/all/vendor-config-onl/src/python/onl/install/App.py index 79884203..55630010 100644 --- a/packages/base/all/vendor-config-onl/src/python/onl/install/App.py +++ b/packages/base/all/vendor-config-onl/src/python/onl/install/App.py @@ -14,8 +14,6 @@ from InstallUtils import InitrdContext from InstallUtils import SubprocessMixin import ConfUtils, BaseInstall -import onl.platform.current - class App(SubprocessMixin): def __init__(self, log=None): @@ -33,7 +31,11 @@ class App(SubprocessMixin): def run(self): self.log.info("getting installer configuration") - self.machineConf = ConfUtils.MachineConf() + if os.path.exists(ConfUtils.MachineConf.PATH): + self.machineConf = ConfUtils.MachineConf() + else: + self.log.warn("missing /etc/machine.conf from ONIE runtime") + self.machineConf = ConfUtils.MachineConf(path='/dev/null') self.installerConf = ConfUtils.InstallerConf() ##self.log.info("using native GRUB") @@ -71,6 +73,15 @@ class App(SubprocessMixin): code = self.findPlatform() if code: return code + try: + import onl.platform.current + except: + self.log.exception("cannot find platform config") + code = 1 + if self.log.level < logging.INFO: + self.post_mortem() + if code: return code + self.onlPlatform = onl.platform.current.OnlPlatform() if 'grub' in self.onlPlatform.platform_config: @@ -111,11 +122,23 @@ class App(SubprocessMixin): def findPlatform(self): - plat = getattr(self.machineConf, 'onie_platform', None) - arch = getattr(self.machineConf, 'onie_arch', None) + plat = arch = None + if os.path.exists(ConfUtils.MachineConf.PATH): + plat = getattr(self.machineConf, 'onie_platform', None) + arch = getattr(self.machineConf, 'onie_arch', None) + if plat and arch: + self.log.info("ONL installer running under ONIE.") + plat = plat.replace('_', '-') + elif os.path.exists("/etc/onl/platform"): + with open("/etc/onl/platform") as fd: + plat = fd.read().strip() + if plat.startswith('x86-64'): + arch = 'x86_64' + else: + arch = plat.partition('-')[0] + self.log.info("ONL installer running under ONL or ONL loader.") + if plat and arch: - self.log.info("ONL installer running under ONIE.") - plat = plat.replace('_', '-') self.installerConf.installer_platform = plat self.installerConf.installer_arch = arch else: From 1f4a489421b8a88fe8757acb7e2538d226761512 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Tue, 10 May 2016 12:03:10 -0700 Subject: [PATCH 041/113] Better error reporting for missing tools --- .../src/python/onl/install/InstallUtils.py | 32 ++++++++++++------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/packages/base/all/vendor-config-onl/src/python/onl/install/InstallUtils.py b/packages/base/all/vendor-config-onl/src/python/onl/install/InstallUtils.py index 4b8f1760..f2e2232f 100644 --- a/packages/base/all/vendor-config-onl/src/python/onl/install/InstallUtils.py +++ b/packages/base/all/vendor-config-onl/src/python/onl/install/InstallUtils.py @@ -679,18 +679,26 @@ class InitrdContext(SubprocessMixin): c2 = ('cpio', '-imd',) self.log.debug("+ %s | %s", " ".join(c1), " ".join(c2)) - p1 = subprocess.Popen(c1, - stdout=subprocess.PIPE) - if self.log.isEnabledFor(logging.DEBUG): - p2 = subprocess.Popen(c2, - cwd=self.dir, - stdin=p1.stdout) - else: - p2 = subprocess.Popen(c2, - cwd=self.dir, - stdin=p1.stdout, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT) + try: + p1 = subprocess.Popen(c1, + stdout=subprocess.PIPE) + except OSError as ex: + self.log.exception("command not found: %s" % c1[0]) + raise ValueError("cannot start pipe") + try: + if self.log.isEnabledFor(logging.DEBUG): + p2 = subprocess.Popen(c2, + cwd=self.dir, + stdin=p1.stdout) + else: + p2 = subprocess.Popen(c2, + cwd=self.dir, + stdin=p1.stdout, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + except OSError as ex: + self.log.exception("cannot start command: %s" % c2[0]) + raise ValueError("cannot start pipe") c1 = p1.wait() out, _ = p2.communicate() c2 = p2.wait() From e63baed466987aa04e18cb48515100664f7c73cc Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Tue, 10 May 2016 12:04:03 -0700 Subject: [PATCH 042/113] Overhaul tmpfs support - find a suitable TMPDIR that is actually tmpfs/ramfs - resize tmpfs/ramfs as needed - enable unzip overwrite mode --- .../any/installer/new-hotness/installer.sh.in | 167 ++++++++++++++++-- 1 file changed, 150 insertions(+), 17 deletions(-) diff --git a/builds/any/installer/new-hotness/installer.sh.in b/builds/any/installer/new-hotness/installer.sh.in index 6a715a62..ade269f9 100644 --- a/builds/any/installer/new-hotness/installer.sh.in +++ b/builds/any/installer/new-hotness/installer.sh.in @@ -85,14 +85,29 @@ esac ############################################################ set -e -cd $(dirname $0) installer_script=${0##*/} +installer_dir=${0%/*} +installer_dir=$(cd $installer_dir && pwd) installer_zip=$1 +installer_tmpfs= +installer_tmpfs_opts= +# installer_tmpfs=??*, installer_tmpfs_opts= --> temporary mount +# installer_tmpfs=??*, installer_tmpfs_opts=??* --> temporary remount + +installer_tmpfs_kmin=1048576 +# minimum tmpfs/ramfs size to run this installer +# (conservative, could be based on actual installer size) + BOOTDIR=/mnt/onie-boot # initial boot partition (onie) +CR=" +" + +cd $installer_dir + has_grub_env() { local tag @@ -136,12 +151,62 @@ if test -r /etc/machine.conf; then . /etc/machine.conf fi +visit_proc_mounts() { + local ifs line dummy fn rest sts + fn=$1; shift + rest="$@" + + ifs=$IFS; IFS=$CR + for line in $(cat /proc/mounts); do + IFS=$ifs + if eval $fn $line $rest; then + : + else + sts=$? + if test $sts -eq 2; then break; fi + return $sts + fi + done + IFS=$ifs + + return 0 +} + # # Installation environment setup. # installer_umount() { - egrep "/tmp/..*" /proc/mounts | cut -d' ' -f2 | sort -r | xargs -n 1 umount + local cwd mpt tdir + cwd=$PWD + cd / + + tdir=${TMPDIR-"/tmp"} + for mpt in $(cat /proc/mounts | cut -d' ' -f2 | sort -r); do + case "$mpt" in + "$tdir"|"$tdir"/*) umount "$mpt" ;; + esac + done + if test "$installer_tmpfs_opts"; then + case ",$installer_tmpfs_opts," in + *,size=*,*) ;; + *) + # default if unspecified is 50% of physical memory + installer_tmpfs_opts=${installer_tmpfs_opts},size=50% + ;; + esac + installer_say "Remounting $installer_tmpfs with options $installer_tmpfs_opts" + mount -o remount,$installer_tmpfs_opts $installer_tmpfs + installer_tmpfs= + fi + if test "$installer_tmpfs"; then + installer_say "Unmounting $installer_tmpfs" + umount "$installer_tmpfs" + fi + + cd $cwd || : + + return 0 } if test "${onie_platform}"; then @@ -194,23 +259,95 @@ fi trap "installer_cleanup" 0 1 -# -# Remount tmpfs larger if possible. -# We will be doing all of our work out of /tmp -# -mount -o remount,size=1024M /tmp || true +# Find a suitable location for TMPDIR + +scan_tmpfs() { + local dev mpt fstype opts tdir + dev=$1; shift + mpt=$1; shift + fstype=$1; shift + opts=$1; shift + shift + shift + tdir="$1" + + case "$fstype" in + ramfs|tmpfs) ;; + *) return 0 ;; + esac + + case "$tdir" in + "$mpt"|"$mpt"/*) + d1=$(stat -c '%D' "$tdir") + d2=$(stat -c '%D' $mpt) + if test "$d1" = "$d2"; then + installer_say "Found installer $fstype on $installer_dir ($mpt) using opts $opts" + installer_tmpfs=$mpt + installer_tmpfs_opts=${opts:-"defaults"} + return 2 + fi + ;; + esac + + return 0 +} + +# maybe installer script was unpacked to a tmpfs/ramfs filesystem +if test -z "$installer_tmpfs" -a "$installer_dir"; then + visit_proc_mounts scan_tmpfs "$installer_dir" + if test "$installer_tmpfs"; then + TMPDIR="$installer_dir" + export TMPDIR + fi +fi +# maybe TMPDIR is on a tmpfs/ramfs filesystem +if test -z "$installer_tmpfs" -a "$TMPDIR"; then + visit_proc_mounts scan_tmpfs "$TMPDIR" + if test "$installer_tmpfs"; then + : + else + installer_say "TMPDIR $TMPDIR is not actually tmpfs, ignoring" + unset TMPDIR + fi +fi +# else, hopefully /tmp is a tmpfs/ramfs +if test -z "$installer_tmpfs"; then + visit_proc_mounts scan_tmpfs /tmp + if test "$installer_tmpfs"; then + TMPDIR=/tmp + export TMPDIR + fi +fi + +if test "$installer_tmpfs"; then + set dummy $(df -k $installer_tmpfs | tail -1) + if test $3 -lt $installer_tmpfs_kmin; then + installer_say "Resizing tmpfs $installer_tmpfs to ${installer_tmpfs_kmin}k" + mount -o remount,size=${installer_tmpfs_kmin}k $installer_tmpfs + else + # existing installer_tmpfs is fine, + # no need to unmount or remount + installer_tmpfs= + installer_tmpfs_opts= + fi +else + installer_say "Creating tmpfs for installer" + installer_tmpfs=$(mktemp -d -t installer-tmpfs-XXXXXX) + installer_tmpfs_opts= + mount -t tmpfs -o size=1024m tmpfs $installer_tmpfs + export TMPDIR=$installer_tmpfs +fi # Unpack our distribution -installer_say "Unpacking SwitchLight installer files..." -installer_dir=`pwd` +installer_say "Unpacking ONL installer files..." if test "$SFX_PAD"; then # ha ha, busybox cannot exclude multiple files - unzip $installer_zip -x $SFX_PAD + unzip -o $installer_zip -x $SFX_PAD elif test "$SFX_UNZIP"; then - unzip $installer_zip -x $installer_script + unzip -o $installer_zip -x $installer_script else dd if=$installer_zip bs=$SFX_BLOCKSIZE skip=$SFX_BLOCKS \ - | unzip - -x $installer_script + | unzip -o - -x $installer_script fi # Developer debugging @@ -226,9 +363,6 @@ initrd_archive="@INITRD_ARCHIVE@" initrd_offset="@INITRD_OFFSET@" initrd_size="@INITRD_SIZE@" -TMPDIR=${TMPDIR-"${installer_dir}"} -export TMPDIR - rootdir=$(mktemp -d -t "initrd-XXXXXX") installer_say "Extracting initrd to $rootdir" if test "$initrd_offset"; then @@ -291,10 +425,9 @@ echo "installer_postinst=/mnt/installer/$b" >> "${rootdir}/etc/onl/installer.con # no special handling for /tmp or /run, since this is all in /tmp # anyway -installer_say "Launching Switch Light installer" +installer_say "Launching ONL installer" installer_shell=${installer_shell-"/usr/bin/onl-install"} chroot "${rootdir}" $installer_shell -: chroot "${rootdir}" /usr/bin/onl-install if test -f "$postinst"; then installer_say "Invoking post-install actions" From 7166dce5c6b9279bfeb19a8c04c861f35e6cfb7e Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Tue, 10 May 2016 18:25:20 -0700 Subject: [PATCH 043/113] Updated chroot utils - Set up /run properly - copy in /etc/onl files for self-update --- .../vendor-config-onl/src/lib/install/lib.sh | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/packages/base/all/vendor-config-onl/src/lib/install/lib.sh b/packages/base/all/vendor-config-onl/src/lib/install/lib.sh index 5537de43..78a5033b 100644 --- a/packages/base/all/vendor-config-onl/src/lib/install/lib.sh +++ b/packages/base/all/vendor-config-onl/src/lib/install/lib.sh @@ -74,6 +74,28 @@ installer_mkchroot() { done mkdir -p "${rootdir}/dev/pts" + installer_say "Setting up /run" + rm -fr "${rootdir}/run"/* + mkdir -p "${rootdir}/run" + d1=$(stat -c "%D" /run) + for rdir in /run/*; do + if test -d "$rdir"; then + mkdir "${rootdir}${rdir}" + d2=$(stat -c "%D" $rdir) + t2=$(stat -f -c "%T" $rdir) + case "$t2" in + tmpfs|ramfs) + # skip tmpfs, we'll just inherit the initrd ramfs + ;; + *) + if test "$d1" != "$d2"; then + mount -o bind $rdir "${rootdir}${rdir}" + fi + ;; + esac + fi + done + installer_say "Setting up mounts" mount -t proc proc "${rootdir}/proc" mount -t sysfs sysfs "${rootdir}/sys" @@ -89,6 +111,12 @@ installer_mkchroot() { cp /etc/machine.conf "${rootdir}/etc/machine.conf" fi + # export ONL defines to the installer + mkdir -p "${rootdir}/etc/onl" + if test -d /etc/onl; then + cp -a /etc/onl/. "${rootdir}/etc/onl/." + fi + # export firmware config if test -r /etc/fw_env.config; then cp /etc/fw_env.config "${rootdir}/etc/fw_env.config" From d7d53cdedd102c93aa430473ccb399f311632ab1 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Tue, 10 May 2016 18:27:01 -0700 Subject: [PATCH 044/113] Installer script overhaul - support lazy unzip within python installer - properly locate or create a tmpfs for expanding the installer - properly resize the tmpfs (and restore it) - export the installer zip file to the install routines --- .../any/installer/new-hotness/installer.sh.in | 88 +++++++++++++------ 1 file changed, 62 insertions(+), 26 deletions(-) diff --git a/builds/any/installer/new-hotness/installer.sh.in b/builds/any/installer/new-hotness/installer.sh.in index ade269f9..b7ada262 100644 --- a/builds/any/installer/new-hotness/installer.sh.in +++ b/builds/any/installer/new-hotness/installer.sh.in @@ -103,6 +103,12 @@ installer_tmpfs_kmin=1048576 BOOTDIR=/mnt/onie-boot # initial boot partition (onie) +# Replaced during build packaging with the current version. +onl_version="@ONLVERSION@" +initrd_archive="@INITRD_ARCHIVE@" +initrd_offset="@INITRD_OFFSET@" +initrd_size="@INITRD_SIZE@" + CR=" " @@ -184,24 +190,41 @@ installer_umount() { tdir=${TMPDIR-"/tmp"} for mpt in $(cat /proc/mounts | cut -d' ' -f2 | sort -r); do case "$mpt" in - "$tdir"|"$tdir"/*) umount "$mpt" ;; - esac - done - if test "$installer_tmpfs_opts"; then - case ",$installer_tmpfs_opts," in - *,size=*,*) ;; - *) - # default if unspecified is 50% of physical memory - installer_tmpfs_opts=${installer_tmpfs_opts},size=50% + "$tdir"|"$tdir"/*) + installer_say "Unmounting $mpt" + umount "$mpt" ;; esac - installer_say "Remounting $installer_tmpfs with options $installer_tmpfs_opts" - mount -o remount,$installer_tmpfs_opts $installer_tmpfs - installer_tmpfs= - fi + done + + # handle installer_tmpfs specially if test "$installer_tmpfs"; then - installer_say "Unmounting $installer_tmpfs" - umount "$installer_tmpfs" + if grep -q " $installer_tmpfs " /proc/mounts; then + + if test "$installer_tmpfs_opts"; then + + # remount if still mounted + + case ",$installer_tmpfs_opts," in + *,size=*,*) ;; + *) + # default if unspecified is 50% of physical memory + installer_tmpfs_opts=${installer_tmpfs_opts},size=50% + ;; + esac + installer_say "Remounting $installer_tmpfs with options $installer_tmpfs_opts" + mount -o remount,$installer_tmpfs_opts $installer_tmpfs + + else + + # else unmount if still mounted + + installer_say "Unmounting $installer_tmpfs" + umount "$installer_tmpfs" + + fi + + fi fi cd $cwd || : @@ -339,15 +362,21 @@ else fi # Unpack our distribution +if test "${installer_unpack_only}"; then + installer_list= +else + installer_list=$initrd_archive +fi + installer_say "Unpacking ONL installer files..." if test "$SFX_PAD"; then # ha ha, busybox cannot exclude multiple files - unzip -o $installer_zip -x $SFX_PAD + unzip -o $installer_zip $installer_list -x $SFX_PAD elif test "$SFX_UNZIP"; then - unzip -o $installer_zip -x $installer_script + unzip -o $installer_zip $installer_list -x $installer_script else dd if=$installer_zip bs=$SFX_BLOCKSIZE skip=$SFX_BLOCKS \ - | unzip -o - -x $installer_script + | unzip -o - $installer_list -x $installer_script fi # Developer debugging @@ -357,12 +386,6 @@ if test "${installer_unpack_only}"; then exit 1 fi -# Replaced during build packaging with the current version. -onl_version="@ONLVERSION@" -initrd_archive="@INITRD_ARCHIVE@" -initrd_offset="@INITRD_OFFSET@" -initrd_size="@INITRD_SIZE@" - rootdir=$(mktemp -d -t "initrd-XXXXXX") installer_say "Extracting initrd to $rootdir" if test "$initrd_offset"; then @@ -399,6 +422,19 @@ echo "onl_version=\"$onl_version\"" >> "${rootdir}/etc/onl/installer.conf" installer_md5=$(md5sum "$0" | awk '{print $1}') echo "installer_md5=\"$installer_md5\"" >> "${rootdir}/etc/onl/installer.conf" +# expose the zip file for later expansion by the initrd +case "$installer_zip" in + "${installer_dir}"/*) + echo "installer_zip=\"${installer_zip##*/}\"" >> "${rootdir}/etc/onl/installer.conf" + ;; + *) + zf=$(mktemp "$installer_dir/installer-zip-XXXXXX") + installer_say "Exposing installer archive as $zf" + mount -o bind "$installer_zip" $zf + echo "installer_zip=\"${zf##*/}\"" >> "${rootdir}/etc/onl/installer.conf" + ;; +esac + # Cache our install URL if available if test -f "$0.url"; then installer_url=$(cat "$0.url") @@ -416,8 +452,8 @@ fi postinst=$(mktemp -t postinst-XXXXXX) b=${postinst##*/} -echo "installer_chroot=${rootdir}" >> "${rootdir}/etc/onl/installer.conf" -echo "installer_postinst=/mnt/installer/$b" >> "${rootdir}/etc/onl/installer.conf" +echo "installer_chroot=\"${rootdir}\"" >> "${rootdir}/etc/onl/installer.conf" +echo "installer_postinst=\"/mnt/installer/$b\"" >> "${rootdir}/etc/onl/installer.conf" # for now, skip the other dot-files in /etc/onl, we do not need them # to enable initial install From 5e35ea9192993e126ac2a49fe7c5586f39a56239 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Tue, 10 May 2016 18:28:16 -0700 Subject: [PATCH 045/113] Installer updates - initial support for self-updating within ONL via a URL - lazy unpack support --- .../src/python/onl/install/App.py | 111 +++++++++++- .../src/python/onl/install/BaseInstall.py | 160 +++++++++++++----- 2 files changed, 220 insertions(+), 51 deletions(-) diff --git a/packages/base/all/vendor-config-onl/src/python/onl/install/App.py b/packages/base/all/vendor-config-onl/src/python/onl/install/App.py index 55630010..65968f4c 100644 --- a/packages/base/all/vendor-config-onl/src/python/onl/install/App.py +++ b/packages/base/all/vendor-config-onl/src/python/onl/install/App.py @@ -8,28 +8,110 @@ import sys, os import logging import imp import glob -import distutils.sysconfig +import argparse +import shutil +import urllib +import tempfile +import time from InstallUtils import InitrdContext from InstallUtils import SubprocessMixin +from InstallUtils import ProcMountsParser import ConfUtils, BaseInstall class App(SubprocessMixin): - def __init__(self, log=None): + def __init__(self, url=None, force=False, log=None): if log is not None: self.log = log else: self.log = logging.getLogger(self.__class__.__name__) + self.url = url + self.force = force + # remote-install mode + self.installer = None self.machineConf = None self.installerConf = None self.onlPlatform = None + # local-install mode + + self.nextUpdate = None def run(self): + if self.url is not None: + return self.runUrl() + else: + return self.runLocal() + + def runUrl(self): + pm = ProcMountsParser() + for m in pm.mounts: + if m.dir.startswith('/mnt/onl'): + if not self.force: + self.log.error("directory %s is still mounted", m.dir) + return 1 + self.log.warn("unmounting %s (--force)", m.dir) + self.check_call(('umount', m.dir,)) + + def reporthook(blocks, bsz, sz): + if time.time() < self.nextUpdate: return + self.nextUpdate = time.time() + 0.25 + if sz: + pct = blocks * bsz * 100 / sz + sys.stderr.write("downloaded %d%% ...\r" % pct) + else: + icon = "|/-\\"[blocks % 4] + sys.stderr.write("downloading ... %s\r" % icon) + + p = tempfile.mktemp(prefix="installer-", + suffix=".bin") + try: + self.log.info("downloading installer from %s --> %s", + self.url, p) + self.nextUpdate = 0 + if os.isatty(sys.stdout.fileno()): + dst, headers = urllib.urlretrieve(self.url, p, reporthook) + else: + dst, headers = urllib.urlretrieve(self.url, p) + sys.stdout.write("\n") + + self.log.debug("+ chmod +x %s", p) + os.chmod(p, 0755) + + env = {} + env.update(os.environ) + + if os.path.exists("/etc/onl/platform"): + self.log.debug("enabling unzip features for ONL") + env['SFX_UNZIP'] = '1' + self.log.debug("+ export SFX_UNZIP=1") + env['SFX_LOOP'] = '1' + self.log.debug("+ export SFX_LOOP=1") + env['SFX_PIPE'] = '1' + self.log.debug("+ export SFX_PIPE=1") + + self.log.debug("enabling in-place fixups") + env['SFX_INPLACE'] = '1' + self.log.debug("+ export SFX_INPLACE=1") + + self.log.info("invoking installer...") + try: + self.check_call((p,), env=env) + except subprocess.CalledProcessError as ex: + self.log.error("installer failed") + return ex.returncode + finally: + os.unlink(p) + + self.log.info("please reboot this system now.") + return 0 + + def runLocal(self): + self.log.info("getting installer configuration") if os.path.exists(ConfUtils.MachineConf.PATH): self.machineConf = ConfUtils.MachineConf() @@ -100,6 +182,7 @@ class App(SubprocessMixin): platformConf=self.onlPlatform.platform_config, grubEnv=self.grubEnv, ubootEnv=self.ubootEnv, + force=self.force, log=self.log) try: code = self.installer.run() @@ -230,17 +313,33 @@ class App(SubprocessMixin): logger.addHandler(hnd) logger.propagate = False - debug = 'installer_debug' in os.environ - if debug: + onie_verbose = 'onie_verbose' in os.environ + installer_debug = 'installer_debug' in os.environ + + ap = argparse.ArgumentParser() + ap.add_argument('-v', '--verbose', action='store_true', + default=onie_verbose, + help="Enable verbose logging") + ap.add_argument('-D', '--debug', action='store_true', + default=installer_debug, + help="Enable python debugging") + ap.add_argument('-U', '--url', type=str, + help="Install from a remote URL") + ap.add_argument('-F', '--force', action='store_true', + help="Unmount filesystems before install") + ops = ap.parse_args() + + if ops.verbose: logger.setLevel(logging.DEBUG) - app = cls(log=logger) + app = cls(url=ops.url, force=ops.force, + log=logger) try: code = app.run() except: logger.exception("runner failed") code = 1 - if debug: + if ops.debug: app.post_mortem() app.shutdown() diff --git a/packages/base/all/vendor-config-onl/src/python/onl/install/BaseInstall.py b/packages/base/all/vendor-config-onl/src/python/onl/install/BaseInstall.py index 895a0876..da4c62ab 100644 --- a/packages/base/all/vendor-config-onl/src/python/onl/install/BaseInstall.py +++ b/packages/base/all/vendor-config-onl/src/python/onl/install/BaseInstall.py @@ -11,6 +11,8 @@ import logging import StringIO import parted import yaml +import zipfile +import shutil from InstallUtils import SubprocessMixin from InstallUtils import MountContext, BlkidParser, PartedParser @@ -44,6 +46,7 @@ class Base: def __init__(self, machineConf=None, installerConf=None, platformConf=None, grubEnv=None, ubootEnv=None, + force=False, log=None): self.im = self.installmeta(installerConf=installerConf, machineConf=machineConf, @@ -52,6 +55,9 @@ class Base: ubootEnv = ubootEnv) self.log = log or logging.getLogger(self.__class__.__name__) + self.force = False + # unmount filesystems as needed + self.device = None # target device, initialize this later @@ -69,16 +75,65 @@ class Base: self.configArchive = None # backup of ONL-CONFIG during re-partitioning + self.zf = None + # zipfile handle to installer archive + def run(self): self.log.error("not implemented") return 1 def shutdown(self): - pass + zf, self.zf = self.zf, None + if zf: zf.close() + + def installerCopy(self, basename, dst, optional=False): + """Copy the file as-is, or get it from the installer zip.""" + + src = os.path.join(self.im.installerConf.installer_dir, basename) + if os.path.exists(src): + self.copy2(src, dst) + return + + if basename in self.zf.namelist(): + self.log.debug("+ unzip -p %s %s > %s", + self.im.installerConf.installer_zip, basename, dst) + with self.zf.open(basename, "r") as rfd: + with open(dst, "wb") as wfd: + shutil.copyfileobj(rfd, wfd) + return + + if not optional: + raise ValueError("missing installer file %s" % basename) + + def installerDd(self, basename, device): + + p = os.path.join(self.im.installerConf.installer_dir, basename) + if os.path.exists(p): + cmd = ('dd', + 'if=' + basename, + 'of=' + device,) + self.check_call(cmd, vmode=self.V2) + return + + if basename in self.zf.namelist(): + self.log.debug("+ unzip -p %s %s | dd of=%s", + self.im.installerConf.installer_zip, basename, device) + with self.zf.open(basename, "r") as rfd: + with open(device, "rb+") as wfd: + shutil.copyfileobj(rfd, wfd) + return + + raise ValueError("cannot find file %s" % basename) + + def installerExists(self, basename): + if basename in os.listdir(self.im.installerConf.installer_dir): return True + if basename in self.zf.namelist(): return True + return False def installSwi(self): - swis = [x for x in os.listdir(self.im.installerConf.installer_dir) if x.endswith('.swi')] + files = os.listdir(self.im.installerConf.installer_dir) + self.zf.namelist() + swis = [x for x in files if x.endswith('.swi')] if not swis: self.log.info("No ONL Software Image available for installation.") self.log.info("Post-install ZTN installation will be required.") @@ -88,13 +143,12 @@ class Base: return base = swis[0] - src = os.path.join(self.im.installerConf.installer_dir, base) self.log.info("Installing ONL Software Image (%s)...", base) dev = self.blkidParts['ONL-IMAGES'] with MountContext(dev.device, log=self.log) as ctx: dst = os.path.join(ctx.dir, base) - self.copy2(src, dst) + self.installerCopy(base, dst) return 0 @@ -268,18 +322,18 @@ class Base: self.log.info("Installing boot-config to %s", dev.device) - src = os.path.join(self.im.installerConf.installer_dir, 'boot-config') - ##src = os.path.join(self.im.installerConf.installer_platform_dir, 'boot-config') + basename = 'boot-config' with MountContext(dev.device, log=self.log) as ctx: - dst = os.path.join(ctx.dir, 'boot-config') - self.copy2(src, dst) + dst = os.path.join(ctx.dir, basename) + self.installerCopy(basename, dst) + with open(dst) as fd: + buf = fd.read() - with open(src) as fd: - ecf = fd.read().encode('base64', 'strict').strip() - if self.im.grub and self.im.grubEnv is not None: - setattr(self.im.grubEnv, 'boot_config_default', ecf) - if self.im.uboot and self.im.ubootEnv is not None: - setattr(self.im.ubootEnv, 'boot-config-default', ecf) + ecf = buf.encode('base64', 'strict').strip() + if self.im.grub and self.im.grubEnv is not None: + setattr(self.im.grubEnv, 'boot_config_default', ecf) + if self.im.uboot and self.im.ubootEnv is not None: + setattr(self.im.ubootEnv, 'boot-config-default', ecf) return 0 @@ -288,9 +342,19 @@ class Base: pm = ProcMountsParser() for m in pm.mounts: if m.device.startswith(self.device): - self.log.error("mount %s on %s will be erased by install", - m.dir, m.device) - return 1 + if not self.force: + self.log.error("mount %s on %s will be erased by install", + m.dir, m.device) + return 1 + else: + self.log.warn("unmounting %s from %s (--force)", + m.dir, m.device) + try: + self.check_call(('umount', m.dir,)) + except subprocess.CalledProcessError: + self.log.error("cannot unmount") + return 1 + return 0 GRUB_TPL = """\ @@ -426,14 +490,15 @@ class GrubInstaller(SubprocessMixin, Base): self.log.info("Installing kernel") dev = self.blkidParts['ONL-BOOT'] + + files = set(os.listdir(self.im.installerConf.installer_dir) + self.zf.namelist()) + files = [b for b in files if b.startswith('kernel-') or b.startswith('onl-loader-initrd-')] + with MountContext(dev.device, log=self.log) as ctx: def _cp(b): - src = os.path.join(self.im.installerConf.installer_dir, b) - if not os.path.isfile(src): return - if b.startswith('kernel-') or b.startswith('onl-loader-initrd-'): - dst = os.path.join(ctx.dir, b) - self.copy2(src, dst) - [_cp(e) for e in os.listdir(self.im.installerConf.installer_dir)] + dst = os.path.join(ctx.dir, b) + self.installerCopy(b, dst, optional=True) + [_cp(e) for e in files] d = os.path.join(ctx.dir, "grub") self.makedirs(d) @@ -485,6 +550,11 @@ class GrubInstaller(SubprocessMixin, Base): self.im.grubEnv.__dict__['bootPart'] = dev.device self.im.grubEnv.__dict__['bootDir'] = None + # get a handle to the installer zip + p = os.path.join(self.im.installerConf.installer_dir, + self.im.installerConf.installer_zip) + self.zf = zipfile.ZipFile(p) + code = self.installSwi() if code: return code @@ -513,7 +583,7 @@ class GrubInstaller(SubprocessMixin, Base): return self.installGpt() def shutdown(self): - pass + Base.shutdown(self) class UbootInstaller(SubprocessMixin, Base): @@ -598,42 +668,37 @@ class UbootInstaller(SubprocessMixin, Base): def installLoader(self): - loaderSrc = None c1 = self.im.platformConf['flat_image_tree'].get('itb', None) if type(c1) == dict: c1 = c1.get('=', None) c2 = ("%s.itb" % (self.im.installerConf.installer_platform,)) c3 = "onl-loader-fit.itb" - loaderSrc = None + loaderBasename = None for c in (c1, c2, c3): if c is None: continue - p = os.path.join(self.im.installerConf.installer_dir, c) - if os.path.exists(p): - loaderSrc = p + if self.installerExists(c): + loaderBasename = c break - if not loaderSrc: + if not loaderBasename: self.log.error("The platform loader file is missing.") return 1 - self.log.info("Installing the ONL loader from %s...", loaderSrc) + self.log.info("Installing the ONL loader from %s...", loaderBasename) if self.rawLoaderDevice is not None: self.log.info("Installing ONL loader %s --> %s...", - loaderSrc, self.rawLoaderDevice) - cmd = ('dd', - 'if=' + loaderSrc, - 'of=' + self.rawLoaderDevice,) - self.check_call(cmd, vmode=self.V2) - else: - dev = self.blkidParts['ONL-BOOT'] - basename = os.path.split(loaderSrc)[1] - self.log.info("Installing ONL loader %s --> %s:%s...", - loaderSrc, dev.device, basename) - with MountContext(dev.device, log=self.log) as ctx: - dst = os.path.join(ctx.dir, basename) - self.copy2(loaderSrc, dst) + loaderBasename, self.rawLoaderDevice) + self.installerDd(loaderBasename, self.rawLoaderDevice) + return 0 + + dev = self.blkidParts['ONL-BOOT'] + self.log.info("Installing ONL loader %s --> %s:%s...", + loaderBasename, dev.device, loaderBasename) + with MountContext(dev.device, log=self.log) as ctx: + dst = os.path.join(ctx.dir, loaderBasename) + self.installerCopy(loaderBasename, dst) return 0 @@ -713,6 +778,11 @@ class UbootInstaller(SubprocessMixin, Base): self.rawLoaderDevice = self.device + str(partIdx+1) break + # get a handle to the installer zip + p = os.path.join(self.im.installerConf.installer_dir, + self.im.installerConf.installer_zip) + self.zf = zipfile.ZipFile(p) + code = self.installSwi() if code: return code @@ -744,4 +814,4 @@ class UbootInstaller(SubprocessMixin, Base): return self.installUboot() def shutdown(self): - pass + Base.shutdown(self) From bb1c556cc4e502c9a3465d491a7368740d599a09 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Wed, 11 May 2016 13:47:32 -0700 Subject: [PATCH 046/113] Better error handling for failed connections Export debug and verbosity settings --- .../src/python/onl/install/App.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/packages/base/all/vendor-config-onl/src/python/onl/install/App.py b/packages/base/all/vendor-config-onl/src/python/onl/install/App.py index 65968f4c..ad98eb1a 100644 --- a/packages/base/all/vendor-config-onl/src/python/onl/install/App.py +++ b/packages/base/all/vendor-config-onl/src/python/onl/install/App.py @@ -21,7 +21,9 @@ import ConfUtils, BaseInstall class App(SubprocessMixin): - def __init__(self, url=None, force=False, log=None): + def __init__(self, url=None, + debug=False, force=False, + log=None): if log is not None: self.log = log @@ -30,6 +32,7 @@ class App(SubprocessMixin): self.url = url self.force = force + self.debug = debug # remote-install mode self.installer = None @@ -98,6 +101,15 @@ class App(SubprocessMixin): env['SFX_INPLACE'] = '1' self.log.debug("+ export SFX_INPLACE=1") + if self.debug: + self.log.debug("enabling installer debug") + env['installer_debug'] = 'y' + self.log.debug("+ export installer_debug=y") + if self.log.level < logging.INFO: + self.log.debug("enabling installer verbose logging") + env['installer_verbose'] = 'y' + self.log.debug("+ export installer_verbose=y") + self.log.info("invoking installer...") try: self.check_call((p,), env=env) @@ -105,7 +117,8 @@ class App(SubprocessMixin): self.log.error("installer failed") return ex.returncode finally: - os.unlink(p) + if os.path.exists(p): + os.unlink(p) self.log.info("please reboot this system now.") return 0 From d2c7fc536a0f6cc3744b150e269c88081eba2078 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Wed, 11 May 2016 13:49:50 -0700 Subject: [PATCH 047/113] Updates for loader-based and onl-based installs - allow some SFX settings to be overridden - refactor checksum validation - support --inplace padding fixups to economize on disk space --- tools/mkshar | 23 +++++++++++---- tools/scripts/sfx.sh.in | 62 +++++++++++++++++++++++------------------ 2 files changed, 52 insertions(+), 33 deletions(-) diff --git a/tools/mkshar b/tools/mkshar index 138f2755..fa63795a 100755 --- a/tools/mkshar +++ b/tools/mkshar @@ -36,6 +36,9 @@ parser.add_option('--unzip-loop', parser.add_option('--unzip-pad', action='store_true', help="Special pad options for deficient unzip") +parser.add_option('--inplace', + action='store_true', + help="Perform fixups in-place") parser.add_option('--fixup-perms', type=str, help="Post-unpack shell script to fix permissions") @@ -142,6 +145,10 @@ def _splice(tag, val): line = line + ('#' * llen) buf = buf[:p] + line + buf[q:] +def _spliceMaybe(tag, val): + val = "${%s-\"%s\"}" % (tag, val,) + _splice(tag, val) + logger.info("prepping SFX") _splice('SFX_BYTES', len(buf)) @@ -153,23 +160,27 @@ if opts.lazy: else: _splice('SFX_LAZY', '') if opts.unzip_sfx: - _splice('SFX_UNZIP', '1') + _spliceMaybe('SFX_UNZIP', '1') else: - _splice('SFX_UNZIP', '') + _spliceMaybe('SFX_UNZIP', '') if opts.unzip_pipe: - _splice('SFX_PIPE', '1') + _spliceMaybe('SFX_PIPE', '1') else: - _splice('SFX_PIPE', '') + _spliceMaybe('SFX_PIPE', '') if opts.unzip_loop: - _splice('SFX_LOOP', '1') + _spliceMaybe('SFX_LOOP', '1') else: - _splice('SFX_LOOP', '') + _spliceMaybe('SFX_LOOP', '') if opts.unzip_pad: _splice('SFX_PAD', 'pad.bin') else: _splice('SFX_PAD', '') if opts.fixup_perms: _splice('SFX_PERMS', opts.fixup_perms) +if opts.inplace: + _spliceMaybe('SFX_INPLACE', '1') +else: + _spliceMaybe('SFX_INPLACE', '') # remember the checksum offset ckStart = buf.find("SFX_CHECKSUM=") diff --git a/tools/scripts/sfx.sh.in b/tools/scripts/sfx.sh.in index bd1598bc..43d4463f 100644 --- a/tools/scripts/sfx.sh.in +++ b/tools/scripts/sfx.sh.in @@ -4,7 +4,7 @@ set -e CMD=${0##*/} -UNZIP=/usr/bin/unzip +UNZIP=${UNZIP-"/usr/bin/unzip"} UNZIPOPTS= UNZIPARGS= @@ -29,9 +29,10 @@ SFX_INSTALL=install ## internal script in the payload to run ################# SFX_PERMS= ## internal script to correct file permissions #################### SFX_PAD= ## pad file (this payload) to skip during unpack #################### SFX_LAZY= ## set to '1' to defer extraction to SFX_INSTALL ################## -SFX_UNZIP=1 ## set to '' if this unzip cannot parse SFX headers ############# -SFX_LOOP=1 ## set to '' if this unzip cannot read from a loopback/block #### -SFX_PIPE=1 ## set to '' if this unzip cannot read from a pipe ############## +SFX_UNZIP=1 ## set to '' if this unzip cannot parse SFX headers ############## +SFX_LOOP=1 ## set to '' if this unzip cannot read from a loopback/block ###### +SFX_PIPE=1 ## set to '' if this unzip cannot read from a pipe ################ +SFX_INPLACE= ## set to '1' if this zip file can be modified in place########## if test "$SFX_PAD"; then UNZIPARGS=$UNZIPARGS${UNZIPARGS:+" "}"-x $SFX_PAD" @@ -100,6 +101,23 @@ do_cleanup() } trap "do_cleanup" 0 1 +echo "$CMD: computing checksum of original archive" +{ + dd if="$SHARABS" bs=$SFX_BLOCKSIZE count=$SFX_BLOCKS 2>/dev/null | sed -e "/^SFX_CHECKSUM=/d"; + dd if="$SHARABS" bs=$SFX_BLOCKSIZE skip=$SFX_BLOCKS 2>/dev/null +} | md5sum > "$workdir/ck" + +set dummy `cat "$workdir/ck"` +newck=$2 +rm -f "$workdir/ck" + +if test "$SFX_CHECKSUM" = "$newck"; then + echo "$CMD: checksum is OK" +else + echo "$CMD: *** checksum mismatch" 1>&2 + exit 1 +fi + _t() { local c z @@ -144,11 +162,19 @@ case "$SFX_PAD:$SFX_UNZIP:$SFX_LOOP:$SFX_PIPE" in esac if test "$SFX_PAD"; then - echo "$CMD: copying file and resetting pad" - cp "$SHARABS" $workdir/onie-installer.zip - dd if="$SHARABS" of=$workdir/onie-installer.zip bs=512 skip=$(($SFX_BLOCKS-1)) count=1 conv=notrunc - _CAT=":" - _ZIP="$workdir/onie-installer.zip" + echo "$CMD: extracting pad" + dd if="$SHARABS" of=$workdir/zip.bin bs=512 skip=$(($SFX_BLOCKS-1)) count=1 + if test "$SFX_INPLACE"; then + _CAT=":" + _ZIP="$SHARABS" + else + echo "$CMD: copying file before resetting pad" + cp "$SHARABS" $workdir/onie-installer.zip + _CAT=":" + _ZIP="$workdir/onie-installer.zip" + fi + echo "$CMD: resetting pad" + dd if="$workdir/zip.bin" of="$_ZIP" bs=512 count=1 conv=notrunc elif test "$SFX_UNZIP"; then echo "$CMD: processing SFX with unzip" _CAT=":" @@ -209,24 +235,6 @@ case "$banner" in ;; esac -echo "$CMD: computing checksum" -{ - dd if="$SHARABS" bs=$SFX_BLOCKSIZE count=$SFX_BLOCKS 2>/dev/null | sed -e "/^SFX_CHECKSUM=/d"; - dd if="$SHARABS" bs=$SFX_BLOCKSIZE skip=$SFX_BLOCKS 2>/dev/null -} | md5sum > "$UNZIPDIR/ck" - -set dummy `cat "$UNZIPDIR/ck"` -newck=$2 - -rm -f "$UNZIPDIR/ck" - -if test "$SFX_CHECKSUM" = "$newck"; then - echo "$CMD: checksum is OK" -else - echo "$CMD: *** checksum mismatch" 1>&2 - exit 1 -fi - shardir=`dirname $0` shardir=`cd $shardir && pwd` From 2915cbb35be51f51eab0ffd493b2163188dd3444 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Wed, 11 May 2016 13:56:40 -0700 Subject: [PATCH 048/113] Minor tmpfs fixes - don't unmount /tmp - fix bind-mount target so chroot can see the installer file --- builds/any/installer/new-hotness/installer.sh.in | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/builds/any/installer/new-hotness/installer.sh.in b/builds/any/installer/new-hotness/installer.sh.in index b7ada262..050290bc 100644 --- a/builds/any/installer/new-hotness/installer.sh.in +++ b/builds/any/installer/new-hotness/installer.sh.in @@ -190,7 +190,7 @@ installer_umount() { tdir=${TMPDIR-"/tmp"} for mpt in $(cat /proc/mounts | cut -d' ' -f2 | sort -r); do case "$mpt" in - "$tdir"|"$tdir"/*) + "$tdir"/*) installer_say "Unmounting $mpt" umount "$mpt" ;; @@ -215,16 +215,18 @@ installer_umount() { installer_say "Remounting $installer_tmpfs with options $installer_tmpfs_opts" mount -o remount,$installer_tmpfs_opts $installer_tmpfs - else + elif test "$installer_tmpfs" != "/tmp"; then # else unmount if still mounted installer_say "Unmounting $installer_tmpfs" umount "$installer_tmpfs" + rmdir "$installer_tmpfs" fi fi + fi cd $cwd || : @@ -428,9 +430,9 @@ case "$installer_zip" in echo "installer_zip=\"${installer_zip##*/}\"" >> "${rootdir}/etc/onl/installer.conf" ;; *) - zf=$(mktemp "$installer_dir/installer-zip-XXXXXX") - installer_say "Exposing installer archive as $zf" - mount -o bind "$installer_zip" $zf + zf=$(mktemp "$rootdir/mnt/installer/installer-zip-XXXXXX") + installer_say "Exposing installer archive $installer_zip as $zf" + mount --bind "$installer_zip" $zf echo "installer_zip=\"${zf##*/}\"" >> "${rootdir}/etc/onl/installer.conf" ;; esac From 19a8e75036670bc6b60d4ba186571005adc6089a Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Wed, 11 May 2016 13:57:22 -0700 Subject: [PATCH 049/113] Optionally mount tmpfs within the loader - XXX DANGER @jnealtowns be advised --- .../base/all/initrds/loader-initrd-files/src/bin/sysinit | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/base/all/initrds/loader-initrd-files/src/bin/sysinit b/packages/base/all/initrds/loader-initrd-files/src/bin/sysinit index 6c255b85..f859a4a6 100755 --- a/packages/base/all/initrds/loader-initrd-files/src/bin/sysinit +++ b/packages/base/all/initrds/loader-initrd-files/src/bin/sysinit @@ -36,7 +36,12 @@ trap "restoreconsole; reboot -f" EXIT mount -t proc proc /proc mount -t sysfs sysfs /sys mount -o remount,size=1M /dev - +case "$(stat -f -c "%T" /tmp)" in + tmpfs|ramfs) ;; + *) + mount -t tmpfs tmpfs /tmp + ;; +esac # Grab cmdline settings From bac2e2cdc191f9cc25360f111c94514b637ca97a Mon Sep 17 00:00:00 2001 From: Steven Noble Date: Fri, 13 May 2016 05:17:07 +0000 Subject: [PATCH 050/113] updated 3.18 kernel to include AUFS and other options --- .../configs/x86_64-all/x86_64-all.config | 88 +- .../any/kernels/3.18.25/patches/aufs.patch | 33877 ++++++++++++++++ .../base/any/kernels/3.18.25/patches/series | 1 + 3 files changed, 33941 insertions(+), 25 deletions(-) create mode 100644 packages/base/any/kernels/3.18.25/patches/aufs.patch create mode 100644 packages/base/any/kernels/3.18.25/patches/series diff --git a/packages/base/any/kernels/3.18.25/configs/x86_64-all/x86_64-all.config b/packages/base/any/kernels/3.18.25/configs/x86_64-all/x86_64-all.config index 0f87091b..38eda785 100644 --- a/packages/base/any/kernels/3.18.25/configs/x86_64-all/x86_64-all.config +++ b/packages/base/any/kernels/3.18.25/configs/x86_64-all/x86_64-all.config @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/x86_64 3.18.25 Kernel Configuration +# Linux/x86 3.18.25 Kernel Configuration # CONFIG_64BIT=y CONFIG_X86_64=y @@ -772,10 +772,11 @@ CONFIG_BRIDGE_NETFILTER=y # Core Netfilter Configuration # CONFIG_NETFILTER_NETLINK=y -# CONFIG_NETFILTER_NETLINK_ACCT is not set +CONFIG_NETFILTER_NETLINK_ACCT=y CONFIG_NETFILTER_NETLINK_QUEUE=y CONFIG_NETFILTER_NETLINK_LOG=y CONFIG_NF_CONNTRACK=y +CONFIG_NF_LOG_COMMON=y CONFIG_NF_CONNTRACK_MARK=y CONFIG_NF_CONNTRACK_SECMARK=y CONFIG_NF_CONNTRACK_ZONES=y @@ -783,6 +784,7 @@ CONFIG_NF_CONNTRACK_PROCFS=y CONFIG_NF_CONNTRACK_EVENTS=y # CONFIG_NF_CONNTRACK_TIMEOUT is not set CONFIG_NF_CONNTRACK_TIMESTAMP=y +CONFIG_NF_CONNTRACK_LABELS=y CONFIG_NF_CT_PROTO_DCCP=y CONFIG_NF_CT_PROTO_GRE=y CONFIG_NF_CT_PROTO_SCTP=y @@ -799,8 +801,9 @@ CONFIG_NF_CONNTRACK_SANE=y CONFIG_NF_CONNTRACK_SIP=y CONFIG_NF_CONNTRACK_TFTP=y CONFIG_NF_CT_NETLINK=y -# CONFIG_NF_CT_NETLINK_TIMEOUT is not set -# CONFIG_NETFILTER_NETLINK_QUEUE_CT is not set +CONFIG_NF_CT_NETLINK_TIMEOUT=y +CONFIG_NF_CT_NETLINK_HELPER=y +CONFIG_NETFILTER_NETLINK_QUEUE_CT=y CONFIG_NF_NAT=y CONFIG_NF_NAT_NEEDED=y CONFIG_NF_NAT_PROTO_DCCP=y @@ -832,17 +835,17 @@ CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y CONFIG_NETFILTER_XT_TARGET_CT=y CONFIG_NETFILTER_XT_TARGET_DSCP=y CONFIG_NETFILTER_XT_TARGET_HL=y -# CONFIG_NETFILTER_XT_TARGET_HMARK is not set +CONFIG_NETFILTER_XT_TARGET_HMARK=y CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y -# CONFIG_NETFILTER_XT_TARGET_LOG is not set +CONFIG_NETFILTER_XT_TARGET_LOG=y CONFIG_NETFILTER_XT_TARGET_MARK=y CONFIG_NETFILTER_XT_NAT=y -# CONFIG_NETFILTER_XT_TARGET_NETMAP is not set +CONFIG_NETFILTER_XT_TARGET_NETMAP=y CONFIG_NETFILTER_XT_TARGET_NFLOG=y CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y CONFIG_NETFILTER_XT_TARGET_NOTRACK=y CONFIG_NETFILTER_XT_TARGET_RATEEST=y -# CONFIG_NETFILTER_XT_TARGET_REDIRECT is not set +CONFIG_NETFILTER_XT_TARGET_REDIRECT=y CONFIG_NETFILTER_XT_TARGET_TEE=y CONFIG_NETFILTER_XT_TARGET_TPROXY=y CONFIG_NETFILTER_XT_TARGET_TRACE=y @@ -854,12 +857,12 @@ CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=y # Xtables matches # CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=y -# CONFIG_NETFILTER_XT_MATCH_BPF is not set -# CONFIG_NETFILTER_XT_MATCH_CGROUP is not set +CONFIG_NETFILTER_XT_MATCH_BPF=y +CONFIG_NETFILTER_XT_MATCH_CGROUP=y CONFIG_NETFILTER_XT_MATCH_CLUSTER=y CONFIG_NETFILTER_XT_MATCH_COMMENT=y CONFIG_NETFILTER_XT_MATCH_CONNBYTES=y -# CONFIG_NETFILTER_XT_MATCH_CONNLABEL is not set +CONFIG_NETFILTER_XT_MATCH_CONNLABEL=y CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y CONFIG_NETFILTER_XT_MATCH_CONNMARK=y CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y @@ -872,20 +875,20 @@ CONFIG_NETFILTER_XT_MATCH_ESP=y CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y CONFIG_NETFILTER_XT_MATCH_HELPER=y CONFIG_NETFILTER_XT_MATCH_HL=y -# CONFIG_NETFILTER_XT_MATCH_IPCOMP is not set +CONFIG_NETFILTER_XT_MATCH_IPCOMP=y CONFIG_NETFILTER_XT_MATCH_IPRANGE=y CONFIG_NETFILTER_XT_MATCH_IPVS=y -# CONFIG_NETFILTER_XT_MATCH_L2TP is not set +CONFIG_NETFILTER_XT_MATCH_L2TP=y CONFIG_NETFILTER_XT_MATCH_LENGTH=y CONFIG_NETFILTER_XT_MATCH_LIMIT=y CONFIG_NETFILTER_XT_MATCH_MAC=y CONFIG_NETFILTER_XT_MATCH_MARK=y CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y -# CONFIG_NETFILTER_XT_MATCH_NFACCT is not set +CONFIG_NETFILTER_XT_MATCH_NFACCT=y CONFIG_NETFILTER_XT_MATCH_OSF=y CONFIG_NETFILTER_XT_MATCH_OWNER=y CONFIG_NETFILTER_XT_MATCH_POLICY=y -# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set +CONFIG_NETFILTER_XT_MATCH_PHYSDEV=y CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y CONFIG_NETFILTER_XT_MATCH_QUOTA=y CONFIG_NETFILTER_XT_MATCH_RATEEST=y @@ -965,7 +968,7 @@ CONFIG_NF_DEFRAG_IPV4=y CONFIG_NF_CONNTRACK_IPV4=y CONFIG_NF_CONNTRACK_PROC_COMPAT=y # CONFIG_NF_LOG_ARP is not set -# CONFIG_NF_LOG_IPV4 is not set +CONFIG_NF_LOG_IPV4=y CONFIG_NF_REJECT_IPV4=y CONFIG_NF_NAT_IPV4=y CONFIG_NF_NAT_MASQUERADE_IPV4=y @@ -1000,7 +1003,7 @@ CONFIG_IP_NF_ARP_MANGLE=y CONFIG_NF_DEFRAG_IPV6=y CONFIG_NF_CONNTRACK_IPV6=y CONFIG_NF_REJECT_IPV6=y -# CONFIG_NF_LOG_IPV6 is not set +CONFIG_NF_LOG_IPV6=y # CONFIG_NF_NAT_IPV6 is not set CONFIG_IP6_NF_IPTABLES=y CONFIG_IP6_NF_MATCH_AH=y @@ -1019,7 +1022,27 @@ CONFIG_IP6_NF_TARGET_REJECT=y CONFIG_IP6_NF_MANGLE=y CONFIG_IP6_NF_RAW=y # CONFIG_IP6_NF_NAT is not set -# CONFIG_BRIDGE_NF_EBTABLES is not set +CONFIG_BRIDGE_NF_EBTABLES=y +CONFIG_BRIDGE_EBT_BROUTE=y +CONFIG_BRIDGE_EBT_T_FILTER=y +CONFIG_BRIDGE_EBT_T_NAT=y +CONFIG_BRIDGE_EBT_802_3=y +CONFIG_BRIDGE_EBT_AMONG=y +CONFIG_BRIDGE_EBT_ARP=y +CONFIG_BRIDGE_EBT_IP=y +CONFIG_BRIDGE_EBT_IP6=y +CONFIG_BRIDGE_EBT_LIMIT=y +CONFIG_BRIDGE_EBT_MARK=y +CONFIG_BRIDGE_EBT_PKTTYPE=y +CONFIG_BRIDGE_EBT_STP=y +CONFIG_BRIDGE_EBT_VLAN=y +CONFIG_BRIDGE_EBT_ARPREPLY=y +CONFIG_BRIDGE_EBT_DNAT=y +CONFIG_BRIDGE_EBT_MARK_T=y +CONFIG_BRIDGE_EBT_REDIRECT=y +CONFIG_BRIDGE_EBT_SNAT=y +CONFIG_BRIDGE_EBT_LOG=y +CONFIG_BRIDGE_EBT_NFLOG=y # CONFIG_IP_DCCP is not set CONFIG_IP_SCTP=y # CONFIG_SCTP_DBG_OBJCNT is not set @@ -1035,14 +1058,14 @@ CONFIG_SCTP_COOKIE_HMAC_MD5=y CONFIG_STP=y CONFIG_BRIDGE=y CONFIG_BRIDGE_IGMP_SNOOPING=y -# CONFIG_BRIDGE_VLAN_FILTERING is not set +CONFIG_BRIDGE_VLAN_FILTERING=y CONFIG_HAVE_NET_DSA=y CONFIG_VLAN_8021Q=y # CONFIG_VLAN_8021Q_GVRP is not set # CONFIG_VLAN_8021Q_MVRP is not set # CONFIG_DECNET is not set CONFIG_LLC=y -# CONFIG_LLC2 is not set +CONFIG_LLC2=y # CONFIG_IPX is not set # CONFIG_ATALK is not set # CONFIG_X25 is not set @@ -1056,15 +1079,15 @@ CONFIG_DNS_RESOLVER=y # CONFIG_BATMAN_ADV is not set # CONFIG_OPENVSWITCH is not set # CONFIG_VSOCKETS is not set -# CONFIG_NETLINK_MMAP is not set -# CONFIG_NETLINK_DIAG is not set +CONFIG_NETLINK_MMAP=y +CONFIG_NETLINK_DIAG=y # CONFIG_NET_MPLS_GSO is not set # CONFIG_HSR is not set CONFIG_RPS=y CONFIG_RFS_ACCEL=y CONFIG_XPS=y # CONFIG_CGROUP_NET_PRIO is not set -# CONFIG_CGROUP_NET_CLASSID is not set +CONFIG_CGROUP_NET_CLASSID=y CONFIG_NET_RX_BUSY_POLL=y CONFIG_BQL=y # CONFIG_BPF_JIT is not set @@ -1173,7 +1196,7 @@ CONFIG_BLK_DEV_RAM_SIZE=65536 # # CONFIG_SENSORS_LIS3LV02D is not set # CONFIG_AD525X_DPOT is not set -# CONFIG_DUMMY_IRQ is not set +CONFIG_DUMMY_IRQ=y # CONFIG_IBM_ASM is not set # CONFIG_PHANTOM is not set # CONFIG_SGI_IOC4 is not set @@ -1486,7 +1509,7 @@ CONFIG_NETDEVICES=y CONFIG_MII=y CONFIG_NET_CORE=y # CONFIG_BONDING is not set -# CONFIG_DUMMY is not set +CONFIG_DUMMY=y # CONFIG_EQUALIZER is not set # CONFIG_NET_FC is not set # CONFIG_NET_TEAM is not set @@ -3007,6 +3030,21 @@ CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3 # CONFIG_UFS_FS is not set # CONFIG_EXOFS_FS is not set # CONFIG_F2FS_FS is not set +CONFIG_AUFS_FS=y +CONFIG_AUFS_BRANCH_MAX_127=y +# CONFIG_AUFS_BRANCH_MAX_511 is not set +# CONFIG_AUFS_BRANCH_MAX_1023 is not set +# CONFIG_AUFS_BRANCH_MAX_32767 is not set +CONFIG_AUFS_SBILIST=y +# CONFIG_AUFS_HNOTIFY is not set +# CONFIG_AUFS_EXPORT is not set +# CONFIG_AUFS_XATTR is not set +# CONFIG_AUFS_FHSM is not set +# CONFIG_AUFS_RDU is not set +# CONFIG_AUFS_SHWH is not set +# CONFIG_AUFS_BR_RAMFS is not set +CONFIG_AUFS_BDEV_LOOP=y +# CONFIG_AUFS_DEBUG is not set CONFIG_ORE=y CONFIG_NETWORK_FILESYSTEMS=y CONFIG_NFS_FS=y diff --git a/packages/base/any/kernels/3.18.25/patches/aufs.patch b/packages/base/any/kernels/3.18.25/patches/aufs.patch new file mode 100644 index 00000000..b0dd85d1 --- /dev/null +++ b/packages/base/any/kernels/3.18.25/patches/aufs.patch @@ -0,0 +1,33877 @@ +From 9da2de12351d9d38412a0074d49efaf3c5bf6f3f Mon Sep 17 00:00:00 2001 +From: Steven Noble +Date: Thu, 12 May 2016 21:42:28 +0000 +Subject: [PATCH] AUFS patches applied + +--- + MAINTAINERS | 14 + + drivers/block/loop.c | 18 + + fs/Kconfig | 1 + + fs/Makefile | 1 + + fs/aufs/Kconfig | 185 ++++ + fs/aufs/Makefile | 44 + + fs/aufs/aufs.h | 59 ++ + fs/aufs/branch.c | 1402 ++++++++++++++++++++++++++++++ + fs/aufs/branch.h | 279 ++++++ + fs/aufs/conf.mk | 38 + + fs/aufs/cpup.c | 1368 +++++++++++++++++++++++++++++ + fs/aufs/cpup.h | 94 ++ + fs/aufs/dbgaufs.c | 432 +++++++++ + fs/aufs/dbgaufs.h | 48 + + fs/aufs/dcsub.c | 224 +++++ + fs/aufs/dcsub.h | 123 +++ + fs/aufs/debug.c | 436 ++++++++++ + fs/aufs/debug.h | 228 +++++ + fs/aufs/dentry.c | 1129 ++++++++++++++++++++++++ + fs/aufs/dentry.h | 234 +++++ + fs/aufs/dinfo.c | 544 ++++++++++++ + fs/aufs/dir.c | 756 ++++++++++++++++ + fs/aufs/dir.h | 131 +++ + fs/aufs/dynop.c | 379 ++++++++ + fs/aufs/dynop.h | 76 ++ + fs/aufs/export.c | 831 ++++++++++++++++++ + fs/aufs/f_op.c | 781 +++++++++++++++++ + fs/aufs/fhsm.c | 426 +++++++++ + fs/aufs/file.c | 857 ++++++++++++++++++ + fs/aufs/file.h | 291 +++++++ + fs/aufs/finfo.c | 156 ++++ + fs/aufs/fstype.h | 400 +++++++++ + fs/aufs/hfsnotify.c | 288 ++++++ + fs/aufs/hfsplus.c | 56 ++ + fs/aufs/hnotify.c | 714 +++++++++++++++ + fs/aufs/i_op.c | 1460 +++++++++++++++++++++++++++++++ + fs/aufs/i_op_add.c | 930 ++++++++++++++++++++ + fs/aufs/i_op_del.c | 506 +++++++++++ + fs/aufs/i_op_ren.c | 1013 ++++++++++++++++++++++ + fs/aufs/iinfo.c | 277 ++++++ + fs/aufs/inode.c | 522 +++++++++++ + fs/aufs/inode.h | 686 +++++++++++++++ + fs/aufs/ioctl.c | 219 +++++ + fs/aufs/loop.c | 146 ++++ + fs/aufs/loop.h | 52 ++ + fs/aufs/magic.mk | 30 + + fs/aufs/module.c | 222 +++++ + fs/aufs/module.h | 105 +++ + fs/aufs/mvdown.c | 703 +++++++++++++++ + fs/aufs/opts.c | 1878 ++++++++++++++++++++++++++++++++++++++++ + fs/aufs/opts.h | 212 +++++ + fs/aufs/plink.c | 506 +++++++++++ + fs/aufs/poll.c | 52 ++ + fs/aufs/posix_acl.c | 98 +++ + fs/aufs/procfs.c | 169 ++++ + fs/aufs/rdu.c | 388 +++++++++ + fs/aufs/rwsem.h | 191 ++++ + fs/aufs/sbinfo.c | 348 ++++++++ + fs/aufs/spl.h | 111 +++ + fs/aufs/super.c | 1041 ++++++++++++++++++++++ + fs/aufs/super.h | 626 ++++++++++++++ + fs/aufs/sysaufs.c | 104 +++ + fs/aufs/sysaufs.h | 101 +++ + fs/aufs/sysfs.c | 376 ++++++++ + fs/aufs/sysrq.c | 157 ++++ + fs/aufs/vdir.c | 888 +++++++++++++++++++ + fs/aufs/vfsub.c | 864 ++++++++++++++++++ + fs/aufs/vfsub.h | 315 +++++++ + fs/aufs/wbr_policy.c | 765 ++++++++++++++++ + fs/aufs/whout.c | 1061 +++++++++++++++++++++++ + fs/aufs/whout.h | 85 ++ + fs/aufs/wkq.c | 213 +++++ + fs/aufs/wkq.h | 91 ++ + fs/aufs/xattr.c | 344 ++++++++ + fs/aufs/xino.c | 1343 ++++++++++++++++++++++++++++ + fs/buffer.c | 2 +- + fs/dcache.c | 2 +- + fs/fcntl.c | 4 +- + fs/inode.c | 2 +- + fs/proc/base.c | 2 +- + fs/proc/nommu.c | 5 +- + fs/proc/task_mmu.c | 7 +- + fs/proc/task_nommu.c | 5 +- + fs/splice.c | 10 +- + include/linux/file.h | 1 + + include/linux/fs.h | 3 + + include/linux/mm.h | 22 + + include/linux/mm_types.h | 2 + + include/linux/splice.h | 6 + + include/uapi/linux/Kbuild | 1 + + include/uapi/linux/aufs_type.h | 419 +++++++++ + kernel/fork.c | 2 +- + mm/Makefile | 2 +- + mm/filemap.c | 2 +- + mm/fremap.c | 16 +- + mm/memory.c | 2 +- + mm/mmap.c | 12 +- + mm/nommu.c | 10 +- + mm/prfile.c | 86 ++ + 99 files changed, 32835 insertions(+), 31 deletions(-) + create mode 100644 fs/aufs/Kconfig + create mode 100644 fs/aufs/Makefile + create mode 100644 fs/aufs/aufs.h + create mode 100644 fs/aufs/branch.c + create mode 100644 fs/aufs/branch.h + create mode 100644 fs/aufs/conf.mk + create mode 100644 fs/aufs/cpup.c + create mode 100644 fs/aufs/cpup.h + create mode 100644 fs/aufs/dbgaufs.c + create mode 100644 fs/aufs/dbgaufs.h + create mode 100644 fs/aufs/dcsub.c + create mode 100644 fs/aufs/dcsub.h + create mode 100644 fs/aufs/debug.c + create mode 100644 fs/aufs/debug.h + create mode 100644 fs/aufs/dentry.c + create mode 100644 fs/aufs/dentry.h + create mode 100644 fs/aufs/dinfo.c + create mode 100644 fs/aufs/dir.c + create mode 100644 fs/aufs/dir.h + create mode 100644 fs/aufs/dynop.c + create mode 100644 fs/aufs/dynop.h + create mode 100644 fs/aufs/export.c + create mode 100644 fs/aufs/f_op.c + create mode 100644 fs/aufs/fhsm.c + create mode 100644 fs/aufs/file.c + create mode 100644 fs/aufs/file.h + create mode 100644 fs/aufs/finfo.c + create mode 100644 fs/aufs/fstype.h + create mode 100644 fs/aufs/hfsnotify.c + create mode 100644 fs/aufs/hfsplus.c + create mode 100644 fs/aufs/hnotify.c + create mode 100644 fs/aufs/i_op.c + create mode 100644 fs/aufs/i_op_add.c + create mode 100644 fs/aufs/i_op_del.c + create mode 100644 fs/aufs/i_op_ren.c + create mode 100644 fs/aufs/iinfo.c + create mode 100644 fs/aufs/inode.c + create mode 100644 fs/aufs/inode.h + create mode 100644 fs/aufs/ioctl.c + create mode 100644 fs/aufs/loop.c + create mode 100644 fs/aufs/loop.h + create mode 100644 fs/aufs/magic.mk + create mode 100644 fs/aufs/module.c + create mode 100644 fs/aufs/module.h + create mode 100644 fs/aufs/mvdown.c + create mode 100644 fs/aufs/opts.c + create mode 100644 fs/aufs/opts.h + create mode 100644 fs/aufs/plink.c + create mode 100644 fs/aufs/poll.c + create mode 100644 fs/aufs/posix_acl.c + create mode 100644 fs/aufs/procfs.c + create mode 100644 fs/aufs/rdu.c + create mode 100644 fs/aufs/rwsem.h + create mode 100644 fs/aufs/sbinfo.c + create mode 100644 fs/aufs/spl.h + create mode 100644 fs/aufs/super.c + create mode 100644 fs/aufs/super.h + create mode 100644 fs/aufs/sysaufs.c + create mode 100644 fs/aufs/sysaufs.h + create mode 100644 fs/aufs/sysfs.c + create mode 100644 fs/aufs/sysrq.c + create mode 100644 fs/aufs/vdir.c + create mode 100644 fs/aufs/vfsub.c + create mode 100644 fs/aufs/vfsub.h + create mode 100644 fs/aufs/wbr_policy.c + create mode 100644 fs/aufs/whout.c + create mode 100644 fs/aufs/whout.h + create mode 100644 fs/aufs/wkq.c + create mode 100644 fs/aufs/wkq.h + create mode 100644 fs/aufs/xattr.c + create mode 100644 fs/aufs/xino.c + create mode 100644 include/uapi/linux/aufs_type.h + create mode 100644 mm/prfile.c + +diff --git a/MAINTAINERS b/MAINTAINERS +index c721042..83801d0 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -1795,6 +1795,20 @@ F: include/linux/audit.h + F: include/uapi/linux/audit.h + F: kernel/audit* + ++AUFS (advanced multi layered unification filesystem) FILESYSTEM ++M: "J. R. Okajima" ++L: linux-unionfs@vger.kernel.org ++L: aufs-users@lists.sourceforge.net (members only) ++W: http://aufs.sourceforge.net ++T: git://git.code.sf.net/p/aufs/aufs3-linux ++T: git://github.com/sfjro/aufs3-linux.git ++S: Supported ++F: Documentation/filesystems/aufs/ ++F: Documentation/ABI/testing/debugfs-aufs ++F: Documentation/ABI/testing/sysfs-aufs ++F: fs/aufs/ ++F: include/uapi/linux/aufs_type.h ++ + AUXILIARY DISPLAY DRIVERS + M: Miguel Ojeda Sandonis + W: http://miguelojeda.es/auxdisplay.htm +diff --git a/drivers/block/loop.c b/drivers/block/loop.c +index 6cb1beb..12678be 100644 +--- a/drivers/block/loop.c ++++ b/drivers/block/loop.c +@@ -692,6 +692,24 @@ static inline int is_loop_device(struct file *file) + return i && S_ISBLK(i->i_mode) && MAJOR(i->i_rdev) == LOOP_MAJOR; + } + ++/* ++ * for AUFS ++ * no get/put for file. ++ */ ++struct file *loop_backing_file(struct super_block *sb) ++{ ++ struct file *ret; ++ struct loop_device *l; ++ ++ ret = NULL; ++ if (MAJOR(sb->s_dev) == LOOP_MAJOR) { ++ l = sb->s_bdev->bd_disk->private_data; ++ ret = l->lo_backing_file; ++ } ++ return ret; ++} ++EXPORT_SYMBOL_GPL(loop_backing_file); ++ + /* loop sysfs attributes */ + + static ssize_t loop_attr_show(struct device *dev, char *page, +diff --git a/fs/Kconfig b/fs/Kconfig +index 664991a..1481093 100644 +--- a/fs/Kconfig ++++ b/fs/Kconfig +@@ -210,6 +210,7 @@ source "fs/ufs/Kconfig" + source "fs/exofs/Kconfig" + source "fs/f2fs/Kconfig" + source "fs/efivarfs/Kconfig" ++source "fs/aufs/Kconfig" + + endif # MISC_FILESYSTEMS + +diff --git a/fs/Makefile b/fs/Makefile +index da0bbb4..c8bc724 100644 +--- a/fs/Makefile ++++ b/fs/Makefile +@@ -126,3 +126,4 @@ obj-y += exofs/ # Multiple modules + obj-$(CONFIG_CEPH_FS) += ceph/ + obj-$(CONFIG_PSTORE) += pstore/ + obj-$(CONFIG_EFIVAR_FS) += efivarfs/ ++obj-$(CONFIG_AUFS_FS) += aufs/ +diff --git a/fs/aufs/Kconfig b/fs/aufs/Kconfig +new file mode 100644 +index 0000000..63560ce +--- /dev/null ++++ b/fs/aufs/Kconfig +@@ -0,0 +1,185 @@ ++config AUFS_FS ++ tristate "Aufs (Advanced multi layered unification filesystem) support" ++ help ++ Aufs is a stackable unification filesystem such as Unionfs, ++ which unifies several directories and provides a merged single ++ directory. ++ In the early days, aufs was entirely re-designed and ++ re-implemented Unionfs Version 1.x series. Introducing many ++ original ideas, approaches and improvements, it becomes totally ++ different from Unionfs while keeping the basic features. ++ ++if AUFS_FS ++choice ++ prompt "Maximum number of branches" ++ default AUFS_BRANCH_MAX_127 ++ help ++ Specifies the maximum number of branches (or member directories) ++ in a single aufs. The larger value consumes more system ++ resources and has a minor impact to performance. ++config AUFS_BRANCH_MAX_127 ++ bool "127" ++ help ++ Specifies the maximum number of branches (or member directories) ++ in a single aufs. The larger value consumes more system ++ resources and has a minor impact to performance. ++config AUFS_BRANCH_MAX_511 ++ bool "511" ++ help ++ Specifies the maximum number of branches (or member directories) ++ in a single aufs. The larger value consumes more system ++ resources and has a minor impact to performance. ++config AUFS_BRANCH_MAX_1023 ++ bool "1023" ++ help ++ Specifies the maximum number of branches (or member directories) ++ in a single aufs. The larger value consumes more system ++ resources and has a minor impact to performance. ++config AUFS_BRANCH_MAX_32767 ++ bool "32767" ++ help ++ Specifies the maximum number of branches (or member directories) ++ in a single aufs. The larger value consumes more system ++ resources and has a minor impact to performance. ++endchoice ++ ++config AUFS_SBILIST ++ bool ++ depends on AUFS_MAGIC_SYSRQ || PROC_FS ++ default y ++ help ++ Automatic configuration for internal use. ++ When aufs supports Magic SysRq or /proc, enabled automatically. ++ ++config AUFS_HNOTIFY ++ bool "Detect direct branch access (bypassing aufs)" ++ help ++ If you want to modify files on branches directly, eg. bypassing aufs, ++ and want aufs to detect the changes of them fully, then enable this ++ option and use 'udba=notify' mount option. ++ Currently there is only one available configuration, "fsnotify". ++ It will have a negative impact to the performance. ++ See detail in aufs.5. ++ ++choice ++ prompt "method" if AUFS_HNOTIFY ++ default AUFS_HFSNOTIFY ++config AUFS_HFSNOTIFY ++ bool "fsnotify" ++ select FSNOTIFY ++endchoice ++ ++config AUFS_EXPORT ++ bool "NFS-exportable aufs" ++ depends on EXPORTFS ++ help ++ If you want to export your mounted aufs via NFS, then enable this ++ option. There are several requirements for this configuration. ++ See detail in aufs.5. ++ ++config AUFS_INO_T_64 ++ bool ++ depends on AUFS_EXPORT ++ depends on 64BIT && !(ALPHA || S390) ++ default y ++ help ++ Automatic configuration for internal use. ++ /* typedef unsigned long/int __kernel_ino_t */ ++ /* alpha and s390x are int */ ++ ++config AUFS_XATTR ++ bool "support for XATTR/EA (including Security Labels)" ++ help ++ If your branch fs supports XATTR/EA and you want to make them ++ available in aufs too, then enable this opsion and specify the ++ branch attributes for EA. ++ See detail in aufs.5. ++ ++config AUFS_FHSM ++ bool "File-based Hierarchical Storage Management" ++ help ++ Hierarchical Storage Management (or HSM) is a well-known feature ++ in the storage world. Aufs provides this feature as file-based. ++ with multiple branches. ++ These multiple branches are prioritized, ie. the topmost one ++ should be the fastest drive and be used heavily. ++ ++config AUFS_RDU ++ bool "Readdir in userspace" ++ help ++ Aufs has two methods to provide a merged view for a directory, ++ by a user-space library and by kernel-space natively. The latter ++ is always enabled but sometimes large and slow. ++ If you enable this option, install the library in aufs2-util ++ package, and set some environment variables for your readdir(3), ++ then the work will be handled in user-space which generally ++ shows better performance in most cases. ++ See detail in aufs.5. ++ ++config AUFS_SHWH ++ bool "Show whiteouts" ++ help ++ If you want to make the whiteouts in aufs visible, then enable ++ this option and specify 'shwh' mount option. Although it may ++ sounds like philosophy or something, but in technically it ++ simply shows the name of whiteout with keeping its behaviour. ++ ++config AUFS_BR_RAMFS ++ bool "Ramfs (initramfs/rootfs) as an aufs branch" ++ help ++ If you want to use ramfs as an aufs branch fs, then enable this ++ option. Generally tmpfs is recommended. ++ Aufs prohibited them to be a branch fs by default, because ++ initramfs becomes unusable after switch_root or something ++ generally. If you sets initramfs as an aufs branch and boot your ++ system by switch_root, you will meet a problem easily since the ++ files in initramfs may be inaccessible. ++ Unless you are going to use ramfs as an aufs branch fs without ++ switch_root or something, leave it N. ++ ++config AUFS_BR_FUSE ++ bool "Fuse fs as an aufs branch" ++ depends on FUSE_FS ++ select AUFS_POLL ++ help ++ If you want to use fuse-based userspace filesystem as an aufs ++ branch fs, then enable this option. ++ It implements the internal poll(2) operation which is ++ implemented by fuse only (curretnly). ++ ++config AUFS_POLL ++ bool ++ help ++ Automatic configuration for internal use. ++ ++config AUFS_BR_HFSPLUS ++ bool "Hfsplus as an aufs branch" ++ depends on HFSPLUS_FS ++ default y ++ help ++ If you want to use hfsplus fs as an aufs branch fs, then enable ++ this option. This option introduces a small overhead at ++ copying-up a file on hfsplus. ++ ++config AUFS_BDEV_LOOP ++ bool ++ depends on BLK_DEV_LOOP ++ default y ++ help ++ Automatic configuration for internal use. ++ Convert =[ym] into =y. ++ ++config AUFS_DEBUG ++ bool "Debug aufs" ++ help ++ Enable this to compile aufs internal debug code. ++ It will have a negative impact to the performance. ++ ++config AUFS_MAGIC_SYSRQ ++ bool ++ depends on AUFS_DEBUG && MAGIC_SYSRQ ++ default y ++ help ++ Automatic configuration for internal use. ++ When aufs supports Magic SysRq, enabled automatically. ++endif +diff --git a/fs/aufs/Makefile b/fs/aufs/Makefile +new file mode 100644 +index 0000000..c7a501e +--- /dev/null ++++ b/fs/aufs/Makefile +@@ -0,0 +1,44 @@ ++ ++include ${src}/magic.mk ++ifeq (${CONFIG_AUFS_FS},m) ++include ${src}/conf.mk ++endif ++-include ${src}/priv_def.mk ++ ++# cf. include/linux/kernel.h ++# enable pr_debug ++ccflags-y += -DDEBUG ++# sparse requires the full pathname ++ifdef M ++ccflags-y += -include ${M}/../../include/uapi/linux/aufs_type.h ++else ++ccflags-y += -include ${srctree}/include/uapi/linux/aufs_type.h ++endif ++ ++obj-$(CONFIG_AUFS_FS) += aufs.o ++aufs-y := module.o sbinfo.o super.o branch.o xino.o sysaufs.o opts.o \ ++ wkq.o vfsub.o dcsub.o \ ++ cpup.o whout.o wbr_policy.o \ ++ dinfo.o dentry.o \ ++ dynop.o \ ++ finfo.o file.o f_op.o \ ++ dir.o vdir.o \ ++ iinfo.o inode.o i_op.o i_op_add.o i_op_del.o i_op_ren.o \ ++ mvdown.o ioctl.o ++ ++# all are boolean ++aufs-$(CONFIG_PROC_FS) += procfs.o plink.o ++aufs-$(CONFIG_SYSFS) += sysfs.o ++aufs-$(CONFIG_DEBUG_FS) += dbgaufs.o ++aufs-$(CONFIG_AUFS_BDEV_LOOP) += loop.o ++aufs-$(CONFIG_AUFS_HNOTIFY) += hnotify.o ++aufs-$(CONFIG_AUFS_HFSNOTIFY) += hfsnotify.o ++aufs-$(CONFIG_AUFS_EXPORT) += export.o ++aufs-$(CONFIG_AUFS_XATTR) += xattr.o ++aufs-$(CONFIG_FS_POSIX_ACL) += posix_acl.o ++aufs-$(CONFIG_AUFS_FHSM) += fhsm.o ++aufs-$(CONFIG_AUFS_POLL) += poll.o ++aufs-$(CONFIG_AUFS_RDU) += rdu.o ++aufs-$(CONFIG_AUFS_BR_HFSPLUS) += hfsplus.o ++aufs-$(CONFIG_AUFS_DEBUG) += debug.o ++aufs-$(CONFIG_AUFS_MAGIC_SYSRQ) += sysrq.o +diff --git a/fs/aufs/aufs.h b/fs/aufs/aufs.h +new file mode 100644 +index 0000000..e48d268 +--- /dev/null ++++ b/fs/aufs/aufs.h +@@ -0,0 +1,59 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * all header files ++ */ ++ ++#ifndef __AUFS_H__ ++#define __AUFS_H__ ++ ++#ifdef __KERNEL__ ++ ++#define AuStub(type, name, body, ...) \ ++ static inline type name(__VA_ARGS__) { body; } ++ ++#define AuStubVoid(name, ...) \ ++ AuStub(void, name, , __VA_ARGS__) ++#define AuStubInt0(name, ...) \ ++ AuStub(int, name, return 0, __VA_ARGS__) ++ ++#include "debug.h" ++ ++#include "branch.h" ++#include "cpup.h" ++#include "dcsub.h" ++#include "dbgaufs.h" ++#include "dentry.h" ++#include "dir.h" ++#include "dynop.h" ++#include "file.h" ++#include "fstype.h" ++#include "inode.h" ++#include "loop.h" ++#include "module.h" ++#include "opts.h" ++#include "rwsem.h" ++#include "spl.h" ++#include "super.h" ++#include "sysaufs.h" ++#include "vfsub.h" ++#include "whout.h" ++#include "wkq.h" ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_H__ */ +diff --git a/fs/aufs/branch.c b/fs/aufs/branch.c +new file mode 100644 +index 0000000..17210b2 +--- /dev/null ++++ b/fs/aufs/branch.c +@@ -0,0 +1,1402 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * branch management ++ */ ++ ++#include ++#include ++#include "aufs.h" ++ ++/* ++ * free a single branch ++ */ ++static void au_br_do_free(struct au_branch *br) ++{ ++ int i; ++ struct au_wbr *wbr; ++ struct au_dykey **key; ++ ++ au_hnotify_fin_br(br); ++ ++ if (br->br_xino.xi_file) ++ fput(br->br_xino.xi_file); ++ mutex_destroy(&br->br_xino.xi_nondir_mtx); ++ ++ AuDebugOn(atomic_read(&br->br_count)); ++ ++ wbr = br->br_wbr; ++ if (wbr) { ++ for (i = 0; i < AuBrWh_Last; i++) ++ dput(wbr->wbr_wh[i]); ++ AuDebugOn(atomic_read(&wbr->wbr_wh_running)); ++ AuRwDestroy(&wbr->wbr_wh_rwsem); ++ } ++ ++ if (br->br_fhsm) { ++ au_br_fhsm_fin(br->br_fhsm); ++ kfree(br->br_fhsm); ++ } ++ ++ key = br->br_dykey; ++ for (i = 0; i < AuBrDynOp; i++, key++) ++ if (*key) ++ au_dy_put(*key); ++ else ++ break; ++ ++ /* recursive lock, s_umount of branch's */ ++ lockdep_off(); ++ path_put(&br->br_path); ++ lockdep_on(); ++ kfree(wbr); ++ kfree(br); ++} ++ ++/* ++ * frees all branches ++ */ ++void au_br_free(struct au_sbinfo *sbinfo) ++{ ++ aufs_bindex_t bmax; ++ struct au_branch **br; ++ ++ AuRwMustWriteLock(&sbinfo->si_rwsem); ++ ++ bmax = sbinfo->si_bend + 1; ++ br = sbinfo->si_branch; ++ while (bmax--) ++ au_br_do_free(*br++); ++} ++ ++/* ++ * find the index of a branch which is specified by @br_id. ++ */ ++int au_br_index(struct super_block *sb, aufs_bindex_t br_id) ++{ ++ aufs_bindex_t bindex, bend; ++ ++ bend = au_sbend(sb); ++ for (bindex = 0; bindex <= bend; bindex++) ++ if (au_sbr_id(sb, bindex) == br_id) ++ return bindex; ++ return -1; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * add a branch ++ */ ++ ++static int test_overlap(struct super_block *sb, struct dentry *h_adding, ++ struct dentry *h_root) ++{ ++ if (unlikely(h_adding == h_root ++ || au_test_loopback_overlap(sb, h_adding))) ++ return 1; ++ if (h_adding->d_sb != h_root->d_sb) ++ return 0; ++ return au_test_subdir(h_adding, h_root) ++ || au_test_subdir(h_root, h_adding); ++} ++ ++/* ++ * returns a newly allocated branch. @new_nbranch is a number of branches ++ * after adding a branch. ++ */ ++static struct au_branch *au_br_alloc(struct super_block *sb, int new_nbranch, ++ int perm) ++{ ++ struct au_branch *add_branch; ++ struct dentry *root; ++ int err; ++ ++ err = -ENOMEM; ++ root = sb->s_root; ++ add_branch = kzalloc(sizeof(*add_branch), GFP_NOFS); ++ if (unlikely(!add_branch)) ++ goto out; ++ ++ err = au_hnotify_init_br(add_branch, perm); ++ if (unlikely(err)) ++ goto out_br; ++ ++ if (au_br_writable(perm)) { ++ /* may be freed separately at changing the branch permission */ ++ add_branch->br_wbr = kzalloc(sizeof(*add_branch->br_wbr), ++ GFP_NOFS); ++ if (unlikely(!add_branch->br_wbr)) ++ goto out_hnotify; ++ } ++ ++ if (au_br_fhsm(perm)) { ++ err = au_fhsm_br_alloc(add_branch); ++ if (unlikely(err)) ++ goto out_wbr; ++ } ++ ++ err = au_sbr_realloc(au_sbi(sb), new_nbranch); ++ if (!err) ++ err = au_di_realloc(au_di(root), new_nbranch); ++ if (!err) ++ err = au_ii_realloc(au_ii(root->d_inode), new_nbranch); ++ if (!err) ++ return add_branch; /* success */ ++ ++out_wbr: ++ kfree(add_branch->br_wbr); ++out_hnotify: ++ au_hnotify_fin_br(add_branch); ++out_br: ++ kfree(add_branch); ++out: ++ return ERR_PTR(err); ++} ++ ++/* ++ * test if the branch permission is legal or not. ++ */ ++static int test_br(struct inode *inode, int brperm, char *path) ++{ ++ int err; ++ ++ err = (au_br_writable(brperm) && IS_RDONLY(inode)); ++ if (!err) ++ goto out; ++ ++ err = -EINVAL; ++ pr_err("write permission for readonly mount or inode, %s\n", path); ++ ++out: ++ return err; ++} ++ ++/* ++ * returns: ++ * 0: success, the caller will add it ++ * plus: success, it is already unified, the caller should ignore it ++ * minus: error ++ */ ++static int test_add(struct super_block *sb, struct au_opt_add *add, int remount) ++{ ++ int err; ++ aufs_bindex_t bend, bindex; ++ struct dentry *root; ++ struct inode *inode, *h_inode; ++ ++ root = sb->s_root; ++ bend = au_sbend(sb); ++ if (unlikely(bend >= 0 ++ && au_find_dbindex(root, add->path.dentry) >= 0)) { ++ err = 1; ++ if (!remount) { ++ err = -EINVAL; ++ pr_err("%s duplicated\n", add->pathname); ++ } ++ goto out; ++ } ++ ++ err = -ENOSPC; /* -E2BIG; */ ++ if (unlikely(AUFS_BRANCH_MAX <= add->bindex ++ || AUFS_BRANCH_MAX - 1 <= bend)) { ++ pr_err("number of branches exceeded %s\n", add->pathname); ++ goto out; ++ } ++ ++ err = -EDOM; ++ if (unlikely(add->bindex < 0 || bend + 1 < add->bindex)) { ++ pr_err("bad index %d\n", add->bindex); ++ goto out; ++ } ++ ++ inode = add->path.dentry->d_inode; ++ err = -ENOENT; ++ if (unlikely(!inode->i_nlink)) { ++ pr_err("no existence %s\n", add->pathname); ++ goto out; ++ } ++ ++ err = -EINVAL; ++ if (unlikely(inode->i_sb == sb)) { ++ pr_err("%s must be outside\n", add->pathname); ++ goto out; ++ } ++ ++ if (unlikely(au_test_fs_unsuppoted(inode->i_sb))) { ++ pr_err("unsupported filesystem, %s (%s)\n", ++ add->pathname, au_sbtype(inode->i_sb)); ++ goto out; ++ } ++ ++ if (unlikely(inode->i_sb->s_stack_depth)) { ++ pr_err("already stacked, %s (%s)\n", ++ add->pathname, au_sbtype(inode->i_sb)); ++ goto out; ++ } ++ ++ err = test_br(add->path.dentry->d_inode, add->perm, add->pathname); ++ if (unlikely(err)) ++ goto out; ++ ++ if (bend < 0) ++ return 0; /* success */ ++ ++ err = -EINVAL; ++ for (bindex = 0; bindex <= bend; bindex++) ++ if (unlikely(test_overlap(sb, add->path.dentry, ++ au_h_dptr(root, bindex)))) { ++ pr_err("%s is overlapped\n", add->pathname); ++ goto out; ++ } ++ ++ err = 0; ++ if (au_opt_test(au_mntflags(sb), WARN_PERM)) { ++ h_inode = au_h_dptr(root, 0)->d_inode; ++ if ((h_inode->i_mode & S_IALLUGO) != (inode->i_mode & S_IALLUGO) ++ || !uid_eq(h_inode->i_uid, inode->i_uid) ++ || !gid_eq(h_inode->i_gid, inode->i_gid)) ++ pr_warn("uid/gid/perm %s %u/%u/0%o, %u/%u/0%o\n", ++ add->pathname, ++ i_uid_read(inode), i_gid_read(inode), ++ (inode->i_mode & S_IALLUGO), ++ i_uid_read(h_inode), i_gid_read(h_inode), ++ (h_inode->i_mode & S_IALLUGO)); ++ } ++ ++out: ++ return err; ++} ++ ++/* ++ * initialize or clean the whiteouts for an adding branch ++ */ ++static int au_br_init_wh(struct super_block *sb, struct au_branch *br, ++ int new_perm) ++{ ++ int err, old_perm; ++ aufs_bindex_t bindex; ++ struct mutex *h_mtx; ++ struct au_wbr *wbr; ++ struct au_hinode *hdir; ++ ++ err = vfsub_mnt_want_write(au_br_mnt(br)); ++ if (unlikely(err)) ++ goto out; ++ ++ wbr = br->br_wbr; ++ old_perm = br->br_perm; ++ br->br_perm = new_perm; ++ hdir = NULL; ++ h_mtx = NULL; ++ bindex = au_br_index(sb, br->br_id); ++ if (0 <= bindex) { ++ hdir = au_hi(sb->s_root->d_inode, bindex); ++ au_hn_imtx_lock_nested(hdir, AuLsc_I_PARENT); ++ } else { ++ h_mtx = &au_br_dentry(br)->d_inode->i_mutex; ++ mutex_lock_nested(h_mtx, AuLsc_I_PARENT); ++ } ++ if (!wbr) ++ err = au_wh_init(br, sb); ++ else { ++ wbr_wh_write_lock(wbr); ++ err = au_wh_init(br, sb); ++ wbr_wh_write_unlock(wbr); ++ } ++ if (hdir) ++ au_hn_imtx_unlock(hdir); ++ else ++ mutex_unlock(h_mtx); ++ vfsub_mnt_drop_write(au_br_mnt(br)); ++ br->br_perm = old_perm; ++ ++ if (!err && wbr && !au_br_writable(new_perm)) { ++ kfree(wbr); ++ br->br_wbr = NULL; ++ } ++ ++out: ++ return err; ++} ++ ++static int au_wbr_init(struct au_branch *br, struct super_block *sb, ++ int perm) ++{ ++ int err; ++ struct kstatfs kst; ++ struct au_wbr *wbr; ++ ++ wbr = br->br_wbr; ++ au_rw_init(&wbr->wbr_wh_rwsem); ++ atomic_set(&wbr->wbr_wh_running, 0); ++ ++ /* ++ * a limit for rmdir/rename a dir ++ * cf. AUFS_MAX_NAMELEN in include/uapi/linux/aufs_type.h ++ */ ++ err = vfs_statfs(&br->br_path, &kst); ++ if (unlikely(err)) ++ goto out; ++ err = -EINVAL; ++ if (kst.f_namelen >= NAME_MAX) ++ err = au_br_init_wh(sb, br, perm); ++ else ++ pr_err("%pd(%s), unsupported namelen %ld\n", ++ au_br_dentry(br), ++ au_sbtype(au_br_dentry(br)->d_sb), kst.f_namelen); ++ ++out: ++ return err; ++} ++ ++/* initialize a new branch */ ++static int au_br_init(struct au_branch *br, struct super_block *sb, ++ struct au_opt_add *add) ++{ ++ int err; ++ ++ err = 0; ++ mutex_init(&br->br_xino.xi_nondir_mtx); ++ br->br_perm = add->perm; ++ br->br_path = add->path; /* set first, path_get() later */ ++ spin_lock_init(&br->br_dykey_lock); ++ atomic_set(&br->br_count, 0); ++ atomic_set(&br->br_xino_running, 0); ++ br->br_id = au_new_br_id(sb); ++ AuDebugOn(br->br_id < 0); ++ ++ if (au_br_writable(add->perm)) { ++ err = au_wbr_init(br, sb, add->perm); ++ if (unlikely(err)) ++ goto out_err; ++ } ++ ++ if (au_opt_test(au_mntflags(sb), XINO)) { ++ err = au_xino_br(sb, br, add->path.dentry->d_inode->i_ino, ++ au_sbr(sb, 0)->br_xino.xi_file, /*do_test*/1); ++ if (unlikely(err)) { ++ AuDebugOn(br->br_xino.xi_file); ++ goto out_err; ++ } ++ } ++ ++ sysaufs_br_init(br); ++ path_get(&br->br_path); ++ goto out; /* success */ ++ ++out_err: ++ memset(&br->br_path, 0, sizeof(br->br_path)); ++out: ++ return err; ++} ++ ++static void au_br_do_add_brp(struct au_sbinfo *sbinfo, aufs_bindex_t bindex, ++ struct au_branch *br, aufs_bindex_t bend, ++ aufs_bindex_t amount) ++{ ++ struct au_branch **brp; ++ ++ AuRwMustWriteLock(&sbinfo->si_rwsem); ++ ++ brp = sbinfo->si_branch + bindex; ++ memmove(brp + 1, brp, sizeof(*brp) * amount); ++ *brp = br; ++ sbinfo->si_bend++; ++ if (unlikely(bend < 0)) ++ sbinfo->si_bend = 0; ++} ++ ++static void au_br_do_add_hdp(struct au_dinfo *dinfo, aufs_bindex_t bindex, ++ aufs_bindex_t bend, aufs_bindex_t amount) ++{ ++ struct au_hdentry *hdp; ++ ++ AuRwMustWriteLock(&dinfo->di_rwsem); ++ ++ hdp = dinfo->di_hdentry + bindex; ++ memmove(hdp + 1, hdp, sizeof(*hdp) * amount); ++ au_h_dentry_init(hdp); ++ dinfo->di_bend++; ++ if (unlikely(bend < 0)) ++ dinfo->di_bstart = 0; ++} ++ ++static void au_br_do_add_hip(struct au_iinfo *iinfo, aufs_bindex_t bindex, ++ aufs_bindex_t bend, aufs_bindex_t amount) ++{ ++ struct au_hinode *hip; ++ ++ AuRwMustWriteLock(&iinfo->ii_rwsem); ++ ++ hip = iinfo->ii_hinode + bindex; ++ memmove(hip + 1, hip, sizeof(*hip) * amount); ++ hip->hi_inode = NULL; ++ au_hn_init(hip); ++ iinfo->ii_bend++; ++ if (unlikely(bend < 0)) ++ iinfo->ii_bstart = 0; ++} ++ ++static void au_br_do_add(struct super_block *sb, struct au_branch *br, ++ aufs_bindex_t bindex) ++{ ++ struct dentry *root, *h_dentry; ++ struct inode *root_inode; ++ aufs_bindex_t bend, amount; ++ ++ root = sb->s_root; ++ root_inode = root->d_inode; ++ bend = au_sbend(sb); ++ amount = bend + 1 - bindex; ++ h_dentry = au_br_dentry(br); ++ au_sbilist_lock(); ++ au_br_do_add_brp(au_sbi(sb), bindex, br, bend, amount); ++ au_br_do_add_hdp(au_di(root), bindex, bend, amount); ++ au_br_do_add_hip(au_ii(root_inode), bindex, bend, amount); ++ au_set_h_dptr(root, bindex, dget(h_dentry)); ++ au_set_h_iptr(root_inode, bindex, au_igrab(h_dentry->d_inode), ++ /*flags*/0); ++ au_sbilist_unlock(); ++} ++ ++int au_br_add(struct super_block *sb, struct au_opt_add *add, int remount) ++{ ++ int err; ++ aufs_bindex_t bend, add_bindex; ++ struct dentry *root, *h_dentry; ++ struct inode *root_inode; ++ struct au_branch *add_branch; ++ ++ root = sb->s_root; ++ root_inode = root->d_inode; ++ IMustLock(root_inode); ++ err = test_add(sb, add, remount); ++ if (unlikely(err < 0)) ++ goto out; ++ if (err) { ++ err = 0; ++ goto out; /* success */ ++ } ++ ++ bend = au_sbend(sb); ++ add_branch = au_br_alloc(sb, bend + 2, add->perm); ++ err = PTR_ERR(add_branch); ++ if (IS_ERR(add_branch)) ++ goto out; ++ ++ err = au_br_init(add_branch, sb, add); ++ if (unlikely(err)) { ++ au_br_do_free(add_branch); ++ goto out; ++ } ++ ++ add_bindex = add->bindex; ++ if (!remount) ++ au_br_do_add(sb, add_branch, add_bindex); ++ else { ++ sysaufs_brs_del(sb, add_bindex); ++ au_br_do_add(sb, add_branch, add_bindex); ++ sysaufs_brs_add(sb, add_bindex); ++ } ++ ++ h_dentry = add->path.dentry; ++ if (!add_bindex) { ++ au_cpup_attr_all(root_inode, /*force*/1); ++ sb->s_maxbytes = h_dentry->d_sb->s_maxbytes; ++ } else ++ au_add_nlink(root_inode, h_dentry->d_inode); ++ ++ /* ++ * this test/set prevents aufs from handling unnecesary notify events ++ * of xino files, in case of re-adding a writable branch which was ++ * once detached from aufs. ++ */ ++ if (au_xino_brid(sb) < 0 ++ && au_br_writable(add_branch->br_perm) ++ && !au_test_fs_bad_xino(h_dentry->d_sb) ++ && add_branch->br_xino.xi_file ++ && add_branch->br_xino.xi_file->f_dentry->d_parent == h_dentry) ++ au_xino_brid_set(sb, add_branch->br_id); ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static unsigned long long au_farray_cb(void *a, ++ unsigned long long max __maybe_unused, ++ void *arg) ++{ ++ unsigned long long n; ++ struct file **p, *f; ++ struct au_sphlhead *files; ++ struct au_finfo *finfo; ++ struct super_block *sb = arg; ++ ++ n = 0; ++ p = a; ++ files = &au_sbi(sb)->si_files; ++ spin_lock(&files->spin); ++ hlist_for_each_entry(finfo, &files->head, fi_hlist) { ++ f = finfo->fi_file; ++ if (file_count(f) ++ && !special_file(file_inode(f)->i_mode)) { ++ get_file(f); ++ *p++ = f; ++ n++; ++ AuDebugOn(n > max); ++ } ++ } ++ spin_unlock(&files->spin); ++ ++ return n; ++} ++ ++static struct file **au_farray_alloc(struct super_block *sb, ++ unsigned long long *max) ++{ ++ *max = atomic_long_read(&au_sbi(sb)->si_nfiles); ++ return au_array_alloc(max, au_farray_cb, sb); ++} ++ ++static void au_farray_free(struct file **a, unsigned long long max) ++{ ++ unsigned long long ull; ++ ++ for (ull = 0; ull < max; ull++) ++ if (a[ull]) ++ fput(a[ull]); ++ kvfree(a); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * delete a branch ++ */ ++ ++/* to show the line number, do not make it inlined function */ ++#define AuVerbose(do_info, fmt, ...) do { \ ++ if (do_info) \ ++ pr_info(fmt, ##__VA_ARGS__); \ ++} while (0) ++ ++static int au_test_ibusy(struct inode *inode, aufs_bindex_t bstart, ++ aufs_bindex_t bend) ++{ ++ return (inode && !S_ISDIR(inode->i_mode)) || bstart == bend; ++} ++ ++static int au_test_dbusy(struct dentry *dentry, aufs_bindex_t bstart, ++ aufs_bindex_t bend) ++{ ++ return au_test_ibusy(dentry->d_inode, bstart, bend); ++} ++ ++/* ++ * test if the branch is deletable or not. ++ */ ++static int test_dentry_busy(struct dentry *root, aufs_bindex_t bindex, ++ unsigned int sigen, const unsigned int verbose) ++{ ++ int err, i, j, ndentry; ++ aufs_bindex_t bstart, bend; ++ struct au_dcsub_pages dpages; ++ struct au_dpage *dpage; ++ struct dentry *d; ++ ++ err = au_dpages_init(&dpages, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ err = au_dcsub_pages(&dpages, root, NULL, NULL); ++ if (unlikely(err)) ++ goto out_dpages; ++ ++ for (i = 0; !err && i < dpages.ndpage; i++) { ++ dpage = dpages.dpages + i; ++ ndentry = dpage->ndentry; ++ for (j = 0; !err && j < ndentry; j++) { ++ d = dpage->dentries[j]; ++ AuDebugOn(au_dcount(d) <= 0); ++ if (!au_digen_test(d, sigen)) { ++ di_read_lock_child(d, AuLock_IR); ++ if (unlikely(au_dbrange_test(d))) { ++ di_read_unlock(d, AuLock_IR); ++ continue; ++ } ++ } else { ++ di_write_lock_child(d); ++ if (unlikely(au_dbrange_test(d))) { ++ di_write_unlock(d); ++ continue; ++ } ++ err = au_reval_dpath(d, sigen); ++ if (!err) ++ di_downgrade_lock(d, AuLock_IR); ++ else { ++ di_write_unlock(d); ++ break; ++ } ++ } ++ ++ /* AuDbgDentry(d); */ ++ bstart = au_dbstart(d); ++ bend = au_dbend(d); ++ if (bstart <= bindex ++ && bindex <= bend ++ && au_h_dptr(d, bindex) ++ && au_test_dbusy(d, bstart, bend)) { ++ err = -EBUSY; ++ AuVerbose(verbose, "busy %pd\n", d); ++ AuDbgDentry(d); ++ } ++ di_read_unlock(d, AuLock_IR); ++ } ++ } ++ ++out_dpages: ++ au_dpages_free(&dpages); ++out: ++ return err; ++} ++ ++static int test_inode_busy(struct super_block *sb, aufs_bindex_t bindex, ++ unsigned int sigen, const unsigned int verbose) ++{ ++ int err; ++ unsigned long long max, ull; ++ struct inode *i, **array; ++ aufs_bindex_t bstart, bend; ++ ++ array = au_iarray_alloc(sb, &max); ++ err = PTR_ERR(array); ++ if (IS_ERR(array)) ++ goto out; ++ ++ err = 0; ++ AuDbg("b%d\n", bindex); ++ for (ull = 0; !err && ull < max; ull++) { ++ i = array[ull]; ++ if (unlikely(!i)) ++ break; ++ if (i->i_ino == AUFS_ROOT_INO) ++ continue; ++ ++ /* AuDbgInode(i); */ ++ if (au_iigen(i, NULL) == sigen) ++ ii_read_lock_child(i); ++ else { ++ ii_write_lock_child(i); ++ err = au_refresh_hinode_self(i); ++ au_iigen_dec(i); ++ if (!err) ++ ii_downgrade_lock(i); ++ else { ++ ii_write_unlock(i); ++ break; ++ } ++ } ++ ++ bstart = au_ibstart(i); ++ bend = au_ibend(i); ++ if (bstart <= bindex ++ && bindex <= bend ++ && au_h_iptr(i, bindex) ++ && au_test_ibusy(i, bstart, bend)) { ++ err = -EBUSY; ++ AuVerbose(verbose, "busy i%lu\n", i->i_ino); ++ AuDbgInode(i); ++ } ++ ii_read_unlock(i); ++ } ++ au_iarray_free(array, max); ++ ++out: ++ return err; ++} ++ ++static int test_children_busy(struct dentry *root, aufs_bindex_t bindex, ++ const unsigned int verbose) ++{ ++ int err; ++ unsigned int sigen; ++ ++ sigen = au_sigen(root->d_sb); ++ DiMustNoWaiters(root); ++ IiMustNoWaiters(root->d_inode); ++ di_write_unlock(root); ++ err = test_dentry_busy(root, bindex, sigen, verbose); ++ if (!err) ++ err = test_inode_busy(root->d_sb, bindex, sigen, verbose); ++ di_write_lock_child(root); /* aufs_write_lock() calls ..._child() */ ++ ++ return err; ++} ++ ++static int test_dir_busy(struct file *file, aufs_bindex_t br_id, ++ struct file **to_free, int *idx) ++{ ++ int err; ++ unsigned char matched, root; ++ aufs_bindex_t bindex, bend; ++ struct au_fidir *fidir; ++ struct au_hfile *hfile; ++ ++ err = 0; ++ root = IS_ROOT(file->f_dentry); ++ if (root) { ++ get_file(file); ++ to_free[*idx] = file; ++ (*idx)++; ++ goto out; ++ } ++ ++ matched = 0; ++ fidir = au_fi(file)->fi_hdir; ++ AuDebugOn(!fidir); ++ bend = au_fbend_dir(file); ++ for (bindex = au_fbstart(file); bindex <= bend; bindex++) { ++ hfile = fidir->fd_hfile + bindex; ++ if (!hfile->hf_file) ++ continue; ++ ++ if (hfile->hf_br->br_id == br_id) { ++ matched = 1; ++ break; ++ } ++ } ++ if (matched) ++ err = -EBUSY; ++ ++out: ++ return err; ++} ++ ++static int test_file_busy(struct super_block *sb, aufs_bindex_t br_id, ++ struct file **to_free, int opened) ++{ ++ int err, idx; ++ unsigned long long ull, max; ++ aufs_bindex_t bstart; ++ struct file *file, **array; ++ struct dentry *root; ++ struct au_hfile *hfile; ++ ++ array = au_farray_alloc(sb, &max); ++ err = PTR_ERR(array); ++ if (IS_ERR(array)) ++ goto out; ++ ++ err = 0; ++ idx = 0; ++ root = sb->s_root; ++ di_write_unlock(root); ++ for (ull = 0; ull < max; ull++) { ++ file = array[ull]; ++ if (unlikely(!file)) ++ break; ++ ++ /* AuDbg("%pD\n", file); */ ++ fi_read_lock(file); ++ bstart = au_fbstart(file); ++ if (!d_is_dir(file->f_path.dentry)) { ++ hfile = &au_fi(file)->fi_htop; ++ if (hfile->hf_br->br_id == br_id) ++ err = -EBUSY; ++ } else ++ err = test_dir_busy(file, br_id, to_free, &idx); ++ fi_read_unlock(file); ++ if (unlikely(err)) ++ break; ++ } ++ di_write_lock_child(root); ++ au_farray_free(array, max); ++ AuDebugOn(idx > opened); ++ ++out: ++ return err; ++} ++ ++static void br_del_file(struct file **to_free, unsigned long long opened, ++ aufs_bindex_t br_id) ++{ ++ unsigned long long ull; ++ aufs_bindex_t bindex, bstart, bend, bfound; ++ struct file *file; ++ struct au_fidir *fidir; ++ struct au_hfile *hfile; ++ ++ for (ull = 0; ull < opened; ull++) { ++ file = to_free[ull]; ++ if (unlikely(!file)) ++ break; ++ ++ /* AuDbg("%pD\n", file); */ ++ AuDebugOn(!d_is_dir(file->f_path.dentry)); ++ bfound = -1; ++ fidir = au_fi(file)->fi_hdir; ++ AuDebugOn(!fidir); ++ fi_write_lock(file); ++ bstart = au_fbstart(file); ++ bend = au_fbend_dir(file); ++ for (bindex = bstart; bindex <= bend; bindex++) { ++ hfile = fidir->fd_hfile + bindex; ++ if (!hfile->hf_file) ++ continue; ++ ++ if (hfile->hf_br->br_id == br_id) { ++ bfound = bindex; ++ break; ++ } ++ } ++ AuDebugOn(bfound < 0); ++ au_set_h_fptr(file, bfound, NULL); ++ if (bfound == bstart) { ++ for (bstart++; bstart <= bend; bstart++) ++ if (au_hf_dir(file, bstart)) { ++ au_set_fbstart(file, bstart); ++ break; ++ } ++ } ++ fi_write_unlock(file); ++ } ++} ++ ++static void au_br_do_del_brp(struct au_sbinfo *sbinfo, ++ const aufs_bindex_t bindex, ++ const aufs_bindex_t bend) ++{ ++ struct au_branch **brp, **p; ++ ++ AuRwMustWriteLock(&sbinfo->si_rwsem); ++ ++ brp = sbinfo->si_branch + bindex; ++ if (bindex < bend) ++ memmove(brp, brp + 1, sizeof(*brp) * (bend - bindex)); ++ sbinfo->si_branch[0 + bend] = NULL; ++ sbinfo->si_bend--; ++ ++ p = krealloc(sbinfo->si_branch, sizeof(*p) * bend, AuGFP_SBILIST); ++ if (p) ++ sbinfo->si_branch = p; ++ /* harmless error */ ++} ++ ++static void au_br_do_del_hdp(struct au_dinfo *dinfo, const aufs_bindex_t bindex, ++ const aufs_bindex_t bend) ++{ ++ struct au_hdentry *hdp, *p; ++ ++ AuRwMustWriteLock(&dinfo->di_rwsem); ++ ++ hdp = dinfo->di_hdentry; ++ if (bindex < bend) ++ memmove(hdp + bindex, hdp + bindex + 1, ++ sizeof(*hdp) * (bend - bindex)); ++ hdp[0 + bend].hd_dentry = NULL; ++ dinfo->di_bend--; ++ ++ p = krealloc(hdp, sizeof(*p) * bend, AuGFP_SBILIST); ++ if (p) ++ dinfo->di_hdentry = p; ++ /* harmless error */ ++} ++ ++static void au_br_do_del_hip(struct au_iinfo *iinfo, const aufs_bindex_t bindex, ++ const aufs_bindex_t bend) ++{ ++ struct au_hinode *hip, *p; ++ ++ AuRwMustWriteLock(&iinfo->ii_rwsem); ++ ++ hip = iinfo->ii_hinode + bindex; ++ if (bindex < bend) ++ memmove(hip, hip + 1, sizeof(*hip) * (bend - bindex)); ++ iinfo->ii_hinode[0 + bend].hi_inode = NULL; ++ au_hn_init(iinfo->ii_hinode + bend); ++ iinfo->ii_bend--; ++ ++ p = krealloc(iinfo->ii_hinode, sizeof(*p) * bend, AuGFP_SBILIST); ++ if (p) ++ iinfo->ii_hinode = p; ++ /* harmless error */ ++} ++ ++static void au_br_do_del(struct super_block *sb, aufs_bindex_t bindex, ++ struct au_branch *br) ++{ ++ aufs_bindex_t bend; ++ struct au_sbinfo *sbinfo; ++ struct dentry *root, *h_root; ++ struct inode *inode, *h_inode; ++ struct au_hinode *hinode; ++ ++ SiMustWriteLock(sb); ++ ++ root = sb->s_root; ++ inode = root->d_inode; ++ sbinfo = au_sbi(sb); ++ bend = sbinfo->si_bend; ++ ++ h_root = au_h_dptr(root, bindex); ++ hinode = au_hi(inode, bindex); ++ h_inode = au_igrab(hinode->hi_inode); ++ au_hiput(hinode); ++ ++ au_sbilist_lock(); ++ au_br_do_del_brp(sbinfo, bindex, bend); ++ au_br_do_del_hdp(au_di(root), bindex, bend); ++ au_br_do_del_hip(au_ii(inode), bindex, bend); ++ au_sbilist_unlock(); ++ ++ dput(h_root); ++ iput(h_inode); ++ au_br_do_free(br); ++} ++ ++static unsigned long long empty_cb(void *array, unsigned long long max, ++ void *arg) ++{ ++ return max; ++} ++ ++int au_br_del(struct super_block *sb, struct au_opt_del *del, int remount) ++{ ++ int err, rerr, i; ++ unsigned long long opened; ++ unsigned int mnt_flags; ++ aufs_bindex_t bindex, bend, br_id; ++ unsigned char do_wh, verbose; ++ struct au_branch *br; ++ struct au_wbr *wbr; ++ struct dentry *root; ++ struct file **to_free; ++ ++ err = 0; ++ opened = 0; ++ to_free = NULL; ++ root = sb->s_root; ++ bindex = au_find_dbindex(root, del->h_path.dentry); ++ if (bindex < 0) { ++ if (remount) ++ goto out; /* success */ ++ err = -ENOENT; ++ pr_err("%s no such branch\n", del->pathname); ++ goto out; ++ } ++ AuDbg("bindex b%d\n", bindex); ++ ++ err = -EBUSY; ++ mnt_flags = au_mntflags(sb); ++ verbose = !!au_opt_test(mnt_flags, VERBOSE); ++ bend = au_sbend(sb); ++ if (unlikely(!bend)) { ++ AuVerbose(verbose, "no more branches left\n"); ++ goto out; ++ } ++ br = au_sbr(sb, bindex); ++ AuDebugOn(!path_equal(&br->br_path, &del->h_path)); ++ ++ br_id = br->br_id; ++ opened = atomic_read(&br->br_count); ++ if (unlikely(opened)) { ++ to_free = au_array_alloc(&opened, empty_cb, NULL); ++ err = PTR_ERR(to_free); ++ if (IS_ERR(to_free)) ++ goto out; ++ ++ err = test_file_busy(sb, br_id, to_free, opened); ++ if (unlikely(err)) { ++ AuVerbose(verbose, "%llu file(s) opened\n", opened); ++ goto out; ++ } ++ } ++ ++ wbr = br->br_wbr; ++ do_wh = wbr && (wbr->wbr_whbase || wbr->wbr_plink || wbr->wbr_orph); ++ if (do_wh) { ++ /* instead of WbrWhMustWriteLock(wbr) */ ++ SiMustWriteLock(sb); ++ for (i = 0; i < AuBrWh_Last; i++) { ++ dput(wbr->wbr_wh[i]); ++ wbr->wbr_wh[i] = NULL; ++ } ++ } ++ ++ err = test_children_busy(root, bindex, verbose); ++ if (unlikely(err)) { ++ if (do_wh) ++ goto out_wh; ++ goto out; ++ } ++ ++ err = 0; ++ if (to_free) { ++ /* ++ * now we confirmed the branch is deletable. ++ * let's free the remaining opened dirs on the branch. ++ */ ++ di_write_unlock(root); ++ br_del_file(to_free, opened, br_id); ++ di_write_lock_child(root); ++ } ++ ++ if (!remount) ++ au_br_do_del(sb, bindex, br); ++ else { ++ sysaufs_brs_del(sb, bindex); ++ au_br_do_del(sb, bindex, br); ++ sysaufs_brs_add(sb, bindex); ++ } ++ ++ if (!bindex) { ++ au_cpup_attr_all(root->d_inode, /*force*/1); ++ sb->s_maxbytes = au_sbr_sb(sb, 0)->s_maxbytes; ++ } else ++ au_sub_nlink(root->d_inode, del->h_path.dentry->d_inode); ++ if (au_opt_test(mnt_flags, PLINK)) ++ au_plink_half_refresh(sb, br_id); ++ ++ if (au_xino_brid(sb) == br_id) ++ au_xino_brid_set(sb, -1); ++ goto out; /* success */ ++ ++out_wh: ++ /* revert */ ++ rerr = au_br_init_wh(sb, br, br->br_perm); ++ if (rerr) ++ pr_warn("failed re-creating base whiteout, %s. (%d)\n", ++ del->pathname, rerr); ++out: ++ if (to_free) ++ au_farray_free(to_free, opened); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_ibusy(struct super_block *sb, struct aufs_ibusy __user *arg) ++{ ++ int err; ++ aufs_bindex_t bstart, bend; ++ struct aufs_ibusy ibusy; ++ struct inode *inode, *h_inode; ++ ++ err = -EPERM; ++ if (unlikely(!capable(CAP_SYS_ADMIN))) ++ goto out; ++ ++ err = copy_from_user(&ibusy, arg, sizeof(ibusy)); ++ if (!err) ++ err = !access_ok(VERIFY_WRITE, &arg->h_ino, sizeof(arg->h_ino)); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ goto out; ++ } ++ ++ err = -EINVAL; ++ si_read_lock(sb, AuLock_FLUSH); ++ if (unlikely(ibusy.bindex < 0 || ibusy.bindex > au_sbend(sb))) ++ goto out_unlock; ++ ++ err = 0; ++ ibusy.h_ino = 0; /* invalid */ ++ inode = ilookup(sb, ibusy.ino); ++ if (!inode ++ || inode->i_ino == AUFS_ROOT_INO ++ || is_bad_inode(inode)) ++ goto out_unlock; ++ ++ ii_read_lock_child(inode); ++ bstart = au_ibstart(inode); ++ bend = au_ibend(inode); ++ if (bstart <= ibusy.bindex && ibusy.bindex <= bend) { ++ h_inode = au_h_iptr(inode, ibusy.bindex); ++ if (h_inode && au_test_ibusy(inode, bstart, bend)) ++ ibusy.h_ino = h_inode->i_ino; ++ } ++ ii_read_unlock(inode); ++ iput(inode); ++ ++out_unlock: ++ si_read_unlock(sb); ++ if (!err) { ++ err = __put_user(ibusy.h_ino, &arg->h_ino); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ } ++ } ++out: ++ return err; ++} ++ ++long au_ibusy_ioctl(struct file *file, unsigned long arg) ++{ ++ return au_ibusy(file->f_dentry->d_sb, (void __user *)arg); ++} ++ ++#ifdef CONFIG_COMPAT ++long au_ibusy_compat_ioctl(struct file *file, unsigned long arg) ++{ ++ return au_ibusy(file->f_dentry->d_sb, compat_ptr(arg)); ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * change a branch permission ++ */ ++ ++static void au_warn_ima(void) ++{ ++#ifdef CONFIG_IMA ++ /* since it doesn't support mark_files_ro() */ ++ AuWarn1("RW -> RO makes IMA to produce wrong message\n"); ++#endif ++} ++ ++static int do_need_sigen_inc(int a, int b) ++{ ++ return au_br_whable(a) && !au_br_whable(b); ++} ++ ++static int need_sigen_inc(int old, int new) ++{ ++ return do_need_sigen_inc(old, new) ++ || do_need_sigen_inc(new, old); ++} ++ ++static int au_br_mod_files_ro(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ int err, do_warn; ++ unsigned int mnt_flags; ++ unsigned long long ull, max; ++ aufs_bindex_t br_id; ++ unsigned char verbose, writer; ++ struct file *file, *hf, **array; ++ struct inode *inode; ++ struct au_hfile *hfile; ++ ++ mnt_flags = au_mntflags(sb); ++ verbose = !!au_opt_test(mnt_flags, VERBOSE); ++ ++ array = au_farray_alloc(sb, &max); ++ err = PTR_ERR(array); ++ if (IS_ERR(array)) ++ goto out; ++ ++ do_warn = 0; ++ br_id = au_sbr_id(sb, bindex); ++ for (ull = 0; ull < max; ull++) { ++ file = array[ull]; ++ if (unlikely(!file)) ++ break; ++ ++ /* AuDbg("%pD\n", file); */ ++ fi_read_lock(file); ++ if (unlikely(au_test_mmapped(file))) { ++ err = -EBUSY; ++ AuVerbose(verbose, "mmapped %pD\n", file); ++ AuDbgFile(file); ++ FiMustNoWaiters(file); ++ fi_read_unlock(file); ++ goto out_array; ++ } ++ ++ inode = file_inode(file); ++ hfile = &au_fi(file)->fi_htop; ++ hf = hfile->hf_file; ++ if (!S_ISREG(inode->i_mode) ++ || !(file->f_mode & FMODE_WRITE) ++ || hfile->hf_br->br_id != br_id ++ || !(hf->f_mode & FMODE_WRITE)) ++ array[ull] = NULL; ++ else { ++ do_warn = 1; ++ get_file(file); ++ } ++ ++ FiMustNoWaiters(file); ++ fi_read_unlock(file); ++ fput(file); ++ } ++ ++ err = 0; ++ if (do_warn) ++ au_warn_ima(); ++ ++ for (ull = 0; ull < max; ull++) { ++ file = array[ull]; ++ if (!file) ++ continue; ++ ++ /* todo: already flushed? */ ++ /* ++ * fs/super.c:mark_files_ro() is gone, but aufs keeps its ++ * approach which resets f_mode and calls mnt_drop_write() and ++ * file_release_write() for each file, because the branch ++ * attribute in aufs world is totally different from the native ++ * fs rw/ro mode. ++ */ ++ /* fi_read_lock(file); */ ++ hfile = &au_fi(file)->fi_htop; ++ hf = hfile->hf_file; ++ /* fi_read_unlock(file); */ ++ spin_lock(&hf->f_lock); ++ writer = !!(hf->f_mode & FMODE_WRITER); ++ hf->f_mode &= ~(FMODE_WRITE | FMODE_WRITER); ++ spin_unlock(&hf->f_lock); ++ if (writer) { ++ put_write_access(file_inode(hf)); ++ __mnt_drop_write(hf->f_path.mnt); ++ } ++ } ++ ++out_array: ++ au_farray_free(array, max); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_br_mod(struct super_block *sb, struct au_opt_mod *mod, int remount, ++ int *do_refresh) ++{ ++ int err, rerr; ++ aufs_bindex_t bindex; ++ struct dentry *root; ++ struct au_branch *br; ++ struct au_br_fhsm *bf; ++ ++ root = sb->s_root; ++ bindex = au_find_dbindex(root, mod->h_root); ++ if (bindex < 0) { ++ if (remount) ++ return 0; /* success */ ++ err = -ENOENT; ++ pr_err("%s no such branch\n", mod->path); ++ goto out; ++ } ++ AuDbg("bindex b%d\n", bindex); ++ ++ err = test_br(mod->h_root->d_inode, mod->perm, mod->path); ++ if (unlikely(err)) ++ goto out; ++ ++ br = au_sbr(sb, bindex); ++ AuDebugOn(mod->h_root != au_br_dentry(br)); ++ if (br->br_perm == mod->perm) ++ return 0; /* success */ ++ ++ /* pre-allocate for non-fhsm --> fhsm */ ++ bf = NULL; ++ if (!au_br_fhsm(br->br_perm) && au_br_fhsm(mod->perm)) { ++ err = au_fhsm_br_alloc(br); ++ if (unlikely(err)) ++ goto out; ++ bf = br->br_fhsm; ++ br->br_fhsm = NULL; ++ } ++ ++ if (au_br_writable(br->br_perm)) { ++ /* remove whiteout base */ ++ err = au_br_init_wh(sb, br, mod->perm); ++ if (unlikely(err)) ++ goto out_bf; ++ ++ if (!au_br_writable(mod->perm)) { ++ /* rw --> ro, file might be mmapped */ ++ DiMustNoWaiters(root); ++ IiMustNoWaiters(root->d_inode); ++ di_write_unlock(root); ++ err = au_br_mod_files_ro(sb, bindex); ++ /* aufs_write_lock() calls ..._child() */ ++ di_write_lock_child(root); ++ ++ if (unlikely(err)) { ++ rerr = -ENOMEM; ++ br->br_wbr = kzalloc(sizeof(*br->br_wbr), ++ GFP_NOFS); ++ if (br->br_wbr) ++ rerr = au_wbr_init(br, sb, br->br_perm); ++ if (unlikely(rerr)) { ++ AuIOErr("nested error %d (%d)\n", ++ rerr, err); ++ br->br_perm = mod->perm; ++ } ++ } ++ } ++ } else if (au_br_writable(mod->perm)) { ++ /* ro --> rw */ ++ err = -ENOMEM; ++ br->br_wbr = kzalloc(sizeof(*br->br_wbr), GFP_NOFS); ++ if (br->br_wbr) { ++ err = au_wbr_init(br, sb, mod->perm); ++ if (unlikely(err)) { ++ kfree(br->br_wbr); ++ br->br_wbr = NULL; ++ } ++ } ++ } ++ if (unlikely(err)) ++ goto out_bf; ++ ++ if (au_br_fhsm(br->br_perm)) { ++ if (!au_br_fhsm(mod->perm)) { ++ /* fhsm --> non-fhsm */ ++ au_br_fhsm_fin(br->br_fhsm); ++ kfree(br->br_fhsm); ++ br->br_fhsm = NULL; ++ } ++ } else if (au_br_fhsm(mod->perm)) ++ /* non-fhsm --> fhsm */ ++ br->br_fhsm = bf; ++ ++ *do_refresh |= need_sigen_inc(br->br_perm, mod->perm); ++ br->br_perm = mod->perm; ++ goto out; /* success */ ++ ++out_bf: ++ kfree(bf); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_br_stfs(struct au_branch *br, struct aufs_stfs *stfs) ++{ ++ int err; ++ struct kstatfs kstfs; ++ ++ err = vfs_statfs(&br->br_path, &kstfs); ++ if (!err) { ++ stfs->f_blocks = kstfs.f_blocks; ++ stfs->f_bavail = kstfs.f_bavail; ++ stfs->f_files = kstfs.f_files; ++ stfs->f_ffree = kstfs.f_ffree; ++ } ++ ++ return err; ++} +diff --git a/fs/aufs/branch.h b/fs/aufs/branch.h +new file mode 100644 +index 0000000..6ae006e +--- /dev/null ++++ b/fs/aufs/branch.h +@@ -0,0 +1,279 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * branch filesystems and xino for them ++ */ ++ ++#ifndef __AUFS_BRANCH_H__ ++#define __AUFS_BRANCH_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include "dynop.h" ++#include "rwsem.h" ++#include "super.h" ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* a xino file */ ++struct au_xino_file { ++ struct file *xi_file; ++ struct mutex xi_nondir_mtx; ++ ++ /* todo: make xino files an array to support huge inode number */ ++ ++#ifdef CONFIG_DEBUG_FS ++ struct dentry *xi_dbgaufs; ++#endif ++}; ++ ++/* File-based Hierarchical Storage Management */ ++struct au_br_fhsm { ++#ifdef CONFIG_AUFS_FHSM ++ struct mutex bf_lock; ++ unsigned long bf_jiffy; ++ struct aufs_stfs bf_stfs; ++ int bf_readable; ++#endif ++}; ++ ++/* members for writable branch only */ ++enum {AuBrWh_BASE, AuBrWh_PLINK, AuBrWh_ORPH, AuBrWh_Last}; ++struct au_wbr { ++ struct au_rwsem wbr_wh_rwsem; ++ struct dentry *wbr_wh[AuBrWh_Last]; ++ atomic_t wbr_wh_running; ++#define wbr_whbase wbr_wh[AuBrWh_BASE] /* whiteout base */ ++#define wbr_plink wbr_wh[AuBrWh_PLINK] /* pseudo-link dir */ ++#define wbr_orph wbr_wh[AuBrWh_ORPH] /* dir for orphans */ ++ ++ /* mfs mode */ ++ unsigned long long wbr_bytes; ++}; ++ ++/* ext2 has 3 types of operations at least, ext3 has 4 */ ++#define AuBrDynOp (AuDyLast * 4) ++ ++#ifdef CONFIG_AUFS_HFSNOTIFY ++/* support for asynchronous destruction */ ++struct au_br_hfsnotify { ++ struct fsnotify_group *hfsn_group; ++}; ++#endif ++ ++/* sysfs entries */ ++struct au_brsysfs { ++ char name[16]; ++ struct attribute attr; ++}; ++ ++enum { ++ AuBrSysfs_BR, ++ AuBrSysfs_BRID, ++ AuBrSysfs_Last ++}; ++ ++/* protected by superblock rwsem */ ++struct au_branch { ++ struct au_xino_file br_xino; ++ ++ aufs_bindex_t br_id; ++ ++ int br_perm; ++ struct path br_path; ++ spinlock_t br_dykey_lock; ++ struct au_dykey *br_dykey[AuBrDynOp]; ++ atomic_t br_count; ++ ++ struct au_wbr *br_wbr; ++ struct au_br_fhsm *br_fhsm; ++ ++ /* xino truncation */ ++ atomic_t br_xino_running; ++ ++#ifdef CONFIG_AUFS_HFSNOTIFY ++ struct au_br_hfsnotify *br_hfsn; ++#endif ++ ++#ifdef CONFIG_SYSFS ++ /* entries under sysfs per mount-point */ ++ struct au_brsysfs br_sysfs[AuBrSysfs_Last]; ++#endif ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct vfsmount *au_br_mnt(struct au_branch *br) ++{ ++ return br->br_path.mnt; ++} ++ ++static inline struct dentry *au_br_dentry(struct au_branch *br) ++{ ++ return br->br_path.dentry; ++} ++ ++static inline struct super_block *au_br_sb(struct au_branch *br) ++{ ++ return au_br_mnt(br)->mnt_sb; ++} ++ ++static inline int au_br_rdonly(struct au_branch *br) ++{ ++ return ((au_br_sb(br)->s_flags & MS_RDONLY) ++ || !au_br_writable(br->br_perm)) ++ ? -EROFS : 0; ++} ++ ++static inline int au_br_hnotifyable(int brperm __maybe_unused) ++{ ++#ifdef CONFIG_AUFS_HNOTIFY ++ return !(brperm & AuBrPerm_RR); ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_br_test_oflag(int oflag, struct au_branch *br) ++{ ++ int err, exec_flag; ++ ++ err = 0; ++ exec_flag = oflag & __FMODE_EXEC; ++ if (unlikely(exec_flag && (au_br_mnt(br)->mnt_flags & MNT_NOEXEC))) ++ err = -EACCES; ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* branch.c */ ++struct au_sbinfo; ++void au_br_free(struct au_sbinfo *sinfo); ++int au_br_index(struct super_block *sb, aufs_bindex_t br_id); ++struct au_opt_add; ++int au_br_add(struct super_block *sb, struct au_opt_add *add, int remount); ++struct au_opt_del; ++int au_br_del(struct super_block *sb, struct au_opt_del *del, int remount); ++long au_ibusy_ioctl(struct file *file, unsigned long arg); ++#ifdef CONFIG_COMPAT ++long au_ibusy_compat_ioctl(struct file *file, unsigned long arg); ++#endif ++struct au_opt_mod; ++int au_br_mod(struct super_block *sb, struct au_opt_mod *mod, int remount, ++ int *do_refresh); ++struct aufs_stfs; ++int au_br_stfs(struct au_branch *br, struct aufs_stfs *stfs); ++ ++/* xino.c */ ++static const loff_t au_loff_max = LLONG_MAX; ++ ++int au_xib_trunc(struct super_block *sb); ++ssize_t xino_fread(au_readf_t func, struct file *file, void *buf, size_t size, ++ loff_t *pos); ++ssize_t xino_fwrite(au_writef_t func, struct file *file, void *buf, size_t size, ++ loff_t *pos); ++struct file *au_xino_create2(struct file *base_file, struct file *copy_src); ++struct file *au_xino_create(struct super_block *sb, char *fname, int silent); ++ino_t au_xino_new_ino(struct super_block *sb); ++void au_xino_delete_inode(struct inode *inode, const int unlinked); ++int au_xino_write(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ ino_t ino); ++int au_xino_read(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ ino_t *ino); ++int au_xino_br(struct super_block *sb, struct au_branch *br, ino_t hino, ++ struct file *base_file, int do_test); ++int au_xino_trunc(struct super_block *sb, aufs_bindex_t bindex); ++ ++struct au_opt_xino; ++int au_xino_set(struct super_block *sb, struct au_opt_xino *xino, int remount); ++void au_xino_clr(struct super_block *sb); ++struct file *au_xino_def(struct super_block *sb); ++int au_xino_path(struct seq_file *seq, struct file *file); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* Superblock to branch */ ++static inline ++aufs_bindex_t au_sbr_id(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ return au_sbr(sb, bindex)->br_id; ++} ++ ++static inline ++struct vfsmount *au_sbr_mnt(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ return au_br_mnt(au_sbr(sb, bindex)); ++} ++ ++static inline ++struct super_block *au_sbr_sb(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ return au_br_sb(au_sbr(sb, bindex)); ++} ++ ++static inline void au_sbr_put(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ atomic_dec(&au_sbr(sb, bindex)->br_count); ++} ++ ++static inline int au_sbr_perm(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ return au_sbr(sb, bindex)->br_perm; ++} ++ ++static inline int au_sbr_whable(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ return au_br_whable(au_sbr_perm(sb, bindex)); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * wbr_wh_read_lock, wbr_wh_write_lock ++ * wbr_wh_read_unlock, wbr_wh_write_unlock, wbr_wh_downgrade_lock ++ */ ++AuSimpleRwsemFuncs(wbr_wh, struct au_wbr *wbr, &wbr->wbr_wh_rwsem); ++ ++#define WbrWhMustNoWaiters(wbr) AuRwMustNoWaiters(&wbr->wbr_wh_rwsem) ++#define WbrWhMustAnyLock(wbr) AuRwMustAnyLock(&wbr->wbr_wh_rwsem) ++#define WbrWhMustWriteLock(wbr) AuRwMustWriteLock(&wbr->wbr_wh_rwsem) ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_FHSM ++static inline void au_br_fhsm_init(struct au_br_fhsm *brfhsm) ++{ ++ mutex_init(&brfhsm->bf_lock); ++ brfhsm->bf_jiffy = 0; ++ brfhsm->bf_readable = 0; ++} ++ ++static inline void au_br_fhsm_fin(struct au_br_fhsm *brfhsm) ++{ ++ mutex_destroy(&brfhsm->bf_lock); ++} ++#else ++AuStubVoid(au_br_fhsm_init, struct au_br_fhsm *brfhsm) ++AuStubVoid(au_br_fhsm_fin, struct au_br_fhsm *brfhsm) ++#endif ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_BRANCH_H__ */ +diff --git a/fs/aufs/conf.mk b/fs/aufs/conf.mk +new file mode 100644 +index 0000000..0bbb2d3 +--- /dev/null ++++ b/fs/aufs/conf.mk +@@ -0,0 +1,38 @@ ++ ++AuConfStr = CONFIG_AUFS_FS=${CONFIG_AUFS_FS} ++ ++define AuConf ++ifdef ${1} ++AuConfStr += ${1}=${${1}} ++endif ++endef ++ ++AuConfAll = BRANCH_MAX_127 BRANCH_MAX_511 BRANCH_MAX_1023 BRANCH_MAX_32767 \ ++ SBILIST \ ++ HNOTIFY HFSNOTIFY \ ++ EXPORT INO_T_64 \ ++ XATTR \ ++ FHSM \ ++ RDU \ ++ SHWH \ ++ BR_RAMFS \ ++ BR_FUSE POLL \ ++ BR_HFSPLUS \ ++ BDEV_LOOP \ ++ DEBUG MAGIC_SYSRQ ++$(foreach i, ${AuConfAll}, \ ++ $(eval $(call AuConf,CONFIG_AUFS_${i}))) ++ ++AuConfName = ${obj}/conf.str ++${AuConfName}.tmp: FORCE ++ @echo ${AuConfStr} | tr ' ' '\n' | sed -e 's/^/"/' -e 's/$$/\\n"/' > $@ ++${AuConfName}: ${AuConfName}.tmp ++ @diff -q $< $@ > /dev/null 2>&1 || { \ ++ echo ' GEN ' $@; \ ++ cp -p $< $@; \ ++ } ++FORCE: ++clean-files += ${AuConfName} ${AuConfName}.tmp ++${obj}/sysfs.o: ${AuConfName} ++ ++-include ${srctree}/${src}/conf_priv.mk +diff --git a/fs/aufs/cpup.c b/fs/aufs/cpup.c +new file mode 100644 +index 0000000..9d8b767 +--- /dev/null ++++ b/fs/aufs/cpup.c +@@ -0,0 +1,1368 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * copy-up functions, see wbr_policy.c for copy-down ++ */ ++ ++#include ++#include ++#include ++#include "aufs.h" ++ ++void au_cpup_attr_flags(struct inode *dst, unsigned int iflags) ++{ ++ const unsigned int mask = S_DEAD | S_SWAPFILE | S_PRIVATE ++ | S_NOATIME | S_NOCMTIME | S_AUTOMOUNT; ++ ++ BUILD_BUG_ON(sizeof(iflags) != sizeof(dst->i_flags)); ++ ++ dst->i_flags |= iflags & ~mask; ++ if (au_test_fs_notime(dst->i_sb)) ++ dst->i_flags |= S_NOATIME | S_NOCMTIME; ++} ++ ++void au_cpup_attr_timesizes(struct inode *inode) ++{ ++ struct inode *h_inode; ++ ++ h_inode = au_h_iptr(inode, au_ibstart(inode)); ++ fsstack_copy_attr_times(inode, h_inode); ++ fsstack_copy_inode_size(inode, h_inode); ++} ++ ++void au_cpup_attr_nlink(struct inode *inode, int force) ++{ ++ struct inode *h_inode; ++ struct super_block *sb; ++ aufs_bindex_t bindex, bend; ++ ++ sb = inode->i_sb; ++ bindex = au_ibstart(inode); ++ h_inode = au_h_iptr(inode, bindex); ++ if (!force ++ && !S_ISDIR(h_inode->i_mode) ++ && au_opt_test(au_mntflags(sb), PLINK) ++ && au_plink_test(inode)) ++ return; ++ ++ /* ++ * 0 can happen in revalidating. ++ * h_inode->i_mutex may not be held here, but it is harmless since once ++ * i_nlink reaches 0, it will never become positive except O_TMPFILE ++ * case. ++ * todo: O_TMPFILE+linkat(AT_SYMLINK_FOLLOW) bypassing aufs may cause ++ * the incorrect link count. ++ */ ++ set_nlink(inode, h_inode->i_nlink); ++ ++ /* ++ * fewer nlink makes find(1) noisy, but larger nlink doesn't. ++ * it may includes whplink directory. ++ */ ++ if (S_ISDIR(h_inode->i_mode)) { ++ bend = au_ibend(inode); ++ for (bindex++; bindex <= bend; bindex++) { ++ h_inode = au_h_iptr(inode, bindex); ++ if (h_inode) ++ au_add_nlink(inode, h_inode); ++ } ++ } ++} ++ ++void au_cpup_attr_changeable(struct inode *inode) ++{ ++ struct inode *h_inode; ++ ++ h_inode = au_h_iptr(inode, au_ibstart(inode)); ++ inode->i_mode = h_inode->i_mode; ++ inode->i_uid = h_inode->i_uid; ++ inode->i_gid = h_inode->i_gid; ++ au_cpup_attr_timesizes(inode); ++ au_cpup_attr_flags(inode, h_inode->i_flags); ++} ++ ++void au_cpup_igen(struct inode *inode, struct inode *h_inode) ++{ ++ struct au_iinfo *iinfo = au_ii(inode); ++ ++ IiMustWriteLock(inode); ++ ++ iinfo->ii_higen = h_inode->i_generation; ++ iinfo->ii_hsb1 = h_inode->i_sb; ++} ++ ++void au_cpup_attr_all(struct inode *inode, int force) ++{ ++ struct inode *h_inode; ++ ++ h_inode = au_h_iptr(inode, au_ibstart(inode)); ++ au_cpup_attr_changeable(inode); ++ if (inode->i_nlink > 0) ++ au_cpup_attr_nlink(inode, force); ++ inode->i_rdev = h_inode->i_rdev; ++ inode->i_blkbits = h_inode->i_blkbits; ++ au_cpup_igen(inode, h_inode); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* Note: dt_dentry and dt_h_dentry are not dget/dput-ed */ ++ ++/* keep the timestamps of the parent dir when cpup */ ++void au_dtime_store(struct au_dtime *dt, struct dentry *dentry, ++ struct path *h_path) ++{ ++ struct inode *h_inode; ++ ++ dt->dt_dentry = dentry; ++ dt->dt_h_path = *h_path; ++ h_inode = h_path->dentry->d_inode; ++ dt->dt_atime = h_inode->i_atime; ++ dt->dt_mtime = h_inode->i_mtime; ++ /* smp_mb(); */ ++} ++ ++void au_dtime_revert(struct au_dtime *dt) ++{ ++ struct iattr attr; ++ int err; ++ ++ attr.ia_atime = dt->dt_atime; ++ attr.ia_mtime = dt->dt_mtime; ++ attr.ia_valid = ATTR_FORCE | ATTR_MTIME | ATTR_MTIME_SET ++ | ATTR_ATIME | ATTR_ATIME_SET; ++ ++ /* no delegation since this is a directory */ ++ err = vfsub_notify_change(&dt->dt_h_path, &attr, /*delegated*/NULL); ++ if (unlikely(err)) ++ pr_warn("restoring timestamps failed(%d). ignored\n", err); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* internal use only */ ++struct au_cpup_reg_attr { ++ int valid; ++ struct kstat st; ++ unsigned int iflags; /* inode->i_flags */ ++}; ++ ++static noinline_for_stack ++int cpup_iattr(struct dentry *dst, aufs_bindex_t bindex, struct dentry *h_src, ++ struct au_cpup_reg_attr *h_src_attr) ++{ ++ int err, sbits, icex; ++ unsigned int mnt_flags; ++ unsigned char verbose; ++ struct iattr ia; ++ struct path h_path; ++ struct inode *h_isrc, *h_idst; ++ struct kstat *h_st; ++ struct au_branch *br; ++ ++ h_path.dentry = au_h_dptr(dst, bindex); ++ h_idst = h_path.dentry->d_inode; ++ br = au_sbr(dst->d_sb, bindex); ++ h_path.mnt = au_br_mnt(br); ++ h_isrc = h_src->d_inode; ++ ia.ia_valid = ATTR_FORCE | ATTR_UID | ATTR_GID ++ | ATTR_ATIME | ATTR_MTIME ++ | ATTR_ATIME_SET | ATTR_MTIME_SET; ++ if (h_src_attr && h_src_attr->valid) { ++ h_st = &h_src_attr->st; ++ ia.ia_uid = h_st->uid; ++ ia.ia_gid = h_st->gid; ++ ia.ia_atime = h_st->atime; ++ ia.ia_mtime = h_st->mtime; ++ if (h_idst->i_mode != h_st->mode ++ && !S_ISLNK(h_idst->i_mode)) { ++ ia.ia_valid |= ATTR_MODE; ++ ia.ia_mode = h_st->mode; ++ } ++ sbits = !!(h_st->mode & (S_ISUID | S_ISGID)); ++ au_cpup_attr_flags(h_idst, h_src_attr->iflags); ++ } else { ++ ia.ia_uid = h_isrc->i_uid; ++ ia.ia_gid = h_isrc->i_gid; ++ ia.ia_atime = h_isrc->i_atime; ++ ia.ia_mtime = h_isrc->i_mtime; ++ if (h_idst->i_mode != h_isrc->i_mode ++ && !S_ISLNK(h_idst->i_mode)) { ++ ia.ia_valid |= ATTR_MODE; ++ ia.ia_mode = h_isrc->i_mode; ++ } ++ sbits = !!(h_isrc->i_mode & (S_ISUID | S_ISGID)); ++ au_cpup_attr_flags(h_idst, h_isrc->i_flags); ++ } ++ /* no delegation since it is just created */ ++ err = vfsub_notify_change(&h_path, &ia, /*delegated*/NULL); ++ ++ /* is this nfs only? */ ++ if (!err && sbits && au_test_nfs(h_path.dentry->d_sb)) { ++ ia.ia_valid = ATTR_FORCE | ATTR_MODE; ++ ia.ia_mode = h_isrc->i_mode; ++ err = vfsub_notify_change(&h_path, &ia, /*delegated*/NULL); ++ } ++ ++ icex = br->br_perm & AuBrAttr_ICEX; ++ if (!err) { ++ mnt_flags = au_mntflags(dst->d_sb); ++ verbose = !!au_opt_test(mnt_flags, VERBOSE); ++ err = au_cpup_xattr(h_path.dentry, h_src, icex, verbose); ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_do_copy_file(struct file *dst, struct file *src, loff_t len, ++ char *buf, unsigned long blksize) ++{ ++ int err; ++ size_t sz, rbytes, wbytes; ++ unsigned char all_zero; ++ char *p, *zp; ++ struct mutex *h_mtx; ++ /* reduce stack usage */ ++ struct iattr *ia; ++ ++ zp = page_address(ZERO_PAGE(0)); ++ if (unlikely(!zp)) ++ return -ENOMEM; /* possible? */ ++ ++ err = 0; ++ all_zero = 0; ++ while (len) { ++ AuDbg("len %lld\n", len); ++ sz = blksize; ++ if (len < blksize) ++ sz = len; ++ ++ rbytes = 0; ++ /* todo: signal_pending? */ ++ while (!rbytes || err == -EAGAIN || err == -EINTR) { ++ rbytes = vfsub_read_k(src, buf, sz, &src->f_pos); ++ err = rbytes; ++ } ++ if (unlikely(err < 0)) ++ break; ++ ++ all_zero = 0; ++ if (len >= rbytes && rbytes == blksize) ++ all_zero = !memcmp(buf, zp, rbytes); ++ if (!all_zero) { ++ wbytes = rbytes; ++ p = buf; ++ while (wbytes) { ++ size_t b; ++ ++ b = vfsub_write_k(dst, p, wbytes, &dst->f_pos); ++ err = b; ++ /* todo: signal_pending? */ ++ if (unlikely(err == -EAGAIN || err == -EINTR)) ++ continue; ++ if (unlikely(err < 0)) ++ break; ++ wbytes -= b; ++ p += b; ++ } ++ if (unlikely(err < 0)) ++ break; ++ } else { ++ loff_t res; ++ ++ AuLabel(hole); ++ res = vfsub_llseek(dst, rbytes, SEEK_CUR); ++ err = res; ++ if (unlikely(res < 0)) ++ break; ++ } ++ len -= rbytes; ++ err = 0; ++ } ++ ++ /* the last block may be a hole */ ++ if (!err && all_zero) { ++ AuLabel(last hole); ++ ++ err = 1; ++ if (au_test_nfs(dst->f_dentry->d_sb)) { ++ /* nfs requires this step to make last hole */ ++ /* is this only nfs? */ ++ do { ++ /* todo: signal_pending? */ ++ err = vfsub_write_k(dst, "\0", 1, &dst->f_pos); ++ } while (err == -EAGAIN || err == -EINTR); ++ if (err == 1) ++ dst->f_pos--; ++ } ++ ++ if (err == 1) { ++ ia = (void *)buf; ++ ia->ia_size = dst->f_pos; ++ ia->ia_valid = ATTR_SIZE | ATTR_FILE; ++ ia->ia_file = dst; ++ h_mtx = &file_inode(dst)->i_mutex; ++ mutex_lock_nested(h_mtx, AuLsc_I_CHILD2); ++ /* no delegation since it is just created */ ++ err = vfsub_notify_change(&dst->f_path, ia, ++ /*delegated*/NULL); ++ mutex_unlock(h_mtx); ++ } ++ } ++ ++ return err; ++} ++ ++int au_copy_file(struct file *dst, struct file *src, loff_t len) ++{ ++ int err; ++ unsigned long blksize; ++ unsigned char do_kfree; ++ char *buf; ++ ++ err = -ENOMEM; ++ blksize = dst->f_dentry->d_sb->s_blocksize; ++ if (!blksize || PAGE_SIZE < blksize) ++ blksize = PAGE_SIZE; ++ AuDbg("blksize %lu\n", blksize); ++ do_kfree = (blksize != PAGE_SIZE && blksize >= sizeof(struct iattr *)); ++ if (do_kfree) ++ buf = kmalloc(blksize, GFP_NOFS); ++ else ++ buf = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!buf)) ++ goto out; ++ ++ if (len > (1 << 22)) ++ AuDbg("copying a large file %lld\n", (long long)len); ++ ++ src->f_pos = 0; ++ dst->f_pos = 0; ++ err = au_do_copy_file(dst, src, len, buf, blksize); ++ if (do_kfree) ++ kfree(buf); ++ else ++ free_page((unsigned long)buf); ++ ++out: ++ return err; ++} ++ ++/* ++ * to support a sparse file which is opened with O_APPEND, ++ * we need to close the file. ++ */ ++static int au_cp_regular(struct au_cp_generic *cpg) ++{ ++ int err, i; ++ enum { SRC, DST }; ++ struct { ++ aufs_bindex_t bindex; ++ unsigned int flags; ++ struct dentry *dentry; ++ int force_wr; ++ struct file *file; ++ void *label; ++ } *f, file[] = { ++ { ++ .bindex = cpg->bsrc, ++ .flags = O_RDONLY | O_NOATIME | O_LARGEFILE, ++ .label = &&out ++ }, ++ { ++ .bindex = cpg->bdst, ++ .flags = O_WRONLY | O_NOATIME | O_LARGEFILE, ++ .force_wr = !!au_ftest_cpup(cpg->flags, RWDST), ++ .label = &&out_src ++ } ++ }; ++ struct super_block *sb; ++ struct task_struct *tsk = current; ++ ++ /* bsrc branch can be ro/rw. */ ++ sb = cpg->dentry->d_sb; ++ f = file; ++ for (i = 0; i < 2; i++, f++) { ++ f->dentry = au_h_dptr(cpg->dentry, f->bindex); ++ f->file = au_h_open(cpg->dentry, f->bindex, f->flags, ++ /*file*/NULL, f->force_wr); ++ err = PTR_ERR(f->file); ++ if (IS_ERR(f->file)) ++ goto *f->label; ++ } ++ ++ /* try stopping to update while we copyup */ ++ IMustLock(file[SRC].dentry->d_inode); ++ err = au_copy_file(file[DST].file, file[SRC].file, cpg->len); ++ ++ /* i wonder if we had O_NO_DELAY_FPUT flag */ ++ if (tsk->flags & PF_KTHREAD) ++ __fput_sync(file[DST].file); ++ else { ++ WARN(1, "%pD\nPlease report this warning to aufs-users ML", ++ file[DST].file); ++ fput(file[DST].file); ++ /* ++ * too bad. ++ * we have to call both since we don't know which place the file ++ * was added to. ++ */ ++ task_work_run(); ++ flush_delayed_fput(); ++ } ++ au_sbr_put(sb, file[DST].bindex); ++ ++out_src: ++ fput(file[SRC].file); ++ au_sbr_put(sb, file[SRC].bindex); ++out: ++ return err; ++} ++ ++static int au_do_cpup_regular(struct au_cp_generic *cpg, ++ struct au_cpup_reg_attr *h_src_attr) ++{ ++ int err, rerr; ++ loff_t l; ++ struct path h_path; ++ struct inode *h_src_inode, *h_dst_inode; ++ ++ err = 0; ++ h_src_inode = au_h_iptr(cpg->dentry->d_inode, cpg->bsrc); ++ l = i_size_read(h_src_inode); ++ if (cpg->len == -1 || l < cpg->len) ++ cpg->len = l; ++ if (cpg->len) { ++ /* try stopping to update while we are referencing */ ++ mutex_lock_nested(&h_src_inode->i_mutex, AuLsc_I_CHILD); ++ au_pin_hdir_unlock(cpg->pin); ++ ++ h_path.dentry = au_h_dptr(cpg->dentry, cpg->bsrc); ++ h_path.mnt = au_sbr_mnt(cpg->dentry->d_sb, cpg->bsrc); ++ h_src_attr->iflags = h_src_inode->i_flags; ++ err = vfs_getattr(&h_path, &h_src_attr->st); ++ if (unlikely(err)) { ++ mutex_unlock(&h_src_inode->i_mutex); ++ goto out; ++ } ++ h_src_attr->valid = 1; ++ err = au_cp_regular(cpg); ++ mutex_unlock(&h_src_inode->i_mutex); ++ rerr = au_pin_hdir_relock(cpg->pin); ++ if (!err && rerr) ++ err = rerr; ++ } ++ if (!err && (h_src_inode->i_state & I_LINKABLE)) { ++ h_path.dentry = au_h_dptr(cpg->dentry, cpg->bdst); ++ h_dst_inode = h_path.dentry->d_inode; ++ spin_lock(&h_dst_inode->i_lock); ++ h_dst_inode->i_state |= I_LINKABLE; ++ spin_unlock(&h_dst_inode->i_lock); ++ } ++ ++out: ++ return err; ++} ++ ++static int au_do_cpup_symlink(struct path *h_path, struct dentry *h_src, ++ struct inode *h_dir) ++{ ++ int err, symlen; ++ mm_segment_t old_fs; ++ union { ++ char *k; ++ char __user *u; ++ } sym; ++ ++ err = -ENOSYS; ++ if (unlikely(!h_src->d_inode->i_op->readlink)) ++ goto out; ++ ++ err = -ENOMEM; ++ sym.k = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!sym.k)) ++ goto out; ++ ++ /* unnecessary to support mmap_sem since symlink is not mmap-able */ ++ old_fs = get_fs(); ++ set_fs(KERNEL_DS); ++ symlen = h_src->d_inode->i_op->readlink(h_src, sym.u, PATH_MAX); ++ err = symlen; ++ set_fs(old_fs); ++ ++ if (symlen > 0) { ++ sym.k[symlen] = 0; ++ err = vfsub_symlink(h_dir, h_path, sym.k); ++ } ++ free_page((unsigned long)sym.k); ++ ++out: ++ return err; ++} ++ ++/* ++ * regardless 'acl' option, reset all ACL. ++ * All ACL will be copied up later from the original entry on the lower branch. ++ */ ++static int au_reset_acl(struct inode *h_dir, struct path *h_path, umode_t mode) ++{ ++ int err; ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ ++ h_dentry = h_path->dentry; ++ h_inode = h_dentry->d_inode; ++ /* forget_all_cached_acls(h_inode)); */ ++ err = vfsub_removexattr(h_dentry, XATTR_NAME_POSIX_ACL_ACCESS); ++ AuTraceErr(err); ++ if (err == -EOPNOTSUPP) ++ err = 0; ++ if (!err) ++ err = vfsub_acl_chmod(h_inode, mode); ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_do_cpup_dir(struct au_cp_generic *cpg, struct dentry *dst_parent, ++ struct inode *h_dir, struct path *h_path) ++{ ++ int err; ++ struct inode *dir; ++ ++ err = vfsub_removexattr(h_path->dentry, XATTR_NAME_POSIX_ACL_DEFAULT); ++ AuTraceErr(err); ++ if (err == -EOPNOTSUPP) ++ err = 0; ++ if (unlikely(err)) ++ goto out; ++ ++ /* ++ * strange behaviour from the users view, ++ * particularry setattr case ++ */ ++ dir = dst_parent->d_inode; ++ if (au_ibstart(dir) == cpg->bdst) ++ au_cpup_attr_nlink(dir, /*force*/1); ++ au_cpup_attr_nlink(cpg->dentry->d_inode, /*force*/1); ++ ++out: ++ return err; ++} ++ ++static noinline_for_stack ++int cpup_entry(struct au_cp_generic *cpg, struct dentry *dst_parent, ++ struct au_cpup_reg_attr *h_src_attr) ++{ ++ int err; ++ umode_t mode; ++ unsigned int mnt_flags; ++ unsigned char isdir, isreg, force; ++ const unsigned char do_dt = !!au_ftest_cpup(cpg->flags, DTIME); ++ struct au_dtime dt; ++ struct path h_path; ++ struct dentry *h_src, *h_dst, *h_parent; ++ struct inode *h_inode, *h_dir; ++ struct super_block *sb; ++ ++ /* bsrc branch can be ro/rw. */ ++ h_src = au_h_dptr(cpg->dentry, cpg->bsrc); ++ h_inode = h_src->d_inode; ++ AuDebugOn(h_inode != au_h_iptr(cpg->dentry->d_inode, cpg->bsrc)); ++ ++ /* try stopping to be referenced while we are creating */ ++ h_dst = au_h_dptr(cpg->dentry, cpg->bdst); ++ if (au_ftest_cpup(cpg->flags, RENAME)) ++ AuDebugOn(strncmp(h_dst->d_name.name, AUFS_WH_PFX, ++ AUFS_WH_PFX_LEN)); ++ h_parent = h_dst->d_parent; /* dir inode is locked */ ++ h_dir = h_parent->d_inode; ++ IMustLock(h_dir); ++ AuDebugOn(h_parent != h_dst->d_parent); ++ ++ sb = cpg->dentry->d_sb; ++ h_path.mnt = au_sbr_mnt(sb, cpg->bdst); ++ if (do_dt) { ++ h_path.dentry = h_parent; ++ au_dtime_store(&dt, dst_parent, &h_path); ++ } ++ h_path.dentry = h_dst; ++ ++ isreg = 0; ++ isdir = 0; ++ mode = h_inode->i_mode; ++ switch (mode & S_IFMT) { ++ case S_IFREG: ++ isreg = 1; ++ err = vfsub_create(h_dir, &h_path, S_IRUSR | S_IWUSR, ++ /*want_excl*/true); ++ if (!err) ++ err = au_do_cpup_regular(cpg, h_src_attr); ++ break; ++ case S_IFDIR: ++ isdir = 1; ++ err = vfsub_mkdir(h_dir, &h_path, mode); ++ if (!err) ++ err = au_do_cpup_dir(cpg, dst_parent, h_dir, &h_path); ++ break; ++ case S_IFLNK: ++ err = au_do_cpup_symlink(&h_path, h_src, h_dir); ++ break; ++ case S_IFCHR: ++ case S_IFBLK: ++ AuDebugOn(!capable(CAP_MKNOD)); ++ /*FALLTHROUGH*/ ++ case S_IFIFO: ++ case S_IFSOCK: ++ err = vfsub_mknod(h_dir, &h_path, mode, h_inode->i_rdev); ++ break; ++ default: ++ AuIOErr("Unknown inode type 0%o\n", mode); ++ err = -EIO; ++ } ++ if (!err) ++ err = au_reset_acl(h_dir, &h_path, mode); ++ ++ mnt_flags = au_mntflags(sb); ++ if (!au_opt_test(mnt_flags, UDBA_NONE) ++ && !isdir ++ && au_opt_test(mnt_flags, XINO) ++ && (h_inode->i_nlink == 1 ++ || (h_inode->i_state & I_LINKABLE)) ++ /* todo: unnecessary? */ ++ /* && cpg->dentry->d_inode->i_nlink == 1 */ ++ && cpg->bdst < cpg->bsrc ++ && !au_ftest_cpup(cpg->flags, KEEPLINO)) ++ au_xino_write(sb, cpg->bsrc, h_inode->i_ino, /*ino*/0); ++ /* ignore this error */ ++ ++ if (!err) { ++ force = 0; ++ if (isreg) { ++ force = !!cpg->len; ++ if (cpg->len == -1) ++ force = !!i_size_read(h_inode); ++ } ++ au_fhsm_wrote(sb, cpg->bdst, force); ++ } ++ ++ if (do_dt) ++ au_dtime_revert(&dt); ++ return err; ++} ++ ++static int au_do_ren_after_cpup(struct au_cp_generic *cpg, struct path *h_path) ++{ ++ int err; ++ struct dentry *dentry, *h_dentry, *h_parent, *parent; ++ struct inode *h_dir; ++ aufs_bindex_t bdst; ++ ++ dentry = cpg->dentry; ++ bdst = cpg->bdst; ++ h_dentry = au_h_dptr(dentry, bdst); ++ if (!au_ftest_cpup(cpg->flags, OVERWRITE)) { ++ dget(h_dentry); ++ au_set_h_dptr(dentry, bdst, NULL); ++ err = au_lkup_neg(dentry, bdst, /*wh*/0); ++ if (!err) ++ h_path->dentry = dget(au_h_dptr(dentry, bdst)); ++ au_set_h_dptr(dentry, bdst, h_dentry); ++ } else { ++ err = 0; ++ parent = dget_parent(dentry); ++ h_parent = au_h_dptr(parent, bdst); ++ dput(parent); ++ h_path->dentry = vfsub_lkup_one(&dentry->d_name, h_parent); ++ if (IS_ERR(h_path->dentry)) ++ err = PTR_ERR(h_path->dentry); ++ } ++ if (unlikely(err)) ++ goto out; ++ ++ h_parent = h_dentry->d_parent; /* dir inode is locked */ ++ h_dir = h_parent->d_inode; ++ IMustLock(h_dir); ++ AuDbg("%pd %pd\n", h_dentry, h_path->dentry); ++ /* no delegation since it is just created */ ++ err = vfsub_rename(h_dir, h_dentry, h_dir, h_path, /*delegated*/NULL); ++ dput(h_path->dentry); ++ ++out: ++ return err; ++} ++ ++/* ++ * copyup the @dentry from @bsrc to @bdst. ++ * the caller must set the both of lower dentries. ++ * @len is for truncating when it is -1 copyup the entire file. ++ * in link/rename cases, @dst_parent may be different from the real one. ++ * basic->bsrc can be larger than basic->bdst. ++ */ ++static int au_cpup_single(struct au_cp_generic *cpg, struct dentry *dst_parent) ++{ ++ int err, rerr; ++ aufs_bindex_t old_ibstart; ++ unsigned char isdir, plink; ++ struct dentry *h_src, *h_dst, *h_parent; ++ struct inode *dst_inode, *h_dir, *inode, *delegated; ++ struct super_block *sb; ++ struct au_branch *br; ++ /* to reuduce stack size */ ++ struct { ++ struct au_dtime dt; ++ struct path h_path; ++ struct au_cpup_reg_attr h_src_attr; ++ } *a; ++ ++ err = -ENOMEM; ++ a = kmalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ a->h_src_attr.valid = 0; ++ ++ sb = cpg->dentry->d_sb; ++ br = au_sbr(sb, cpg->bdst); ++ a->h_path.mnt = au_br_mnt(br); ++ h_dst = au_h_dptr(cpg->dentry, cpg->bdst); ++ h_parent = h_dst->d_parent; /* dir inode is locked */ ++ h_dir = h_parent->d_inode; ++ IMustLock(h_dir); ++ ++ h_src = au_h_dptr(cpg->dentry, cpg->bsrc); ++ inode = cpg->dentry->d_inode; ++ ++ if (!dst_parent) ++ dst_parent = dget_parent(cpg->dentry); ++ else ++ dget(dst_parent); ++ ++ plink = !!au_opt_test(au_mntflags(sb), PLINK); ++ dst_inode = au_h_iptr(inode, cpg->bdst); ++ if (dst_inode) { ++ if (unlikely(!plink)) { ++ err = -EIO; ++ AuIOErr("hi%lu(i%lu) exists on b%d " ++ "but plink is disabled\n", ++ dst_inode->i_ino, inode->i_ino, cpg->bdst); ++ goto out_parent; ++ } ++ ++ if (dst_inode->i_nlink) { ++ const int do_dt = au_ftest_cpup(cpg->flags, DTIME); ++ ++ h_src = au_plink_lkup(inode, cpg->bdst); ++ err = PTR_ERR(h_src); ++ if (IS_ERR(h_src)) ++ goto out_parent; ++ if (unlikely(!h_src->d_inode)) { ++ err = -EIO; ++ AuIOErr("i%lu exists on b%d " ++ "but not pseudo-linked\n", ++ inode->i_ino, cpg->bdst); ++ dput(h_src); ++ goto out_parent; ++ } ++ ++ if (do_dt) { ++ a->h_path.dentry = h_parent; ++ au_dtime_store(&a->dt, dst_parent, &a->h_path); ++ } ++ ++ a->h_path.dentry = h_dst; ++ delegated = NULL; ++ err = vfsub_link(h_src, h_dir, &a->h_path, &delegated); ++ if (!err && au_ftest_cpup(cpg->flags, RENAME)) ++ err = au_do_ren_after_cpup(cpg, &a->h_path); ++ if (do_dt) ++ au_dtime_revert(&a->dt); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal link\n"); ++ iput(delegated); ++ } ++ dput(h_src); ++ goto out_parent; ++ } else ++ /* todo: cpup_wh_file? */ ++ /* udba work */ ++ au_update_ibrange(inode, /*do_put_zero*/1); ++ } ++ ++ isdir = S_ISDIR(inode->i_mode); ++ old_ibstart = au_ibstart(inode); ++ err = cpup_entry(cpg, dst_parent, &a->h_src_attr); ++ if (unlikely(err)) ++ goto out_rev; ++ dst_inode = h_dst->d_inode; ++ mutex_lock_nested(&dst_inode->i_mutex, AuLsc_I_CHILD2); ++ /* todo: necessary? */ ++ /* au_pin_hdir_unlock(cpg->pin); */ ++ ++ err = cpup_iattr(cpg->dentry, cpg->bdst, h_src, &a->h_src_attr); ++ if (unlikely(err)) { ++ /* todo: necessary? */ ++ /* au_pin_hdir_relock(cpg->pin); */ /* ignore an error */ ++ mutex_unlock(&dst_inode->i_mutex); ++ goto out_rev; ++ } ++ ++ if (cpg->bdst < old_ibstart) { ++ if (S_ISREG(inode->i_mode)) { ++ err = au_dy_iaop(inode, cpg->bdst, dst_inode); ++ if (unlikely(err)) { ++ /* ignore an error */ ++ /* au_pin_hdir_relock(cpg->pin); */ ++ mutex_unlock(&dst_inode->i_mutex); ++ goto out_rev; ++ } ++ } ++ au_set_ibstart(inode, cpg->bdst); ++ } else ++ au_set_ibend(inode, cpg->bdst); ++ au_set_h_iptr(inode, cpg->bdst, au_igrab(dst_inode), ++ au_hi_flags(inode, isdir)); ++ ++ /* todo: necessary? */ ++ /* err = au_pin_hdir_relock(cpg->pin); */ ++ mutex_unlock(&dst_inode->i_mutex); ++ if (unlikely(err)) ++ goto out_rev; ++ ++ if (!isdir ++ && (h_src->d_inode->i_nlink > 1 ++ || h_src->d_inode->i_state & I_LINKABLE) ++ && plink) ++ au_plink_append(inode, cpg->bdst, h_dst); ++ ++ if (au_ftest_cpup(cpg->flags, RENAME)) { ++ a->h_path.dentry = h_dst; ++ err = au_do_ren_after_cpup(cpg, &a->h_path); ++ } ++ if (!err) ++ goto out_parent; /* success */ ++ ++ /* revert */ ++out_rev: ++ a->h_path.dentry = h_parent; ++ au_dtime_store(&a->dt, dst_parent, &a->h_path); ++ a->h_path.dentry = h_dst; ++ rerr = 0; ++ if (h_dst->d_inode) { ++ if (!isdir) { ++ /* no delegation since it is just created */ ++ rerr = vfsub_unlink(h_dir, &a->h_path, ++ /*delegated*/NULL, /*force*/0); ++ } else ++ rerr = vfsub_rmdir(h_dir, &a->h_path); ++ } ++ au_dtime_revert(&a->dt); ++ if (rerr) { ++ AuIOErr("failed removing broken entry(%d, %d)\n", err, rerr); ++ err = -EIO; ++ } ++out_parent: ++ dput(dst_parent); ++ kfree(a); ++out: ++ return err; ++} ++ ++#if 0 /* reserved */ ++struct au_cpup_single_args { ++ int *errp; ++ struct au_cp_generic *cpg; ++ struct dentry *dst_parent; ++}; ++ ++static void au_call_cpup_single(void *args) ++{ ++ struct au_cpup_single_args *a = args; ++ ++ au_pin_hdir_acquire_nest(a->cpg->pin); ++ *a->errp = au_cpup_single(a->cpg, a->dst_parent); ++ au_pin_hdir_release(a->cpg->pin); ++} ++#endif ++ ++/* ++ * prevent SIGXFSZ in copy-up. ++ * testing CAP_MKNOD is for generic fs, ++ * but CAP_FSETID is for xfs only, currently. ++ */ ++static int au_cpup_sio_test(struct au_pin *pin, umode_t mode) ++{ ++ int do_sio; ++ struct super_block *sb; ++ struct inode *h_dir; ++ ++ do_sio = 0; ++ sb = au_pinned_parent(pin)->d_sb; ++ if (!au_wkq_test() ++ && (!au_sbi(sb)->si_plink_maint_pid ++ || au_plink_maint(sb, AuLock_NOPLM))) { ++ switch (mode & S_IFMT) { ++ case S_IFREG: ++ /* no condition about RLIMIT_FSIZE and the file size */ ++ do_sio = 1; ++ break; ++ case S_IFCHR: ++ case S_IFBLK: ++ do_sio = !capable(CAP_MKNOD); ++ break; ++ } ++ if (!do_sio) ++ do_sio = ((mode & (S_ISUID | S_ISGID)) ++ && !capable(CAP_FSETID)); ++ /* this workaround may be removed in the future */ ++ if (!do_sio) { ++ h_dir = au_pinned_h_dir(pin); ++ do_sio = h_dir->i_mode & S_ISVTX; ++ } ++ } ++ ++ return do_sio; ++} ++ ++#if 0 /* reserved */ ++int au_sio_cpup_single(struct au_cp_generic *cpg, struct dentry *dst_parent) ++{ ++ int err, wkq_err; ++ struct dentry *h_dentry; ++ ++ h_dentry = au_h_dptr(cpg->dentry, cpg->bsrc); ++ if (!au_cpup_sio_test(pin, h_dentry->d_inode->i_mode)) ++ err = au_cpup_single(cpg, dst_parent); ++ else { ++ struct au_cpup_single_args args = { ++ .errp = &err, ++ .cpg = cpg, ++ .dst_parent = dst_parent ++ }; ++ wkq_err = au_wkq_wait(au_call_cpup_single, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ ++ return err; ++} ++#endif ++ ++/* ++ * copyup the @dentry from the first active lower branch to @bdst, ++ * using au_cpup_single(). ++ */ ++static int au_cpup_simple(struct au_cp_generic *cpg) ++{ ++ int err; ++ unsigned int flags_orig; ++ struct dentry *dentry; ++ ++ AuDebugOn(cpg->bsrc < 0); ++ ++ dentry = cpg->dentry; ++ DiMustWriteLock(dentry); ++ ++ err = au_lkup_neg(dentry, cpg->bdst, /*wh*/1); ++ if (!err) { ++ flags_orig = cpg->flags; ++ au_fset_cpup(cpg->flags, RENAME); ++ err = au_cpup_single(cpg, NULL); ++ cpg->flags = flags_orig; ++ if (!err) ++ return 0; /* success */ ++ ++ /* revert */ ++ au_set_h_dptr(dentry, cpg->bdst, NULL); ++ au_set_dbstart(dentry, cpg->bsrc); ++ } ++ ++ return err; ++} ++ ++struct au_cpup_simple_args { ++ int *errp; ++ struct au_cp_generic *cpg; ++}; ++ ++static void au_call_cpup_simple(void *args) ++{ ++ struct au_cpup_simple_args *a = args; ++ ++ au_pin_hdir_acquire_nest(a->cpg->pin); ++ *a->errp = au_cpup_simple(a->cpg); ++ au_pin_hdir_release(a->cpg->pin); ++} ++ ++static int au_do_sio_cpup_simple(struct au_cp_generic *cpg) ++{ ++ int err, wkq_err; ++ struct dentry *dentry, *parent; ++ struct file *h_file; ++ struct inode *h_dir; ++ ++ dentry = cpg->dentry; ++ h_file = NULL; ++ if (au_ftest_cpup(cpg->flags, HOPEN)) { ++ AuDebugOn(cpg->bsrc < 0); ++ h_file = au_h_open_pre(dentry, cpg->bsrc, /*force_wr*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ } ++ ++ parent = dget_parent(dentry); ++ h_dir = au_h_iptr(parent->d_inode, cpg->bdst); ++ if (!au_test_h_perm_sio(h_dir, MAY_EXEC | MAY_WRITE) ++ && !au_cpup_sio_test(cpg->pin, dentry->d_inode->i_mode)) ++ err = au_cpup_simple(cpg); ++ else { ++ struct au_cpup_simple_args args = { ++ .errp = &err, ++ .cpg = cpg ++ }; ++ wkq_err = au_wkq_wait(au_call_cpup_simple, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ ++ dput(parent); ++ if (h_file) ++ au_h_open_post(dentry, cpg->bsrc, h_file); ++ ++out: ++ return err; ++} ++ ++int au_sio_cpup_simple(struct au_cp_generic *cpg) ++{ ++ aufs_bindex_t bsrc, bend; ++ struct dentry *dentry, *h_dentry; ++ ++ if (cpg->bsrc < 0) { ++ dentry = cpg->dentry; ++ bend = au_dbend(dentry); ++ for (bsrc = cpg->bdst + 1; bsrc <= bend; bsrc++) { ++ h_dentry = au_h_dptr(dentry, bsrc); ++ if (h_dentry) { ++ AuDebugOn(!h_dentry->d_inode); ++ break; ++ } ++ } ++ AuDebugOn(bsrc > bend); ++ cpg->bsrc = bsrc; ++ } ++ AuDebugOn(cpg->bsrc <= cpg->bdst); ++ return au_do_sio_cpup_simple(cpg); ++} ++ ++int au_sio_cpdown_simple(struct au_cp_generic *cpg) ++{ ++ AuDebugOn(cpg->bdst <= cpg->bsrc); ++ return au_do_sio_cpup_simple(cpg); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * copyup the deleted file for writing. ++ */ ++static int au_do_cpup_wh(struct au_cp_generic *cpg, struct dentry *wh_dentry, ++ struct file *file) ++{ ++ int err; ++ unsigned int flags_orig; ++ aufs_bindex_t bsrc_orig; ++ struct dentry *h_d_dst, *h_d_start; ++ struct au_dinfo *dinfo; ++ struct au_hdentry *hdp; ++ ++ dinfo = au_di(cpg->dentry); ++ AuRwMustWriteLock(&dinfo->di_rwsem); ++ ++ bsrc_orig = cpg->bsrc; ++ cpg->bsrc = dinfo->di_bstart; ++ hdp = dinfo->di_hdentry; ++ h_d_dst = hdp[0 + cpg->bdst].hd_dentry; ++ dinfo->di_bstart = cpg->bdst; ++ hdp[0 + cpg->bdst].hd_dentry = wh_dentry; ++ h_d_start = NULL; ++ if (file) { ++ h_d_start = hdp[0 + cpg->bsrc].hd_dentry; ++ hdp[0 + cpg->bsrc].hd_dentry = au_hf_top(file)->f_dentry; ++ } ++ flags_orig = cpg->flags; ++ cpg->flags = !AuCpup_DTIME; ++ err = au_cpup_single(cpg, /*h_parent*/NULL); ++ cpg->flags = flags_orig; ++ if (file) { ++ if (!err) ++ err = au_reopen_nondir(file); ++ hdp[0 + cpg->bsrc].hd_dentry = h_d_start; ++ } ++ hdp[0 + cpg->bdst].hd_dentry = h_d_dst; ++ dinfo->di_bstart = cpg->bsrc; ++ cpg->bsrc = bsrc_orig; ++ ++ return err; ++} ++ ++static int au_cpup_wh(struct au_cp_generic *cpg, struct file *file) ++{ ++ int err; ++ aufs_bindex_t bdst; ++ struct au_dtime dt; ++ struct dentry *dentry, *parent, *h_parent, *wh_dentry; ++ struct au_branch *br; ++ struct path h_path; ++ ++ dentry = cpg->dentry; ++ bdst = cpg->bdst; ++ br = au_sbr(dentry->d_sb, bdst); ++ parent = dget_parent(dentry); ++ h_parent = au_h_dptr(parent, bdst); ++ wh_dentry = au_whtmp_lkup(h_parent, br, &dentry->d_name); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out; ++ ++ h_path.dentry = h_parent; ++ h_path.mnt = au_br_mnt(br); ++ au_dtime_store(&dt, parent, &h_path); ++ err = au_do_cpup_wh(cpg, wh_dentry, file); ++ if (unlikely(err)) ++ goto out_wh; ++ ++ dget(wh_dentry); ++ h_path.dentry = wh_dentry; ++ if (!d_is_dir(wh_dentry)) { ++ /* no delegation since it is just created */ ++ err = vfsub_unlink(h_parent->d_inode, &h_path, ++ /*delegated*/NULL, /*force*/0); ++ } else ++ err = vfsub_rmdir(h_parent->d_inode, &h_path); ++ if (unlikely(err)) { ++ AuIOErr("failed remove copied-up tmp file %pd(%d)\n", ++ wh_dentry, err); ++ err = -EIO; ++ } ++ au_dtime_revert(&dt); ++ au_set_hi_wh(dentry->d_inode, bdst, wh_dentry); ++ ++out_wh: ++ dput(wh_dentry); ++out: ++ dput(parent); ++ return err; ++} ++ ++struct au_cpup_wh_args { ++ int *errp; ++ struct au_cp_generic *cpg; ++ struct file *file; ++}; ++ ++static void au_call_cpup_wh(void *args) ++{ ++ struct au_cpup_wh_args *a = args; ++ ++ au_pin_hdir_acquire_nest(a->cpg->pin); ++ *a->errp = au_cpup_wh(a->cpg, a->file); ++ au_pin_hdir_release(a->cpg->pin); ++} ++ ++int au_sio_cpup_wh(struct au_cp_generic *cpg, struct file *file) ++{ ++ int err, wkq_err; ++ aufs_bindex_t bdst; ++ struct dentry *dentry, *parent, *h_orph, *h_parent; ++ struct inode *dir, *h_dir, *h_tmpdir; ++ struct au_wbr *wbr; ++ struct au_pin wh_pin, *pin_orig; ++ ++ dentry = cpg->dentry; ++ bdst = cpg->bdst; ++ parent = dget_parent(dentry); ++ dir = parent->d_inode; ++ h_orph = NULL; ++ h_parent = NULL; ++ h_dir = au_igrab(au_h_iptr(dir, bdst)); ++ h_tmpdir = h_dir; ++ pin_orig = NULL; ++ if (!h_dir->i_nlink) { ++ wbr = au_sbr(dentry->d_sb, bdst)->br_wbr; ++ h_orph = wbr->wbr_orph; ++ ++ h_parent = dget(au_h_dptr(parent, bdst)); ++ au_set_h_dptr(parent, bdst, dget(h_orph)); ++ h_tmpdir = h_orph->d_inode; ++ au_set_h_iptr(dir, bdst, au_igrab(h_tmpdir), /*flags*/0); ++ ++ mutex_lock_nested(&h_tmpdir->i_mutex, AuLsc_I_PARENT3); ++ /* todo: au_h_open_pre()? */ ++ ++ pin_orig = cpg->pin; ++ au_pin_init(&wh_pin, dentry, bdst, AuLsc_DI_PARENT, ++ AuLsc_I_PARENT3, cpg->pin->udba, AuPin_DI_LOCKED); ++ cpg->pin = &wh_pin; ++ } ++ ++ if (!au_test_h_perm_sio(h_tmpdir, MAY_EXEC | MAY_WRITE) ++ && !au_cpup_sio_test(cpg->pin, dentry->d_inode->i_mode)) ++ err = au_cpup_wh(cpg, file); ++ else { ++ struct au_cpup_wh_args args = { ++ .errp = &err, ++ .cpg = cpg, ++ .file = file ++ }; ++ wkq_err = au_wkq_wait(au_call_cpup_wh, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ ++ if (h_orph) { ++ mutex_unlock(&h_tmpdir->i_mutex); ++ /* todo: au_h_open_post()? */ ++ au_set_h_iptr(dir, bdst, au_igrab(h_dir), /*flags*/0); ++ au_set_h_dptr(parent, bdst, h_parent); ++ AuDebugOn(!pin_orig); ++ cpg->pin = pin_orig; ++ } ++ iput(h_dir); ++ dput(parent); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * generic routine for both of copy-up and copy-down. ++ */ ++/* cf. revalidate function in file.c */ ++int au_cp_dirs(struct dentry *dentry, aufs_bindex_t bdst, ++ int (*cp)(struct dentry *dentry, aufs_bindex_t bdst, ++ struct au_pin *pin, ++ struct dentry *h_parent, void *arg), ++ void *arg) ++{ ++ int err; ++ struct au_pin pin; ++ struct dentry *d, *parent, *h_parent, *real_parent; ++ ++ err = 0; ++ parent = dget_parent(dentry); ++ if (IS_ROOT(parent)) ++ goto out; ++ ++ au_pin_init(&pin, dentry, bdst, AuLsc_DI_PARENT2, AuLsc_I_PARENT2, ++ au_opt_udba(dentry->d_sb), AuPin_MNT_WRITE); ++ ++ /* do not use au_dpage */ ++ real_parent = parent; ++ while (1) { ++ dput(parent); ++ parent = dget_parent(dentry); ++ h_parent = au_h_dptr(parent, bdst); ++ if (h_parent) ++ goto out; /* success */ ++ ++ /* find top dir which is necessary to cpup */ ++ do { ++ d = parent; ++ dput(parent); ++ parent = dget_parent(d); ++ di_read_lock_parent3(parent, !AuLock_IR); ++ h_parent = au_h_dptr(parent, bdst); ++ di_read_unlock(parent, !AuLock_IR); ++ } while (!h_parent); ++ ++ if (d != real_parent) ++ di_write_lock_child3(d); ++ ++ /* somebody else might create while we were sleeping */ ++ if (!au_h_dptr(d, bdst) || !au_h_dptr(d, bdst)->d_inode) { ++ if (au_h_dptr(d, bdst)) ++ au_update_dbstart(d); ++ ++ au_pin_set_dentry(&pin, d); ++ err = au_do_pin(&pin); ++ if (!err) { ++ err = cp(d, bdst, &pin, h_parent, arg); ++ au_unpin(&pin); ++ } ++ } ++ ++ if (d != real_parent) ++ di_write_unlock(d); ++ if (unlikely(err)) ++ break; ++ } ++ ++out: ++ dput(parent); ++ return err; ++} ++ ++static int au_cpup_dir(struct dentry *dentry, aufs_bindex_t bdst, ++ struct au_pin *pin, ++ struct dentry *h_parent __maybe_unused, ++ void *arg __maybe_unused) ++{ ++ struct au_cp_generic cpg = { ++ .dentry = dentry, ++ .bdst = bdst, ++ .bsrc = -1, ++ .len = 0, ++ .pin = pin, ++ .flags = AuCpup_DTIME ++ }; ++ return au_sio_cpup_simple(&cpg); ++} ++ ++int au_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst) ++{ ++ return au_cp_dirs(dentry, bdst, au_cpup_dir, NULL); ++} ++ ++int au_test_and_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst) ++{ ++ int err; ++ struct dentry *parent; ++ struct inode *dir; ++ ++ parent = dget_parent(dentry); ++ dir = parent->d_inode; ++ err = 0; ++ if (au_h_iptr(dir, bdst)) ++ goto out; ++ ++ di_read_unlock(parent, AuLock_IR); ++ di_write_lock_parent(parent); ++ /* someone else might change our inode while we were sleeping */ ++ if (!au_h_iptr(dir, bdst)) ++ err = au_cpup_dirs(dentry, bdst); ++ di_downgrade_lock(parent, AuLock_IR); ++ ++out: ++ dput(parent); ++ return err; ++} +diff --git a/fs/aufs/cpup.h b/fs/aufs/cpup.h +new file mode 100644 +index 0000000..7721429 +--- /dev/null ++++ b/fs/aufs/cpup.h +@@ -0,0 +1,94 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * copy-up/down functions ++ */ ++ ++#ifndef __AUFS_CPUP_H__ ++#define __AUFS_CPUP_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++ ++struct inode; ++struct file; ++struct au_pin; ++ ++void au_cpup_attr_flags(struct inode *dst, unsigned int iflags); ++void au_cpup_attr_timesizes(struct inode *inode); ++void au_cpup_attr_nlink(struct inode *inode, int force); ++void au_cpup_attr_changeable(struct inode *inode); ++void au_cpup_igen(struct inode *inode, struct inode *h_inode); ++void au_cpup_attr_all(struct inode *inode, int force); ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_cp_generic { ++ struct dentry *dentry; ++ aufs_bindex_t bdst, bsrc; ++ loff_t len; ++ struct au_pin *pin; ++ unsigned int flags; ++}; ++ ++/* cpup flags */ ++#define AuCpup_DTIME 1 /* do dtime_store/revert */ ++#define AuCpup_KEEPLINO (1 << 1) /* do not clear the lower xino, ++ for link(2) */ ++#define AuCpup_RENAME (1 << 2) /* rename after cpup */ ++#define AuCpup_HOPEN (1 << 3) /* call h_open_pre/post() in ++ cpup */ ++#define AuCpup_OVERWRITE (1 << 4) /* allow overwriting the ++ existing entry */ ++#define AuCpup_RWDST (1 << 5) /* force write target even if ++ the branch is marked as RO */ ++ ++#define au_ftest_cpup(flags, name) ((flags) & AuCpup_##name) ++#define au_fset_cpup(flags, name) \ ++ do { (flags) |= AuCpup_##name; } while (0) ++#define au_fclr_cpup(flags, name) \ ++ do { (flags) &= ~AuCpup_##name; } while (0) ++ ++int au_copy_file(struct file *dst, struct file *src, loff_t len); ++int au_sio_cpup_simple(struct au_cp_generic *cpg); ++int au_sio_cpdown_simple(struct au_cp_generic *cpg); ++int au_sio_cpup_wh(struct au_cp_generic *cpg, struct file *file); ++ ++int au_cp_dirs(struct dentry *dentry, aufs_bindex_t bdst, ++ int (*cp)(struct dentry *dentry, aufs_bindex_t bdst, ++ struct au_pin *pin, ++ struct dentry *h_parent, void *arg), ++ void *arg); ++int au_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst); ++int au_test_and_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* keep timestamps when copyup */ ++struct au_dtime { ++ struct dentry *dt_dentry; ++ struct path dt_h_path; ++ struct timespec dt_atime, dt_mtime; ++}; ++void au_dtime_store(struct au_dtime *dt, struct dentry *dentry, ++ struct path *h_path); ++void au_dtime_revert(struct au_dtime *dt); ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_CPUP_H__ */ +diff --git a/fs/aufs/dbgaufs.c b/fs/aufs/dbgaufs.c +new file mode 100644 +index 0000000..b4fdc25 +--- /dev/null ++++ b/fs/aufs/dbgaufs.c +@@ -0,0 +1,432 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * debugfs interface ++ */ ++ ++#include ++#include "aufs.h" ++ ++#ifndef CONFIG_SYSFS ++#error DEBUG_FS depends upon SYSFS ++#endif ++ ++static struct dentry *dbgaufs; ++static const mode_t dbgaufs_mode = S_IRUSR | S_IRGRP | S_IROTH; ++ ++/* 20 is max digits length of ulong 64 */ ++struct dbgaufs_arg { ++ int n; ++ char a[20 * 4]; ++}; ++ ++/* ++ * common function for all XINO files ++ */ ++static int dbgaufs_xi_release(struct inode *inode __maybe_unused, ++ struct file *file) ++{ ++ kfree(file->private_data); ++ return 0; ++} ++ ++static int dbgaufs_xi_open(struct file *xf, struct file *file, int do_fcnt) ++{ ++ int err; ++ struct kstat st; ++ struct dbgaufs_arg *p; ++ ++ err = -ENOMEM; ++ p = kmalloc(sizeof(*p), GFP_NOFS); ++ if (unlikely(!p)) ++ goto out; ++ ++ err = 0; ++ p->n = 0; ++ file->private_data = p; ++ if (!xf) ++ goto out; ++ ++ err = vfs_getattr(&xf->f_path, &st); ++ if (!err) { ++ if (do_fcnt) ++ p->n = snprintf ++ (p->a, sizeof(p->a), "%ld, %llux%lu %lld\n", ++ (long)file_count(xf), st.blocks, st.blksize, ++ (long long)st.size); ++ else ++ p->n = snprintf(p->a, sizeof(p->a), "%llux%lu %lld\n", ++ st.blocks, st.blksize, ++ (long long)st.size); ++ AuDebugOn(p->n >= sizeof(p->a)); ++ } else { ++ p->n = snprintf(p->a, sizeof(p->a), "err %d\n", err); ++ err = 0; ++ } ++ ++out: ++ return err; ++ ++} ++ ++static ssize_t dbgaufs_xi_read(struct file *file, char __user *buf, ++ size_t count, loff_t *ppos) ++{ ++ struct dbgaufs_arg *p; ++ ++ p = file->private_data; ++ return simple_read_from_buffer(buf, count, ppos, p->a, p->n); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct dbgaufs_plink_arg { ++ int n; ++ char a[]; ++}; ++ ++static int dbgaufs_plink_release(struct inode *inode __maybe_unused, ++ struct file *file) ++{ ++ free_page((unsigned long)file->private_data); ++ return 0; ++} ++ ++static int dbgaufs_plink_open(struct inode *inode, struct file *file) ++{ ++ int err, i, limit; ++ unsigned long n, sum; ++ struct dbgaufs_plink_arg *p; ++ struct au_sbinfo *sbinfo; ++ struct super_block *sb; ++ struct au_sphlhead *sphl; ++ ++ err = -ENOMEM; ++ p = (void *)get_zeroed_page(GFP_NOFS); ++ if (unlikely(!p)) ++ goto out; ++ ++ err = -EFBIG; ++ sbinfo = inode->i_private; ++ sb = sbinfo->si_sb; ++ si_noflush_read_lock(sb); ++ if (au_opt_test(au_mntflags(sb), PLINK)) { ++ limit = PAGE_SIZE - sizeof(p->n); ++ ++ /* the number of buckets */ ++ n = snprintf(p->a + p->n, limit, "%d\n", AuPlink_NHASH); ++ p->n += n; ++ limit -= n; ++ ++ sum = 0; ++ for (i = 0, sphl = sbinfo->si_plink; ++ i < AuPlink_NHASH; ++ i++, sphl++) { ++ n = au_sphl_count(sphl); ++ sum += n; ++ ++ n = snprintf(p->a + p->n, limit, "%lu ", n); ++ p->n += n; ++ limit -= n; ++ if (unlikely(limit <= 0)) ++ goto out_free; ++ } ++ p->a[p->n - 1] = '\n'; ++ ++ /* the sum of plinks */ ++ n = snprintf(p->a + p->n, limit, "%lu\n", sum); ++ p->n += n; ++ limit -= n; ++ if (unlikely(limit <= 0)) ++ goto out_free; ++ } else { ++#define str "1\n0\n0\n" ++ p->n = sizeof(str) - 1; ++ strcpy(p->a, str); ++#undef str ++ } ++ si_read_unlock(sb); ++ ++ err = 0; ++ file->private_data = p; ++ goto out; /* success */ ++ ++out_free: ++ free_page((unsigned long)p); ++out: ++ return err; ++} ++ ++static ssize_t dbgaufs_plink_read(struct file *file, char __user *buf, ++ size_t count, loff_t *ppos) ++{ ++ struct dbgaufs_plink_arg *p; ++ ++ p = file->private_data; ++ return simple_read_from_buffer(buf, count, ppos, p->a, p->n); ++} ++ ++static const struct file_operations dbgaufs_plink_fop = { ++ .owner = THIS_MODULE, ++ .open = dbgaufs_plink_open, ++ .release = dbgaufs_plink_release, ++ .read = dbgaufs_plink_read ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int dbgaufs_xib_open(struct inode *inode, struct file *file) ++{ ++ int err; ++ struct au_sbinfo *sbinfo; ++ struct super_block *sb; ++ ++ sbinfo = inode->i_private; ++ sb = sbinfo->si_sb; ++ si_noflush_read_lock(sb); ++ err = dbgaufs_xi_open(sbinfo->si_xib, file, /*do_fcnt*/0); ++ si_read_unlock(sb); ++ return err; ++} ++ ++static const struct file_operations dbgaufs_xib_fop = { ++ .owner = THIS_MODULE, ++ .open = dbgaufs_xib_open, ++ .release = dbgaufs_xi_release, ++ .read = dbgaufs_xi_read ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define DbgaufsXi_PREFIX "xi" ++ ++static int dbgaufs_xino_open(struct inode *inode, struct file *file) ++{ ++ int err; ++ long l; ++ struct au_sbinfo *sbinfo; ++ struct super_block *sb; ++ struct file *xf; ++ struct qstr *name; ++ ++ err = -ENOENT; ++ xf = NULL; ++ name = &file->f_dentry->d_name; ++ if (unlikely(name->len < sizeof(DbgaufsXi_PREFIX) ++ || memcmp(name->name, DbgaufsXi_PREFIX, ++ sizeof(DbgaufsXi_PREFIX) - 1))) ++ goto out; ++ err = kstrtol(name->name + sizeof(DbgaufsXi_PREFIX) - 1, 10, &l); ++ if (unlikely(err)) ++ goto out; ++ ++ sbinfo = inode->i_private; ++ sb = sbinfo->si_sb; ++ si_noflush_read_lock(sb); ++ if (l <= au_sbend(sb)) { ++ xf = au_sbr(sb, (aufs_bindex_t)l)->br_xino.xi_file; ++ err = dbgaufs_xi_open(xf, file, /*do_fcnt*/1); ++ } else ++ err = -ENOENT; ++ si_read_unlock(sb); ++ ++out: ++ return err; ++} ++ ++static const struct file_operations dbgaufs_xino_fop = { ++ .owner = THIS_MODULE, ++ .open = dbgaufs_xino_open, ++ .release = dbgaufs_xi_release, ++ .read = dbgaufs_xi_read ++}; ++ ++void dbgaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ aufs_bindex_t bend; ++ struct au_branch *br; ++ struct au_xino_file *xi; ++ ++ if (!au_sbi(sb)->si_dbgaufs) ++ return; ++ ++ bend = au_sbend(sb); ++ for (; bindex <= bend; bindex++) { ++ br = au_sbr(sb, bindex); ++ xi = &br->br_xino; ++ debugfs_remove(xi->xi_dbgaufs); ++ xi->xi_dbgaufs = NULL; ++ } ++} ++ ++void dbgaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ struct au_sbinfo *sbinfo; ++ struct dentry *parent; ++ struct au_branch *br; ++ struct au_xino_file *xi; ++ aufs_bindex_t bend; ++ char name[sizeof(DbgaufsXi_PREFIX) + 5]; /* "xi" bindex NULL */ ++ ++ sbinfo = au_sbi(sb); ++ parent = sbinfo->si_dbgaufs; ++ if (!parent) ++ return; ++ ++ bend = au_sbend(sb); ++ for (; bindex <= bend; bindex++) { ++ snprintf(name, sizeof(name), DbgaufsXi_PREFIX "%d", bindex); ++ br = au_sbr(sb, bindex); ++ xi = &br->br_xino; ++ AuDebugOn(xi->xi_dbgaufs); ++ xi->xi_dbgaufs = debugfs_create_file(name, dbgaufs_mode, parent, ++ sbinfo, &dbgaufs_xino_fop); ++ /* ignore an error */ ++ if (unlikely(!xi->xi_dbgaufs)) ++ AuWarn1("failed %s under debugfs\n", name); ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_EXPORT ++static int dbgaufs_xigen_open(struct inode *inode, struct file *file) ++{ ++ int err; ++ struct au_sbinfo *sbinfo; ++ struct super_block *sb; ++ ++ sbinfo = inode->i_private; ++ sb = sbinfo->si_sb; ++ si_noflush_read_lock(sb); ++ err = dbgaufs_xi_open(sbinfo->si_xigen, file, /*do_fcnt*/0); ++ si_read_unlock(sb); ++ return err; ++} ++ ++static const struct file_operations dbgaufs_xigen_fop = { ++ .owner = THIS_MODULE, ++ .open = dbgaufs_xigen_open, ++ .release = dbgaufs_xi_release, ++ .read = dbgaufs_xi_read ++}; ++ ++static int dbgaufs_xigen_init(struct au_sbinfo *sbinfo) ++{ ++ int err; ++ ++ /* ++ * This function is a dynamic '__init' function actually, ++ * so the tiny check for si_rwsem is unnecessary. ++ */ ++ /* AuRwMustWriteLock(&sbinfo->si_rwsem); */ ++ ++ err = -EIO; ++ sbinfo->si_dbgaufs_xigen = debugfs_create_file ++ ("xigen", dbgaufs_mode, sbinfo->si_dbgaufs, sbinfo, ++ &dbgaufs_xigen_fop); ++ if (sbinfo->si_dbgaufs_xigen) ++ err = 0; ++ ++ return err; ++} ++#else ++static int dbgaufs_xigen_init(struct au_sbinfo *sbinfo) ++{ ++ return 0; ++} ++#endif /* CONFIG_AUFS_EXPORT */ ++ ++/* ---------------------------------------------------------------------- */ ++ ++void dbgaufs_si_fin(struct au_sbinfo *sbinfo) ++{ ++ /* ++ * This function is a dynamic '__fin' function actually, ++ * so the tiny check for si_rwsem is unnecessary. ++ */ ++ /* AuRwMustWriteLock(&sbinfo->si_rwsem); */ ++ ++ debugfs_remove_recursive(sbinfo->si_dbgaufs); ++ sbinfo->si_dbgaufs = NULL; ++ kobject_put(&sbinfo->si_kobj); ++} ++ ++int dbgaufs_si_init(struct au_sbinfo *sbinfo) ++{ ++ int err; ++ char name[SysaufsSiNameLen]; ++ ++ /* ++ * This function is a dynamic '__init' function actually, ++ * so the tiny check for si_rwsem is unnecessary. ++ */ ++ /* AuRwMustWriteLock(&sbinfo->si_rwsem); */ ++ ++ err = -ENOENT; ++ if (!dbgaufs) { ++ AuErr1("/debug/aufs is uninitialized\n"); ++ goto out; ++ } ++ ++ err = -EIO; ++ sysaufs_name(sbinfo, name); ++ sbinfo->si_dbgaufs = debugfs_create_dir(name, dbgaufs); ++ if (unlikely(!sbinfo->si_dbgaufs)) ++ goto out; ++ kobject_get(&sbinfo->si_kobj); ++ ++ sbinfo->si_dbgaufs_xib = debugfs_create_file ++ ("xib", dbgaufs_mode, sbinfo->si_dbgaufs, sbinfo, ++ &dbgaufs_xib_fop); ++ if (unlikely(!sbinfo->si_dbgaufs_xib)) ++ goto out_dir; ++ ++ sbinfo->si_dbgaufs_plink = debugfs_create_file ++ ("plink", dbgaufs_mode, sbinfo->si_dbgaufs, sbinfo, ++ &dbgaufs_plink_fop); ++ if (unlikely(!sbinfo->si_dbgaufs_plink)) ++ goto out_dir; ++ ++ err = dbgaufs_xigen_init(sbinfo); ++ if (!err) ++ goto out; /* success */ ++ ++out_dir: ++ dbgaufs_si_fin(sbinfo); ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void dbgaufs_fin(void) ++{ ++ debugfs_remove(dbgaufs); ++} ++ ++int __init dbgaufs_init(void) ++{ ++ int err; ++ ++ err = -EIO; ++ dbgaufs = debugfs_create_dir(AUFS_NAME, NULL); ++ if (dbgaufs) ++ err = 0; ++ return err; ++} +diff --git a/fs/aufs/dbgaufs.h b/fs/aufs/dbgaufs.h +new file mode 100644 +index 0000000..d1e09bd +--- /dev/null ++++ b/fs/aufs/dbgaufs.h +@@ -0,0 +1,48 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * debugfs interface ++ */ ++ ++#ifndef __DBGAUFS_H__ ++#define __DBGAUFS_H__ ++ ++#ifdef __KERNEL__ ++ ++struct super_block; ++struct au_sbinfo; ++ ++#ifdef CONFIG_DEBUG_FS ++/* dbgaufs.c */ ++void dbgaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex); ++void dbgaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex); ++void dbgaufs_si_fin(struct au_sbinfo *sbinfo); ++int dbgaufs_si_init(struct au_sbinfo *sbinfo); ++void dbgaufs_fin(void); ++int __init dbgaufs_init(void); ++#else ++AuStubVoid(dbgaufs_brs_del, struct super_block *sb, aufs_bindex_t bindex) ++AuStubVoid(dbgaufs_brs_add, struct super_block *sb, aufs_bindex_t bindex) ++AuStubVoid(dbgaufs_si_fin, struct au_sbinfo *sbinfo) ++AuStubInt0(dbgaufs_si_init, struct au_sbinfo *sbinfo) ++AuStubVoid(dbgaufs_fin, void) ++AuStubInt0(__init dbgaufs_init, void) ++#endif /* CONFIG_DEBUG_FS */ ++ ++#endif /* __KERNEL__ */ ++#endif /* __DBGAUFS_H__ */ +diff --git a/fs/aufs/dcsub.c b/fs/aufs/dcsub.c +new file mode 100644 +index 0000000..832baa4 +--- /dev/null ++++ b/fs/aufs/dcsub.c +@@ -0,0 +1,224 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * sub-routines for dentry cache ++ */ ++ ++#include "aufs.h" ++ ++static void au_dpage_free(struct au_dpage *dpage) ++{ ++ int i; ++ struct dentry **p; ++ ++ p = dpage->dentries; ++ for (i = 0; i < dpage->ndentry; i++) ++ dput(*p++); ++ free_page((unsigned long)dpage->dentries); ++} ++ ++int au_dpages_init(struct au_dcsub_pages *dpages, gfp_t gfp) ++{ ++ int err; ++ void *p; ++ ++ err = -ENOMEM; ++ dpages->dpages = kmalloc(sizeof(*dpages->dpages), gfp); ++ if (unlikely(!dpages->dpages)) ++ goto out; ++ ++ p = (void *)__get_free_page(gfp); ++ if (unlikely(!p)) ++ goto out_dpages; ++ ++ dpages->dpages[0].ndentry = 0; ++ dpages->dpages[0].dentries = p; ++ dpages->ndpage = 1; ++ return 0; /* success */ ++ ++out_dpages: ++ kfree(dpages->dpages); ++out: ++ return err; ++} ++ ++void au_dpages_free(struct au_dcsub_pages *dpages) ++{ ++ int i; ++ struct au_dpage *p; ++ ++ p = dpages->dpages; ++ for (i = 0; i < dpages->ndpage; i++) ++ au_dpage_free(p++); ++ kfree(dpages->dpages); ++} ++ ++static int au_dpages_append(struct au_dcsub_pages *dpages, ++ struct dentry *dentry, gfp_t gfp) ++{ ++ int err, sz; ++ struct au_dpage *dpage; ++ void *p; ++ ++ dpage = dpages->dpages + dpages->ndpage - 1; ++ sz = PAGE_SIZE / sizeof(dentry); ++ if (unlikely(dpage->ndentry >= sz)) { ++ AuLabel(new dpage); ++ err = -ENOMEM; ++ sz = dpages->ndpage * sizeof(*dpages->dpages); ++ p = au_kzrealloc(dpages->dpages, sz, ++ sz + sizeof(*dpages->dpages), gfp); ++ if (unlikely(!p)) ++ goto out; ++ ++ dpages->dpages = p; ++ dpage = dpages->dpages + dpages->ndpage; ++ p = (void *)__get_free_page(gfp); ++ if (unlikely(!p)) ++ goto out; ++ ++ dpage->ndentry = 0; ++ dpage->dentries = p; ++ dpages->ndpage++; ++ } ++ ++ AuDebugOn(au_dcount(dentry) <= 0); ++ dpage->dentries[dpage->ndentry++] = dget_dlock(dentry); ++ return 0; /* success */ ++ ++out: ++ return err; ++} ++ ++/* todo: BAD approach */ ++/* copied from linux/fs/dcache.c */ ++enum d_walk_ret { ++ D_WALK_CONTINUE, ++ D_WALK_QUIT, ++ D_WALK_NORETRY, ++ D_WALK_SKIP, ++}; ++ ++extern void d_walk(struct dentry *parent, void *data, ++ enum d_walk_ret (*enter)(void *, struct dentry *), ++ void (*finish)(void *)); ++ ++struct ac_dpages_arg { ++ int err; ++ struct au_dcsub_pages *dpages; ++ struct super_block *sb; ++ au_dpages_test test; ++ void *arg; ++}; ++ ++static enum d_walk_ret au_call_dpages_append(void *_arg, struct dentry *dentry) ++{ ++ enum d_walk_ret ret; ++ struct ac_dpages_arg *arg = _arg; ++ ++ ret = D_WALK_CONTINUE; ++ if (dentry->d_sb == arg->sb ++ && !IS_ROOT(dentry) ++ && au_dcount(dentry) > 0 ++ && au_di(dentry) ++ && (!arg->test || arg->test(dentry, arg->arg))) { ++ arg->err = au_dpages_append(arg->dpages, dentry, GFP_ATOMIC); ++ if (unlikely(arg->err)) ++ ret = D_WALK_QUIT; ++ } ++ ++ return ret; ++} ++ ++int au_dcsub_pages(struct au_dcsub_pages *dpages, struct dentry *root, ++ au_dpages_test test, void *arg) ++{ ++ struct ac_dpages_arg args = { ++ .err = 0, ++ .dpages = dpages, ++ .sb = root->d_sb, ++ .test = test, ++ .arg = arg ++ }; ++ ++ d_walk(root, &args, au_call_dpages_append, NULL); ++ ++ return args.err; ++} ++ ++int au_dcsub_pages_rev(struct au_dcsub_pages *dpages, struct dentry *dentry, ++ int do_include, au_dpages_test test, void *arg) ++{ ++ int err; ++ ++ err = 0; ++ write_seqlock(&rename_lock); ++ spin_lock(&dentry->d_lock); ++ if (do_include ++ && au_dcount(dentry) > 0 ++ && (!test || test(dentry, arg))) ++ err = au_dpages_append(dpages, dentry, GFP_ATOMIC); ++ spin_unlock(&dentry->d_lock); ++ if (unlikely(err)) ++ goto out; ++ ++ /* ++ * RCU for vfsmount is unnecessary since this is a traverse in a single ++ * mount ++ */ ++ while (!IS_ROOT(dentry)) { ++ dentry = dentry->d_parent; /* rename_lock is locked */ ++ spin_lock(&dentry->d_lock); ++ if (au_dcount(dentry) > 0 ++ && (!test || test(dentry, arg))) ++ err = au_dpages_append(dpages, dentry, GFP_ATOMIC); ++ spin_unlock(&dentry->d_lock); ++ if (unlikely(err)) ++ break; ++ } ++ ++out: ++ write_sequnlock(&rename_lock); ++ return err; ++} ++ ++static inline int au_dcsub_dpages_aufs(struct dentry *dentry, void *arg) ++{ ++ return au_di(dentry) && dentry->d_sb == arg; ++} ++ ++int au_dcsub_pages_rev_aufs(struct au_dcsub_pages *dpages, ++ struct dentry *dentry, int do_include) ++{ ++ return au_dcsub_pages_rev(dpages, dentry, do_include, ++ au_dcsub_dpages_aufs, dentry->d_sb); ++} ++ ++int au_test_subdir(struct dentry *d1, struct dentry *d2) ++{ ++ struct path path[2] = { ++ { ++ .dentry = d1 ++ }, ++ { ++ .dentry = d2 ++ } ++ }; ++ ++ return path_is_under(path + 0, path + 1); ++} +diff --git a/fs/aufs/dcsub.h b/fs/aufs/dcsub.h +new file mode 100644 +index 0000000..7997944 +--- /dev/null ++++ b/fs/aufs/dcsub.h +@@ -0,0 +1,123 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * sub-routines for dentry cache ++ */ ++ ++#ifndef __AUFS_DCSUB_H__ ++#define __AUFS_DCSUB_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++ ++struct au_dpage { ++ int ndentry; ++ struct dentry **dentries; ++}; ++ ++struct au_dcsub_pages { ++ int ndpage; ++ struct au_dpage *dpages; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* dcsub.c */ ++int au_dpages_init(struct au_dcsub_pages *dpages, gfp_t gfp); ++void au_dpages_free(struct au_dcsub_pages *dpages); ++typedef int (*au_dpages_test)(struct dentry *dentry, void *arg); ++int au_dcsub_pages(struct au_dcsub_pages *dpages, struct dentry *root, ++ au_dpages_test test, void *arg); ++int au_dcsub_pages_rev(struct au_dcsub_pages *dpages, struct dentry *dentry, ++ int do_include, au_dpages_test test, void *arg); ++int au_dcsub_pages_rev_aufs(struct au_dcsub_pages *dpages, ++ struct dentry *dentry, int do_include); ++int au_test_subdir(struct dentry *d1, struct dentry *d2); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * todo: in linux-3.13, several similar (but faster) helpers are added to ++ * include/linux/dcache.h. Try them (in the future). ++ */ ++ ++static inline int au_d_hashed_positive(struct dentry *d) ++{ ++ int err; ++ struct inode *inode = d->d_inode; ++ ++ err = 0; ++ if (unlikely(d_unhashed(d) || !inode || !inode->i_nlink)) ++ err = -ENOENT; ++ return err; ++} ++ ++static inline int au_d_linkable(struct dentry *d) ++{ ++ int err; ++ struct inode *inode = d->d_inode; ++ ++ err = au_d_hashed_positive(d); ++ if (err ++ && inode ++ && (inode->i_state & I_LINKABLE)) ++ err = 0; ++ return err; ++} ++ ++static inline int au_d_alive(struct dentry *d) ++{ ++ int err; ++ struct inode *inode; ++ ++ err = 0; ++ if (!IS_ROOT(d)) ++ err = au_d_hashed_positive(d); ++ else { ++ inode = d->d_inode; ++ if (unlikely(d_unlinked(d) || !inode || !inode->i_nlink)) ++ err = -ENOENT; ++ } ++ return err; ++} ++ ++static inline int au_alive_dir(struct dentry *d) ++{ ++ int err; ++ ++ err = au_d_alive(d); ++ if (unlikely(err || IS_DEADDIR(d->d_inode))) ++ err = -ENOENT; ++ return err; ++} ++ ++static inline int au_qstreq(struct qstr *a, struct qstr *b) ++{ ++ return a->len == b->len ++ && !memcmp(a->name, b->name, a->len); ++} ++ ++static inline int au_dcount(struct dentry *d) ++{ ++ return (int)d_count(d); ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_DCSUB_H__ */ +diff --git a/fs/aufs/debug.c b/fs/aufs/debug.c +new file mode 100644 +index 0000000..2747d13 +--- /dev/null ++++ b/fs/aufs/debug.c +@@ -0,0 +1,436 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * debug print functions ++ */ ++ ++#include "aufs.h" ++ ++/* Returns 0, or -errno. arg is in kp->arg. */ ++static int param_atomic_t_set(const char *val, const struct kernel_param *kp) ++{ ++ int err, n; ++ ++ err = kstrtoint(val, 0, &n); ++ if (!err) { ++ if (n > 0) ++ au_debug_on(); ++ else ++ au_debug_off(); ++ } ++ return err; ++} ++ ++/* Returns length written or -errno. Buffer is 4k (ie. be short!) */ ++static int param_atomic_t_get(char *buffer, const struct kernel_param *kp) ++{ ++ atomic_t *a; ++ ++ a = kp->arg; ++ return sprintf(buffer, "%d", atomic_read(a)); ++} ++ ++static struct kernel_param_ops param_ops_atomic_t = { ++ .set = param_atomic_t_set, ++ .get = param_atomic_t_get ++ /* void (*free)(void *arg) */ ++}; ++ ++atomic_t aufs_debug = ATOMIC_INIT(0); ++MODULE_PARM_DESC(debug, "debug print"); ++module_param_named(debug, aufs_debug, atomic_t, S_IRUGO | S_IWUSR | S_IWGRP); ++ ++DEFINE_MUTEX(au_dbg_mtx); /* just to serialize the dbg msgs */ ++char *au_plevel = KERN_DEBUG; ++#define dpri(fmt, ...) do { \ ++ if ((au_plevel \ ++ && strcmp(au_plevel, KERN_DEBUG)) \ ++ || au_debug_test()) \ ++ printk("%s" fmt, au_plevel, ##__VA_ARGS__); \ ++} while (0) ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_dpri_whlist(struct au_nhash *whlist) ++{ ++ unsigned long ul, n; ++ struct hlist_head *head; ++ struct au_vdir_wh *pos; ++ ++ n = whlist->nh_num; ++ head = whlist->nh_head; ++ for (ul = 0; ul < n; ul++) { ++ hlist_for_each_entry(pos, head, wh_hash) ++ dpri("b%d, %.*s, %d\n", ++ pos->wh_bindex, ++ pos->wh_str.len, pos->wh_str.name, ++ pos->wh_str.len); ++ head++; ++ } ++} ++ ++void au_dpri_vdir(struct au_vdir *vdir) ++{ ++ unsigned long ul; ++ union au_vdir_deblk_p p; ++ unsigned char *o; ++ ++ if (!vdir || IS_ERR(vdir)) { ++ dpri("err %ld\n", PTR_ERR(vdir)); ++ return; ++ } ++ ++ dpri("deblk %u, nblk %lu, deblk %p, last{%lu, %p}, ver %lu\n", ++ vdir->vd_deblk_sz, vdir->vd_nblk, vdir->vd_deblk, ++ vdir->vd_last.ul, vdir->vd_last.p.deblk, vdir->vd_version); ++ for (ul = 0; ul < vdir->vd_nblk; ul++) { ++ p.deblk = vdir->vd_deblk[ul]; ++ o = p.deblk; ++ dpri("[%lu]: %p\n", ul, o); ++ } ++} ++ ++static int do_pri_inode(aufs_bindex_t bindex, struct inode *inode, int hn, ++ struct dentry *wh) ++{ ++ char *n = NULL; ++ int l = 0; ++ ++ if (!inode || IS_ERR(inode)) { ++ dpri("i%d: err %ld\n", bindex, PTR_ERR(inode)); ++ return -1; ++ } ++ ++ /* the type of i_blocks depends upon CONFIG_LBDAF */ ++ BUILD_BUG_ON(sizeof(inode->i_blocks) != sizeof(unsigned long) ++ && sizeof(inode->i_blocks) != sizeof(u64)); ++ if (wh) { ++ n = (void *)wh->d_name.name; ++ l = wh->d_name.len; ++ } ++ ++ dpri("i%d: %p, i%lu, %s, cnt %d, nl %u, 0%o, sz %llu, blk %llu," ++ " hn %d, ct %lld, np %lu, st 0x%lx, f 0x%x, v %llu, g %x%s%.*s\n", ++ bindex, inode, ++ inode->i_ino, inode->i_sb ? au_sbtype(inode->i_sb) : "??", ++ atomic_read(&inode->i_count), inode->i_nlink, inode->i_mode, ++ i_size_read(inode), (unsigned long long)inode->i_blocks, ++ hn, (long long)timespec_to_ns(&inode->i_ctime) & 0x0ffff, ++ inode->i_mapping ? inode->i_mapping->nrpages : 0, ++ inode->i_state, inode->i_flags, inode->i_version, ++ inode->i_generation, ++ l ? ", wh " : "", l, n); ++ return 0; ++} ++ ++void au_dpri_inode(struct inode *inode) ++{ ++ struct au_iinfo *iinfo; ++ aufs_bindex_t bindex; ++ int err, hn; ++ ++ err = do_pri_inode(-1, inode, -1, NULL); ++ if (err || !au_test_aufs(inode->i_sb)) ++ return; ++ ++ iinfo = au_ii(inode); ++ if (!iinfo) ++ return; ++ dpri("i-1: bstart %d, bend %d, gen %d\n", ++ iinfo->ii_bstart, iinfo->ii_bend, au_iigen(inode, NULL)); ++ if (iinfo->ii_bstart < 0) ++ return; ++ hn = 0; ++ for (bindex = iinfo->ii_bstart; bindex <= iinfo->ii_bend; bindex++) { ++ hn = !!au_hn(iinfo->ii_hinode + bindex); ++ do_pri_inode(bindex, iinfo->ii_hinode[0 + bindex].hi_inode, hn, ++ iinfo->ii_hinode[0 + bindex].hi_whdentry); ++ } ++} ++ ++void au_dpri_dalias(struct inode *inode) ++{ ++ struct dentry *d; ++ ++ spin_lock(&inode->i_lock); ++ hlist_for_each_entry(d, &inode->i_dentry, d_u.d_alias) ++ au_dpri_dentry(d); ++ spin_unlock(&inode->i_lock); ++} ++ ++static int do_pri_dentry(aufs_bindex_t bindex, struct dentry *dentry) ++{ ++ struct dentry *wh = NULL; ++ int hn; ++ struct au_iinfo *iinfo; ++ ++ if (!dentry || IS_ERR(dentry)) { ++ dpri("d%d: err %ld\n", bindex, PTR_ERR(dentry)); ++ return -1; ++ } ++ /* do not call dget_parent() here */ ++ /* note: access d_xxx without d_lock */ ++ dpri("d%d: %p, %pd2?, %s, cnt %d, flags 0x%x, %shashed\n", ++ bindex, dentry, dentry, ++ dentry->d_sb ? au_sbtype(dentry->d_sb) : "??", ++ au_dcount(dentry), dentry->d_flags, ++ d_unhashed(dentry) ? "un" : ""); ++ hn = -1; ++ if (bindex >= 0 && dentry->d_inode && au_test_aufs(dentry->d_sb)) { ++ iinfo = au_ii(dentry->d_inode); ++ if (iinfo) { ++ hn = !!au_hn(iinfo->ii_hinode + bindex); ++ wh = iinfo->ii_hinode[0 + bindex].hi_whdentry; ++ } ++ } ++ do_pri_inode(bindex, dentry->d_inode, hn, wh); ++ return 0; ++} ++ ++void au_dpri_dentry(struct dentry *dentry) ++{ ++ struct au_dinfo *dinfo; ++ aufs_bindex_t bindex; ++ int err; ++ struct au_hdentry *hdp; ++ ++ err = do_pri_dentry(-1, dentry); ++ if (err || !au_test_aufs(dentry->d_sb)) ++ return; ++ ++ dinfo = au_di(dentry); ++ if (!dinfo) ++ return; ++ dpri("d-1: bstart %d, bend %d, bwh %d, bdiropq %d, gen %d, tmp %d\n", ++ dinfo->di_bstart, dinfo->di_bend, ++ dinfo->di_bwh, dinfo->di_bdiropq, au_digen(dentry), ++ dinfo->di_tmpfile); ++ if (dinfo->di_bstart < 0) ++ return; ++ hdp = dinfo->di_hdentry; ++ for (bindex = dinfo->di_bstart; bindex <= dinfo->di_bend; bindex++) ++ do_pri_dentry(bindex, hdp[0 + bindex].hd_dentry); ++} ++ ++static int do_pri_file(aufs_bindex_t bindex, struct file *file) ++{ ++ char a[32]; ++ ++ if (!file || IS_ERR(file)) { ++ dpri("f%d: err %ld\n", bindex, PTR_ERR(file)); ++ return -1; ++ } ++ a[0] = 0; ++ if (bindex < 0 ++ && !IS_ERR_OR_NULL(file->f_dentry) ++ && au_test_aufs(file->f_dentry->d_sb) ++ && au_fi(file)) ++ snprintf(a, sizeof(a), ", gen %d, mmapped %d", ++ au_figen(file), atomic_read(&au_fi(file)->fi_mmapped)); ++ dpri("f%d: mode 0x%x, flags 0%o, cnt %ld, v %llu, pos %llu%s\n", ++ bindex, file->f_mode, file->f_flags, (long)file_count(file), ++ file->f_version, file->f_pos, a); ++ if (!IS_ERR_OR_NULL(file->f_dentry)) ++ do_pri_dentry(bindex, file->f_dentry); ++ return 0; ++} ++ ++void au_dpri_file(struct file *file) ++{ ++ struct au_finfo *finfo; ++ struct au_fidir *fidir; ++ struct au_hfile *hfile; ++ aufs_bindex_t bindex; ++ int err; ++ ++ err = do_pri_file(-1, file); ++ if (err ++ || IS_ERR_OR_NULL(file->f_dentry) ++ || !au_test_aufs(file->f_dentry->d_sb)) ++ return; ++ ++ finfo = au_fi(file); ++ if (!finfo) ++ return; ++ if (finfo->fi_btop < 0) ++ return; ++ fidir = finfo->fi_hdir; ++ if (!fidir) ++ do_pri_file(finfo->fi_btop, finfo->fi_htop.hf_file); ++ else ++ for (bindex = finfo->fi_btop; ++ bindex >= 0 && bindex <= fidir->fd_bbot; ++ bindex++) { ++ hfile = fidir->fd_hfile + bindex; ++ do_pri_file(bindex, hfile ? hfile->hf_file : NULL); ++ } ++} ++ ++static int do_pri_br(aufs_bindex_t bindex, struct au_branch *br) ++{ ++ struct vfsmount *mnt; ++ struct super_block *sb; ++ ++ if (!br || IS_ERR(br)) ++ goto out; ++ mnt = au_br_mnt(br); ++ if (!mnt || IS_ERR(mnt)) ++ goto out; ++ sb = mnt->mnt_sb; ++ if (!sb || IS_ERR(sb)) ++ goto out; ++ ++ dpri("s%d: {perm 0x%x, id %d, cnt %d, wbr %p}, " ++ "%s, dev 0x%02x%02x, flags 0x%lx, cnt %d, active %d, " ++ "xino %d\n", ++ bindex, br->br_perm, br->br_id, atomic_read(&br->br_count), ++ br->br_wbr, au_sbtype(sb), MAJOR(sb->s_dev), MINOR(sb->s_dev), ++ sb->s_flags, sb->s_count, ++ atomic_read(&sb->s_active), !!br->br_xino.xi_file); ++ return 0; ++ ++out: ++ dpri("s%d: err %ld\n", bindex, PTR_ERR(br)); ++ return -1; ++} ++ ++void au_dpri_sb(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ aufs_bindex_t bindex; ++ int err; ++ /* to reuduce stack size */ ++ struct { ++ struct vfsmount mnt; ++ struct au_branch fake; ++ } *a; ++ ++ /* this function can be called from magic sysrq */ ++ a = kzalloc(sizeof(*a), GFP_ATOMIC); ++ if (unlikely(!a)) { ++ dpri("no memory\n"); ++ return; ++ } ++ ++ a->mnt.mnt_sb = sb; ++ a->fake.br_path.mnt = &a->mnt; ++ atomic_set(&a->fake.br_count, 0); ++ smp_mb(); /* atomic_set */ ++ err = do_pri_br(-1, &a->fake); ++ kfree(a); ++ dpri("dev 0x%x\n", sb->s_dev); ++ if (err || !au_test_aufs(sb)) ++ return; ++ ++ sbinfo = au_sbi(sb); ++ if (!sbinfo) ++ return; ++ dpri("nw %d, gen %u, kobj %d\n", ++ atomic_read(&sbinfo->si_nowait.nw_len), sbinfo->si_generation, ++ atomic_read(&sbinfo->si_kobj.kref.refcount)); ++ for (bindex = 0; bindex <= sbinfo->si_bend; bindex++) ++ do_pri_br(bindex, sbinfo->si_branch[0 + bindex]); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void __au_dbg_verify_dinode(struct dentry *dentry, const char *func, int line) ++{ ++ struct inode *h_inode, *inode = dentry->d_inode; ++ struct dentry *h_dentry; ++ aufs_bindex_t bindex, bend, bi; ++ ++ if (!inode /* || au_di(dentry)->di_lsc == AuLsc_DI_TMP */) ++ return; ++ ++ bend = au_dbend(dentry); ++ bi = au_ibend(inode); ++ if (bi < bend) ++ bend = bi; ++ bindex = au_dbstart(dentry); ++ bi = au_ibstart(inode); ++ if (bi > bindex) ++ bindex = bi; ++ ++ for (; bindex <= bend; bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!h_dentry) ++ continue; ++ h_inode = au_h_iptr(inode, bindex); ++ if (unlikely(h_inode != h_dentry->d_inode)) { ++ au_debug_on(); ++ AuDbg("b%d, %s:%d\n", bindex, func, line); ++ AuDbgDentry(dentry); ++ AuDbgInode(inode); ++ au_debug_off(); ++ BUG(); ++ } ++ } ++} ++ ++void au_dbg_verify_gen(struct dentry *parent, unsigned int sigen) ++{ ++ int err, i, j; ++ struct au_dcsub_pages dpages; ++ struct au_dpage *dpage; ++ struct dentry **dentries; ++ ++ err = au_dpages_init(&dpages, GFP_NOFS); ++ AuDebugOn(err); ++ err = au_dcsub_pages_rev_aufs(&dpages, parent, /*do_include*/1); ++ AuDebugOn(err); ++ for (i = dpages.ndpage - 1; !err && i >= 0; i--) { ++ dpage = dpages.dpages + i; ++ dentries = dpage->dentries; ++ for (j = dpage->ndentry - 1; !err && j >= 0; j--) ++ AuDebugOn(au_digen_test(dentries[j], sigen)); ++ } ++ au_dpages_free(&dpages); ++} ++ ++void au_dbg_verify_kthread(void) ++{ ++ if (au_wkq_test()) { ++ au_dbg_blocked(); ++ /* ++ * It may be recursive, but udba=notify between two aufs mounts, ++ * where a single ro branch is shared, is not a problem. ++ */ ++ /* WARN_ON(1); */ ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int __init au_debug_init(void) ++{ ++ aufs_bindex_t bindex; ++ struct au_vdir_destr destr; ++ ++ bindex = -1; ++ AuDebugOn(bindex >= 0); ++ ++ destr.len = -1; ++ AuDebugOn(destr.len < NAME_MAX); ++ ++#ifdef CONFIG_4KSTACKS ++ pr_warn("CONFIG_4KSTACKS is defined.\n"); ++#endif ++ ++ return 0; ++} +diff --git a/fs/aufs/debug.h b/fs/aufs/debug.h +new file mode 100644 +index 0000000..039e6f8 +--- /dev/null ++++ b/fs/aufs/debug.h +@@ -0,0 +1,228 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * debug print functions ++ */ ++ ++#ifndef __AUFS_DEBUG_H__ ++#define __AUFS_DEBUG_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++#include ++ ++#ifdef CONFIG_AUFS_DEBUG ++#define AuDebugOn(a) BUG_ON(a) ++ ++/* module parameter */ ++extern atomic_t aufs_debug; ++static inline void au_debug_on(void) ++{ ++ atomic_inc(&aufs_debug); ++} ++static inline void au_debug_off(void) ++{ ++ atomic_dec_if_positive(&aufs_debug); ++} ++ ++static inline int au_debug_test(void) ++{ ++ return atomic_read(&aufs_debug) > 0; ++} ++#else ++#define AuDebugOn(a) do {} while (0) ++AuStubVoid(au_debug_on, void) ++AuStubVoid(au_debug_off, void) ++AuStubInt0(au_debug_test, void) ++#endif /* CONFIG_AUFS_DEBUG */ ++ ++#define param_check_atomic_t(name, p) __param_check(name, p, atomic_t) ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* debug print */ ++ ++#define AuDbg(fmt, ...) do { \ ++ if (au_debug_test()) \ ++ pr_debug("DEBUG: " fmt, ##__VA_ARGS__); \ ++} while (0) ++#define AuLabel(l) AuDbg(#l "\n") ++#define AuIOErr(fmt, ...) pr_err("I/O Error, " fmt, ##__VA_ARGS__) ++#define AuWarn1(fmt, ...) do { \ ++ static unsigned char _c; \ ++ if (!_c++) \ ++ pr_warn(fmt, ##__VA_ARGS__); \ ++} while (0) ++ ++#define AuErr1(fmt, ...) do { \ ++ static unsigned char _c; \ ++ if (!_c++) \ ++ pr_err(fmt, ##__VA_ARGS__); \ ++} while (0) ++ ++#define AuIOErr1(fmt, ...) do { \ ++ static unsigned char _c; \ ++ if (!_c++) \ ++ AuIOErr(fmt, ##__VA_ARGS__); \ ++} while (0) ++ ++#define AuUnsupportMsg "This operation is not supported." \ ++ " Please report this application to aufs-users ML." ++#define AuUnsupport(fmt, ...) do { \ ++ pr_err(AuUnsupportMsg "\n" fmt, ##__VA_ARGS__); \ ++ dump_stack(); \ ++} while (0) ++ ++#define AuTraceErr(e) do { \ ++ if (unlikely((e) < 0)) \ ++ AuDbg("err %d\n", (int)(e)); \ ++} while (0) ++ ++#define AuTraceErrPtr(p) do { \ ++ if (IS_ERR(p)) \ ++ AuDbg("err %ld\n", PTR_ERR(p)); \ ++} while (0) ++ ++/* dirty macros for debug print, use with "%.*s" and caution */ ++#define AuLNPair(qstr) (qstr)->len, (qstr)->name ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct dentry; ++#ifdef CONFIG_AUFS_DEBUG ++extern struct mutex au_dbg_mtx; ++extern char *au_plevel; ++struct au_nhash; ++void au_dpri_whlist(struct au_nhash *whlist); ++struct au_vdir; ++void au_dpri_vdir(struct au_vdir *vdir); ++struct inode; ++void au_dpri_inode(struct inode *inode); ++void au_dpri_dalias(struct inode *inode); ++void au_dpri_dentry(struct dentry *dentry); ++struct file; ++void au_dpri_file(struct file *filp); ++struct super_block; ++void au_dpri_sb(struct super_block *sb); ++ ++#define au_dbg_verify_dinode(d) __au_dbg_verify_dinode(d, __func__, __LINE__) ++void __au_dbg_verify_dinode(struct dentry *dentry, const char *func, int line); ++void au_dbg_verify_gen(struct dentry *parent, unsigned int sigen); ++void au_dbg_verify_kthread(void); ++ ++int __init au_debug_init(void); ++ ++#define AuDbgWhlist(w) do { \ ++ mutex_lock(&au_dbg_mtx); \ ++ AuDbg(#w "\n"); \ ++ au_dpri_whlist(w); \ ++ mutex_unlock(&au_dbg_mtx); \ ++} while (0) ++ ++#define AuDbgVdir(v) do { \ ++ mutex_lock(&au_dbg_mtx); \ ++ AuDbg(#v "\n"); \ ++ au_dpri_vdir(v); \ ++ mutex_unlock(&au_dbg_mtx); \ ++} while (0) ++ ++#define AuDbgInode(i) do { \ ++ mutex_lock(&au_dbg_mtx); \ ++ AuDbg(#i "\n"); \ ++ au_dpri_inode(i); \ ++ mutex_unlock(&au_dbg_mtx); \ ++} while (0) ++ ++#define AuDbgDAlias(i) do { \ ++ mutex_lock(&au_dbg_mtx); \ ++ AuDbg(#i "\n"); \ ++ au_dpri_dalias(i); \ ++ mutex_unlock(&au_dbg_mtx); \ ++} while (0) ++ ++#define AuDbgDentry(d) do { \ ++ mutex_lock(&au_dbg_mtx); \ ++ AuDbg(#d "\n"); \ ++ au_dpri_dentry(d); \ ++ mutex_unlock(&au_dbg_mtx); \ ++} while (0) ++ ++#define AuDbgFile(f) do { \ ++ mutex_lock(&au_dbg_mtx); \ ++ AuDbg(#f "\n"); \ ++ au_dpri_file(f); \ ++ mutex_unlock(&au_dbg_mtx); \ ++} while (0) ++ ++#define AuDbgSb(sb) do { \ ++ mutex_lock(&au_dbg_mtx); \ ++ AuDbg(#sb "\n"); \ ++ au_dpri_sb(sb); \ ++ mutex_unlock(&au_dbg_mtx); \ ++} while (0) ++ ++#define AuDbgSym(addr) do { \ ++ char sym[KSYM_SYMBOL_LEN]; \ ++ sprint_symbol(sym, (unsigned long)addr); \ ++ AuDbg("%s\n", sym); \ ++} while (0) ++#else ++AuStubVoid(au_dbg_verify_dinode, struct dentry *dentry) ++AuStubVoid(au_dbg_verify_dir_parent, struct dentry *dentry, unsigned int sigen) ++AuStubVoid(au_dbg_verify_nondir_parent, struct dentry *dentry, ++ unsigned int sigen) ++AuStubVoid(au_dbg_verify_gen, struct dentry *parent, unsigned int sigen) ++AuStubVoid(au_dbg_verify_kthread, void) ++AuStubInt0(__init au_debug_init, void) ++ ++#define AuDbgWhlist(w) do {} while (0) ++#define AuDbgVdir(v) do {} while (0) ++#define AuDbgInode(i) do {} while (0) ++#define AuDbgDAlias(i) do {} while (0) ++#define AuDbgDentry(d) do {} while (0) ++#define AuDbgFile(f) do {} while (0) ++#define AuDbgSb(sb) do {} while (0) ++#define AuDbgSym(addr) do {} while (0) ++#endif /* CONFIG_AUFS_DEBUG */ ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_MAGIC_SYSRQ ++int __init au_sysrq_init(void); ++void au_sysrq_fin(void); ++ ++#ifdef CONFIG_HW_CONSOLE ++#define au_dbg_blocked() do { \ ++ WARN_ON(1); \ ++ handle_sysrq('w'); \ ++} while (0) ++#else ++AuStubVoid(au_dbg_blocked, void) ++#endif ++ ++#else ++AuStubInt0(__init au_sysrq_init, void) ++AuStubVoid(au_sysrq_fin, void) ++AuStubVoid(au_dbg_blocked, void) ++#endif /* CONFIG_AUFS_MAGIC_SYSRQ */ ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_DEBUG_H__ */ +diff --git a/fs/aufs/dentry.c b/fs/aufs/dentry.c +new file mode 100644 +index 0000000..ed56947 +--- /dev/null ++++ b/fs/aufs/dentry.c +@@ -0,0 +1,1129 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * lookup and dentry operations ++ */ ++ ++#include ++#include "aufs.h" ++ ++#define AuLkup_ALLOW_NEG 1 ++#define AuLkup_IGNORE_PERM (1 << 1) ++#define au_ftest_lkup(flags, name) ((flags) & AuLkup_##name) ++#define au_fset_lkup(flags, name) \ ++ do { (flags) |= AuLkup_##name; } while (0) ++#define au_fclr_lkup(flags, name) \ ++ do { (flags) &= ~AuLkup_##name; } while (0) ++ ++struct au_do_lookup_args { ++ unsigned int flags; ++ mode_t type; ++}; ++ ++/* ++ * returns positive/negative dentry, NULL or an error. ++ * NULL means whiteout-ed or not-found. ++ */ ++static struct dentry* ++au_do_lookup(struct dentry *h_parent, struct dentry *dentry, ++ aufs_bindex_t bindex, struct qstr *wh_name, ++ struct au_do_lookup_args *args) ++{ ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ struct au_branch *br; ++ int wh_found, opq; ++ unsigned char wh_able; ++ const unsigned char allow_neg = !!au_ftest_lkup(args->flags, ALLOW_NEG); ++ const unsigned char ignore_perm = !!au_ftest_lkup(args->flags, ++ IGNORE_PERM); ++ ++ wh_found = 0; ++ br = au_sbr(dentry->d_sb, bindex); ++ wh_able = !!au_br_whable(br->br_perm); ++ if (wh_able) ++ wh_found = au_wh_test(h_parent, wh_name, /*try_sio*/0); ++ h_dentry = ERR_PTR(wh_found); ++ if (!wh_found) ++ goto real_lookup; ++ if (unlikely(wh_found < 0)) ++ goto out; ++ ++ /* We found a whiteout */ ++ /* au_set_dbend(dentry, bindex); */ ++ au_set_dbwh(dentry, bindex); ++ if (!allow_neg) ++ return NULL; /* success */ ++ ++real_lookup: ++ if (!ignore_perm) ++ h_dentry = vfsub_lkup_one(&dentry->d_name, h_parent); ++ else ++ h_dentry = au_sio_lkup_one(&dentry->d_name, h_parent); ++ if (IS_ERR(h_dentry)) { ++ if (PTR_ERR(h_dentry) == -ENAMETOOLONG ++ && !allow_neg) ++ h_dentry = NULL; ++ goto out; ++ } ++ ++ h_inode = h_dentry->d_inode; ++ if (!h_inode) { ++ if (!allow_neg) ++ goto out_neg; ++ } else if (wh_found ++ || (args->type && args->type != (h_inode->i_mode & S_IFMT))) ++ goto out_neg; ++ ++ if (au_dbend(dentry) <= bindex) ++ au_set_dbend(dentry, bindex); ++ if (au_dbstart(dentry) < 0 || bindex < au_dbstart(dentry)) ++ au_set_dbstart(dentry, bindex); ++ au_set_h_dptr(dentry, bindex, h_dentry); ++ ++ if (!d_is_dir(h_dentry) ++ || !wh_able ++ || (d_is_positive(dentry) && !d_is_dir(dentry))) ++ goto out; /* success */ ++ ++ mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD); ++ opq = au_diropq_test(h_dentry); ++ mutex_unlock(&h_inode->i_mutex); ++ if (opq > 0) ++ au_set_dbdiropq(dentry, bindex); ++ else if (unlikely(opq < 0)) { ++ au_set_h_dptr(dentry, bindex, NULL); ++ h_dentry = ERR_PTR(opq); ++ } ++ goto out; ++ ++out_neg: ++ dput(h_dentry); ++ h_dentry = NULL; ++out: ++ return h_dentry; ++} ++ ++static int au_test_shwh(struct super_block *sb, const struct qstr *name) ++{ ++ if (unlikely(!au_opt_test(au_mntflags(sb), SHWH) ++ && !strncmp(name->name, AUFS_WH_PFX, AUFS_WH_PFX_LEN))) ++ return -EPERM; ++ return 0; ++} ++ ++/* ++ * returns the number of lower positive dentries, ++ * otherwise an error. ++ * can be called at unlinking with @type is zero. ++ */ ++int au_lkup_dentry(struct dentry *dentry, aufs_bindex_t bstart, mode_t type) ++{ ++ int npositive, err; ++ aufs_bindex_t bindex, btail, bdiropq; ++ unsigned char isdir, dirperm1; ++ struct qstr whname; ++ struct au_do_lookup_args args = { ++ .flags = 0, ++ .type = type ++ }; ++ const struct qstr *name = &dentry->d_name; ++ struct dentry *parent; ++ struct inode *inode; ++ struct super_block *sb; ++ ++ sb = dentry->d_sb; ++ err = au_test_shwh(sb, name); ++ if (unlikely(err)) ++ goto out; ++ ++ err = au_wh_name_alloc(&whname, name); ++ if (unlikely(err)) ++ goto out; ++ ++ inode = dentry->d_inode; ++ isdir = !!d_is_dir(dentry); ++ if (!type) ++ au_fset_lkup(args.flags, ALLOW_NEG); ++ dirperm1 = !!au_opt_test(au_mntflags(sb), DIRPERM1); ++ ++ npositive = 0; ++ parent = dget_parent(dentry); ++ btail = au_dbtaildir(parent); ++ for (bindex = bstart; bindex <= btail; bindex++) { ++ struct dentry *h_parent, *h_dentry; ++ struct inode *h_inode, *h_dir; ++ ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (h_dentry) { ++ if (h_dentry->d_inode) ++ npositive++; ++ if (type != S_IFDIR) ++ break; ++ continue; ++ } ++ h_parent = au_h_dptr(parent, bindex); ++ if (!h_parent || !d_is_dir(h_parent)) ++ continue; ++ ++ h_dir = h_parent->d_inode; ++ mutex_lock_nested(&h_dir->i_mutex, AuLsc_I_PARENT); ++ h_dentry = au_do_lookup(h_parent, dentry, bindex, &whname, ++ &args); ++ mutex_unlock(&h_dir->i_mutex); ++ err = PTR_ERR(h_dentry); ++ if (IS_ERR(h_dentry)) ++ goto out_parent; ++ if (h_dentry) ++ au_fclr_lkup(args.flags, ALLOW_NEG); ++ if (dirperm1) ++ au_fset_lkup(args.flags, IGNORE_PERM); ++ ++ if (au_dbwh(dentry) == bindex) ++ break; ++ if (!h_dentry) ++ continue; ++ h_inode = h_dentry->d_inode; ++ if (!h_inode) ++ continue; ++ npositive++; ++ if (!args.type) ++ args.type = h_inode->i_mode & S_IFMT; ++ if (args.type != S_IFDIR) ++ break; ++ else if (isdir) { ++ /* the type of lower may be different */ ++ bdiropq = au_dbdiropq(dentry); ++ if (bdiropq >= 0 && bdiropq <= bindex) ++ break; ++ } ++ } ++ ++ if (npositive) { ++ AuLabel(positive); ++ au_update_dbstart(dentry); ++ } ++ err = npositive; ++ if (unlikely(!au_opt_test(au_mntflags(sb), UDBA_NONE) ++ && au_dbstart(dentry) < 0)) { ++ err = -EIO; ++ AuIOErr("both of real entry and whiteout found, %pd, err %d\n", ++ dentry, err); ++ } ++ ++out_parent: ++ dput(parent); ++ kfree(whname.name); ++out: ++ return err; ++} ++ ++struct dentry *au_sio_lkup_one(struct qstr *name, struct dentry *parent) ++{ ++ struct dentry *dentry; ++ int wkq_err; ++ ++ if (!au_test_h_perm_sio(parent->d_inode, MAY_EXEC)) ++ dentry = vfsub_lkup_one(name, parent); ++ else { ++ struct vfsub_lkup_one_args args = { ++ .errp = &dentry, ++ .name = name, ++ .parent = parent ++ }; ++ ++ wkq_err = au_wkq_wait(vfsub_call_lkup_one, &args); ++ if (unlikely(wkq_err)) ++ dentry = ERR_PTR(wkq_err); ++ } ++ ++ return dentry; ++} ++ ++/* ++ * lookup @dentry on @bindex which should be negative. ++ */ ++int au_lkup_neg(struct dentry *dentry, aufs_bindex_t bindex, int wh) ++{ ++ int err; ++ struct dentry *parent, *h_parent, *h_dentry; ++ struct au_branch *br; ++ ++ parent = dget_parent(dentry); ++ h_parent = au_h_dptr(parent, bindex); ++ br = au_sbr(dentry->d_sb, bindex); ++ if (wh) ++ h_dentry = au_whtmp_lkup(h_parent, br, &dentry->d_name); ++ else ++ h_dentry = au_sio_lkup_one(&dentry->d_name, h_parent); ++ err = PTR_ERR(h_dentry); ++ if (IS_ERR(h_dentry)) ++ goto out; ++ if (unlikely(h_dentry->d_inode)) { ++ err = -EIO; ++ AuIOErr("%pd should be negative on b%d.\n", h_dentry, bindex); ++ dput(h_dentry); ++ goto out; ++ } ++ ++ err = 0; ++ if (bindex < au_dbstart(dentry)) ++ au_set_dbstart(dentry, bindex); ++ if (au_dbend(dentry) < bindex) ++ au_set_dbend(dentry, bindex); ++ au_set_h_dptr(dentry, bindex, h_dentry); ++ ++out: ++ dput(parent); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* subset of struct inode */ ++struct au_iattr { ++ unsigned long i_ino; ++ /* unsigned int i_nlink; */ ++ kuid_t i_uid; ++ kgid_t i_gid; ++ u64 i_version; ++/* ++ loff_t i_size; ++ blkcnt_t i_blocks; ++*/ ++ umode_t i_mode; ++}; ++ ++static void au_iattr_save(struct au_iattr *ia, struct inode *h_inode) ++{ ++ ia->i_ino = h_inode->i_ino; ++ /* ia->i_nlink = h_inode->i_nlink; */ ++ ia->i_uid = h_inode->i_uid; ++ ia->i_gid = h_inode->i_gid; ++ ia->i_version = h_inode->i_version; ++/* ++ ia->i_size = h_inode->i_size; ++ ia->i_blocks = h_inode->i_blocks; ++*/ ++ ia->i_mode = (h_inode->i_mode & S_IFMT); ++} ++ ++static int au_iattr_test(struct au_iattr *ia, struct inode *h_inode) ++{ ++ return ia->i_ino != h_inode->i_ino ++ /* || ia->i_nlink != h_inode->i_nlink */ ++ || !uid_eq(ia->i_uid, h_inode->i_uid) ++ || !gid_eq(ia->i_gid, h_inode->i_gid) ++ || ia->i_version != h_inode->i_version ++/* ++ || ia->i_size != h_inode->i_size ++ || ia->i_blocks != h_inode->i_blocks ++*/ ++ || ia->i_mode != (h_inode->i_mode & S_IFMT); ++} ++ ++static int au_h_verify_dentry(struct dentry *h_dentry, struct dentry *h_parent, ++ struct au_branch *br) ++{ ++ int err; ++ struct au_iattr ia; ++ struct inode *h_inode; ++ struct dentry *h_d; ++ struct super_block *h_sb; ++ ++ err = 0; ++ memset(&ia, -1, sizeof(ia)); ++ h_sb = h_dentry->d_sb; ++ h_inode = h_dentry->d_inode; ++ if (h_inode) ++ au_iattr_save(&ia, h_inode); ++ else if (au_test_nfs(h_sb) || au_test_fuse(h_sb)) ++ /* nfs d_revalidate may return 0 for negative dentry */ ++ /* fuse d_revalidate always return 0 for negative dentry */ ++ goto out; ++ ++ /* main purpose is namei.c:cached_lookup() and d_revalidate */ ++ h_d = vfsub_lkup_one(&h_dentry->d_name, h_parent); ++ err = PTR_ERR(h_d); ++ if (IS_ERR(h_d)) ++ goto out; ++ ++ err = 0; ++ if (unlikely(h_d != h_dentry ++ || h_d->d_inode != h_inode ++ || (h_inode && au_iattr_test(&ia, h_inode)))) ++ err = au_busy_or_stale(); ++ dput(h_d); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_h_verify(struct dentry *h_dentry, unsigned int udba, struct inode *h_dir, ++ struct dentry *h_parent, struct au_branch *br) ++{ ++ int err; ++ ++ err = 0; ++ if (udba == AuOpt_UDBA_REVAL ++ && !au_test_fs_remote(h_dentry->d_sb)) { ++ IMustLock(h_dir); ++ err = (h_dentry->d_parent->d_inode != h_dir); ++ } else if (udba != AuOpt_UDBA_NONE) ++ err = au_h_verify_dentry(h_dentry, h_parent, br); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_do_refresh_hdentry(struct dentry *dentry, struct dentry *parent) ++{ ++ int err; ++ aufs_bindex_t new_bindex, bindex, bend, bwh, bdiropq; ++ struct au_hdentry tmp, *p, *q; ++ struct au_dinfo *dinfo; ++ struct super_block *sb; ++ ++ DiMustWriteLock(dentry); ++ ++ sb = dentry->d_sb; ++ dinfo = au_di(dentry); ++ bend = dinfo->di_bend; ++ bwh = dinfo->di_bwh; ++ bdiropq = dinfo->di_bdiropq; ++ p = dinfo->di_hdentry + dinfo->di_bstart; ++ for (bindex = dinfo->di_bstart; bindex <= bend; bindex++, p++) { ++ if (!p->hd_dentry) ++ continue; ++ ++ new_bindex = au_br_index(sb, p->hd_id); ++ if (new_bindex == bindex) ++ continue; ++ ++ if (dinfo->di_bwh == bindex) ++ bwh = new_bindex; ++ if (dinfo->di_bdiropq == bindex) ++ bdiropq = new_bindex; ++ if (new_bindex < 0) { ++ au_hdput(p); ++ p->hd_dentry = NULL; ++ continue; ++ } ++ ++ /* swap two lower dentries, and loop again */ ++ q = dinfo->di_hdentry + new_bindex; ++ tmp = *q; ++ *q = *p; ++ *p = tmp; ++ if (tmp.hd_dentry) { ++ bindex--; ++ p--; ++ } ++ } ++ ++ dinfo->di_bwh = -1; ++ if (bwh >= 0 && bwh <= au_sbend(sb) && au_sbr_whable(sb, bwh)) ++ dinfo->di_bwh = bwh; ++ ++ dinfo->di_bdiropq = -1; ++ if (bdiropq >= 0 ++ && bdiropq <= au_sbend(sb) ++ && au_sbr_whable(sb, bdiropq)) ++ dinfo->di_bdiropq = bdiropq; ++ ++ err = -EIO; ++ dinfo->di_bstart = -1; ++ dinfo->di_bend = -1; ++ bend = au_dbend(parent); ++ p = dinfo->di_hdentry; ++ for (bindex = 0; bindex <= bend; bindex++, p++) ++ if (p->hd_dentry) { ++ dinfo->di_bstart = bindex; ++ break; ++ } ++ ++ if (dinfo->di_bstart >= 0) { ++ p = dinfo->di_hdentry + bend; ++ for (bindex = bend; bindex >= 0; bindex--, p--) ++ if (p->hd_dentry) { ++ dinfo->di_bend = bindex; ++ err = 0; ++ break; ++ } ++ } ++ ++ return err; ++} ++ ++static void au_do_hide(struct dentry *dentry) ++{ ++ struct inode *inode; ++ ++ inode = dentry->d_inode; ++ if (inode) { ++ if (!S_ISDIR(inode->i_mode)) { ++ if (inode->i_nlink && !d_unhashed(dentry)) ++ drop_nlink(inode); ++ } else { ++ clear_nlink(inode); ++ /* stop next lookup */ ++ inode->i_flags |= S_DEAD; ++ } ++ smp_mb(); /* necessary? */ ++ } ++ d_drop(dentry); ++} ++ ++static int au_hide_children(struct dentry *parent) ++{ ++ int err, i, j, ndentry; ++ struct au_dcsub_pages dpages; ++ struct au_dpage *dpage; ++ struct dentry *dentry; ++ ++ err = au_dpages_init(&dpages, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ err = au_dcsub_pages(&dpages, parent, NULL, NULL); ++ if (unlikely(err)) ++ goto out_dpages; ++ ++ /* in reverse order */ ++ for (i = dpages.ndpage - 1; i >= 0; i--) { ++ dpage = dpages.dpages + i; ++ ndentry = dpage->ndentry; ++ for (j = ndentry - 1; j >= 0; j--) { ++ dentry = dpage->dentries[j]; ++ if (dentry != parent) ++ au_do_hide(dentry); ++ } ++ } ++ ++out_dpages: ++ au_dpages_free(&dpages); ++out: ++ return err; ++} ++ ++static void au_hide(struct dentry *dentry) ++{ ++ int err; ++ ++ AuDbgDentry(dentry); ++ if (d_is_dir(dentry)) { ++ /* shrink_dcache_parent(dentry); */ ++ err = au_hide_children(dentry); ++ if (unlikely(err)) ++ AuIOErr("%pd, failed hiding children, ignored %d\n", ++ dentry, err); ++ } ++ au_do_hide(dentry); ++} ++ ++/* ++ * By adding a dirty branch, a cached dentry may be affected in various ways. ++ * ++ * a dirty branch is added ++ * - on the top of layers ++ * - in the middle of layers ++ * - to the bottom of layers ++ * ++ * on the added branch there exists ++ * - a whiteout ++ * - a diropq ++ * - a same named entry ++ * + exist ++ * * negative --> positive ++ * * positive --> positive ++ * - type is unchanged ++ * - type is changed ++ * + doesn't exist ++ * * negative --> negative ++ * * positive --> negative (rejected by au_br_del() for non-dir case) ++ * - none ++ */ ++static int au_refresh_by_dinfo(struct dentry *dentry, struct au_dinfo *dinfo, ++ struct au_dinfo *tmp) ++{ ++ int err; ++ aufs_bindex_t bindex, bend; ++ struct { ++ struct dentry *dentry; ++ struct inode *inode; ++ mode_t mode; ++ } orig_h, tmp_h = { ++ .dentry = NULL ++ }; ++ struct au_hdentry *hd; ++ struct inode *inode, *h_inode; ++ struct dentry *h_dentry; ++ ++ err = 0; ++ AuDebugOn(dinfo->di_bstart < 0); ++ orig_h.dentry = dinfo->di_hdentry[dinfo->di_bstart].hd_dentry; ++ orig_h.inode = orig_h.dentry->d_inode; ++ orig_h.mode = 0; ++ if (orig_h.inode) ++ orig_h.mode = orig_h.inode->i_mode & S_IFMT; ++ if (tmp->di_bstart >= 0) { ++ tmp_h.dentry = tmp->di_hdentry[tmp->di_bstart].hd_dentry; ++ tmp_h.inode = tmp_h.dentry->d_inode; ++ if (tmp_h.inode) ++ tmp_h.mode = tmp_h.inode->i_mode & S_IFMT; ++ } ++ ++ inode = dentry->d_inode; ++ if (!orig_h.inode) { ++ AuDbg("nagative originally\n"); ++ if (inode) { ++ au_hide(dentry); ++ goto out; ++ } ++ AuDebugOn(inode); ++ AuDebugOn(dinfo->di_bstart != dinfo->di_bend); ++ AuDebugOn(dinfo->di_bdiropq != -1); ++ ++ if (!tmp_h.inode) { ++ AuDbg("negative --> negative\n"); ++ /* should have only one negative lower */ ++ if (tmp->di_bstart >= 0 ++ && tmp->di_bstart < dinfo->di_bstart) { ++ AuDebugOn(tmp->di_bstart != tmp->di_bend); ++ AuDebugOn(dinfo->di_bstart != dinfo->di_bend); ++ au_set_h_dptr(dentry, dinfo->di_bstart, NULL); ++ au_di_cp(dinfo, tmp); ++ hd = tmp->di_hdentry + tmp->di_bstart; ++ au_set_h_dptr(dentry, tmp->di_bstart, ++ dget(hd->hd_dentry)); ++ } ++ au_dbg_verify_dinode(dentry); ++ } else { ++ AuDbg("negative --> positive\n"); ++ /* ++ * similar to the behaviour of creating with bypassing ++ * aufs. ++ * unhash it in order to force an error in the ++ * succeeding create operation. ++ * we should not set S_DEAD here. ++ */ ++ d_drop(dentry); ++ /* au_di_swap(tmp, dinfo); */ ++ au_dbg_verify_dinode(dentry); ++ } ++ } else { ++ AuDbg("positive originally\n"); ++ /* inode may be NULL */ ++ AuDebugOn(inode && (inode->i_mode & S_IFMT) != orig_h.mode); ++ if (!tmp_h.inode) { ++ AuDbg("positive --> negative\n"); ++ /* or bypassing aufs */ ++ au_hide(dentry); ++ if (tmp->di_bwh >= 0 && tmp->di_bwh <= dinfo->di_bstart) ++ dinfo->di_bwh = tmp->di_bwh; ++ if (inode) ++ err = au_refresh_hinode_self(inode); ++ au_dbg_verify_dinode(dentry); ++ } else if (orig_h.mode == tmp_h.mode) { ++ AuDbg("positive --> positive, same type\n"); ++ if (!S_ISDIR(orig_h.mode) ++ && dinfo->di_bstart > tmp->di_bstart) { ++ /* ++ * similar to the behaviour of removing and ++ * creating. ++ */ ++ au_hide(dentry); ++ if (inode) ++ err = au_refresh_hinode_self(inode); ++ au_dbg_verify_dinode(dentry); ++ } else { ++ /* fill empty slots */ ++ if (dinfo->di_bstart > tmp->di_bstart) ++ dinfo->di_bstart = tmp->di_bstart; ++ if (dinfo->di_bend < tmp->di_bend) ++ dinfo->di_bend = tmp->di_bend; ++ dinfo->di_bwh = tmp->di_bwh; ++ dinfo->di_bdiropq = tmp->di_bdiropq; ++ hd = tmp->di_hdentry; ++ bend = dinfo->di_bend; ++ for (bindex = tmp->di_bstart; bindex <= bend; ++ bindex++) { ++ if (au_h_dptr(dentry, bindex)) ++ continue; ++ h_dentry = hd[bindex].hd_dentry; ++ if (!h_dentry) ++ continue; ++ h_inode = h_dentry->d_inode; ++ AuDebugOn(!h_inode); ++ AuDebugOn(orig_h.mode ++ != (h_inode->i_mode ++ & S_IFMT)); ++ au_set_h_dptr(dentry, bindex, ++ dget(h_dentry)); ++ } ++ err = au_refresh_hinode(inode, dentry); ++ au_dbg_verify_dinode(dentry); ++ } ++ } else { ++ AuDbg("positive --> positive, different type\n"); ++ /* similar to the behaviour of removing and creating */ ++ au_hide(dentry); ++ if (inode) ++ err = au_refresh_hinode_self(inode); ++ au_dbg_verify_dinode(dentry); ++ } ++ } ++ ++out: ++ return err; ++} ++ ++void au_refresh_dop(struct dentry *dentry, int force_reval) ++{ ++ const struct dentry_operations *dop ++ = force_reval ? &aufs_dop : dentry->d_sb->s_d_op; ++ static const unsigned int mask ++ = DCACHE_OP_REVALIDATE | DCACHE_OP_WEAK_REVALIDATE; ++ ++ BUILD_BUG_ON(sizeof(mask) != sizeof(dentry->d_flags)); ++ ++ if (dentry->d_op == dop) ++ return; ++ ++ AuDbg("%pd\n", dentry); ++ spin_lock(&dentry->d_lock); ++ if (dop == &aufs_dop) ++ dentry->d_flags |= mask; ++ else ++ dentry->d_flags &= ~mask; ++ dentry->d_op = dop; ++ spin_unlock(&dentry->d_lock); ++} ++ ++int au_refresh_dentry(struct dentry *dentry, struct dentry *parent) ++{ ++ int err, ebrange; ++ unsigned int sigen; ++ struct au_dinfo *dinfo, *tmp; ++ struct super_block *sb; ++ struct inode *inode; ++ ++ DiMustWriteLock(dentry); ++ AuDebugOn(IS_ROOT(dentry)); ++ AuDebugOn(!parent->d_inode); ++ ++ sb = dentry->d_sb; ++ inode = dentry->d_inode; ++ sigen = au_sigen(sb); ++ err = au_digen_test(parent, sigen); ++ if (unlikely(err)) ++ goto out; ++ ++ dinfo = au_di(dentry); ++ err = au_di_realloc(dinfo, au_sbend(sb) + 1); ++ if (unlikely(err)) ++ goto out; ++ ebrange = au_dbrange_test(dentry); ++ if (!ebrange) ++ ebrange = au_do_refresh_hdentry(dentry, parent); ++ ++ if (d_unhashed(dentry) || ebrange /* || dinfo->di_tmpfile */) { ++ AuDebugOn(au_dbstart(dentry) < 0 && au_dbend(dentry) >= 0); ++ if (inode) ++ err = au_refresh_hinode_self(inode); ++ au_dbg_verify_dinode(dentry); ++ if (!err) ++ goto out_dgen; /* success */ ++ goto out; ++ } ++ ++ /* temporary dinfo */ ++ AuDbgDentry(dentry); ++ err = -ENOMEM; ++ tmp = au_di_alloc(sb, AuLsc_DI_TMP); ++ if (unlikely(!tmp)) ++ goto out; ++ au_di_swap(tmp, dinfo); ++ /* returns the number of positive dentries */ ++ /* ++ * if current working dir is removed, it returns an error. ++ * but the dentry is legal. ++ */ ++ err = au_lkup_dentry(dentry, /*bstart*/0, /*type*/0); ++ AuDbgDentry(dentry); ++ au_di_swap(tmp, dinfo); ++ if (err == -ENOENT) ++ err = 0; ++ if (err >= 0) { ++ /* compare/refresh by dinfo */ ++ AuDbgDentry(dentry); ++ err = au_refresh_by_dinfo(dentry, dinfo, tmp); ++ au_dbg_verify_dinode(dentry); ++ AuTraceErr(err); ++ } ++ au_rw_write_unlock(&tmp->di_rwsem); ++ au_di_free(tmp); ++ if (unlikely(err)) ++ goto out; ++ ++out_dgen: ++ au_update_digen(dentry); ++out: ++ if (unlikely(err && !(dentry->d_flags & DCACHE_NFSFS_RENAMED))) { ++ AuIOErr("failed refreshing %pd, %d\n", dentry, err); ++ AuDbgDentry(dentry); ++ } ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_do_h_d_reval(struct dentry *h_dentry, unsigned int flags, ++ struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ int err, valid; ++ ++ err = 0; ++ if (!(h_dentry->d_flags & DCACHE_OP_REVALIDATE)) ++ goto out; ++ ++ AuDbg("b%d\n", bindex); ++ /* ++ * gave up supporting LOOKUP_CREATE/OPEN for lower fs, ++ * due to whiteout and branch permission. ++ */ ++ flags &= ~(/*LOOKUP_PARENT |*/ LOOKUP_OPEN | LOOKUP_CREATE ++ | LOOKUP_FOLLOW | LOOKUP_EXCL); ++ /* it may return tri-state */ ++ valid = h_dentry->d_op->d_revalidate(h_dentry, flags); ++ ++ if (unlikely(valid < 0)) ++ err = valid; ++ else if (!valid) ++ err = -EINVAL; ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* todo: remove this */ ++static int h_d_revalidate(struct dentry *dentry, struct inode *inode, ++ unsigned int flags, int do_udba) ++{ ++ int err; ++ umode_t mode, h_mode; ++ aufs_bindex_t bindex, btail, bstart, ibs, ibe; ++ unsigned char plus, unhashed, is_root, h_plus, h_nfs, tmpfile; ++ struct inode *h_inode, *h_cached_inode; ++ struct dentry *h_dentry; ++ struct qstr *name, *h_name; ++ ++ err = 0; ++ plus = 0; ++ mode = 0; ++ ibs = -1; ++ ibe = -1; ++ unhashed = !!d_unhashed(dentry); ++ is_root = !!IS_ROOT(dentry); ++ name = &dentry->d_name; ++ tmpfile = au_di(dentry)->di_tmpfile; ++ ++ /* ++ * Theoretically, REVAL test should be unnecessary in case of ++ * {FS,I}NOTIFY. ++ * But {fs,i}notify doesn't fire some necessary events, ++ * IN_ATTRIB for atime/nlink/pageio ++ * Let's do REVAL test too. ++ */ ++ if (do_udba && inode) { ++ mode = (inode->i_mode & S_IFMT); ++ plus = (inode->i_nlink > 0); ++ ibs = au_ibstart(inode); ++ ibe = au_ibend(inode); ++ } ++ ++ bstart = au_dbstart(dentry); ++ btail = bstart; ++ if (inode && S_ISDIR(inode->i_mode)) ++ btail = au_dbtaildir(dentry); ++ for (bindex = bstart; bindex <= btail; bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!h_dentry) ++ continue; ++ ++ AuDbg("b%d, %pd\n", bindex, h_dentry); ++ h_nfs = !!au_test_nfs(h_dentry->d_sb); ++ spin_lock(&h_dentry->d_lock); ++ h_name = &h_dentry->d_name; ++ if (unlikely(do_udba ++ && !is_root ++ && ((!h_nfs ++ && (unhashed != !!d_unhashed(h_dentry) ++ || (!tmpfile ++ && !au_qstreq(name, h_name)) ++ )) ++ || (h_nfs ++ && !(flags & LOOKUP_OPEN) ++ && (h_dentry->d_flags ++ & DCACHE_NFSFS_RENAMED))) ++ )) { ++ int h_unhashed; ++ ++ h_unhashed = d_unhashed(h_dentry); ++ spin_unlock(&h_dentry->d_lock); ++ AuDbg("unhash 0x%x 0x%x, %pd %pd\n", ++ unhashed, h_unhashed, dentry, h_dentry); ++ goto err; ++ } ++ spin_unlock(&h_dentry->d_lock); ++ ++ err = au_do_h_d_reval(h_dentry, flags, dentry, bindex); ++ if (unlikely(err)) ++ /* do not goto err, to keep the errno */ ++ break; ++ ++ /* todo: plink too? */ ++ if (!do_udba) ++ continue; ++ ++ /* UDBA tests */ ++ h_inode = h_dentry->d_inode; ++ if (unlikely(!!inode != !!h_inode)) ++ goto err; ++ ++ h_plus = plus; ++ h_mode = mode; ++ h_cached_inode = h_inode; ++ if (h_inode) { ++ h_mode = (h_inode->i_mode & S_IFMT); ++ h_plus = (h_inode->i_nlink > 0); ++ } ++ if (inode && ibs <= bindex && bindex <= ibe) ++ h_cached_inode = au_h_iptr(inode, bindex); ++ ++ if (!h_nfs) { ++ if (unlikely(plus != h_plus && !tmpfile)) ++ goto err; ++ } else { ++ if (unlikely(!(h_dentry->d_flags & DCACHE_NFSFS_RENAMED) ++ && !is_root ++ && !IS_ROOT(h_dentry) ++ && unhashed != d_unhashed(h_dentry))) ++ goto err; ++ } ++ if (unlikely(mode != h_mode ++ || h_cached_inode != h_inode)) ++ goto err; ++ continue; ++ ++err: ++ err = -EINVAL; ++ break; ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++/* todo: consolidate with do_refresh() and au_reval_for_attr() */ ++static int simple_reval_dpath(struct dentry *dentry, unsigned int sigen) ++{ ++ int err; ++ struct dentry *parent; ++ ++ if (!au_digen_test(dentry, sigen)) ++ return 0; ++ ++ parent = dget_parent(dentry); ++ di_read_lock_parent(parent, AuLock_IR); ++ AuDebugOn(au_digen_test(parent, sigen)); ++ au_dbg_verify_gen(parent, sigen); ++ err = au_refresh_dentry(dentry, parent); ++ di_read_unlock(parent, AuLock_IR); ++ dput(parent); ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_reval_dpath(struct dentry *dentry, unsigned int sigen) ++{ ++ int err; ++ struct dentry *d, *parent; ++ struct inode *inode; ++ ++ if (!au_ftest_si(au_sbi(dentry->d_sb), FAILED_REFRESH_DIR)) ++ return simple_reval_dpath(dentry, sigen); ++ ++ /* slow loop, keep it simple and stupid */ ++ /* cf: au_cpup_dirs() */ ++ err = 0; ++ parent = NULL; ++ while (au_digen_test(dentry, sigen)) { ++ d = dentry; ++ while (1) { ++ dput(parent); ++ parent = dget_parent(d); ++ if (!au_digen_test(parent, sigen)) ++ break; ++ d = parent; ++ } ++ ++ inode = d->d_inode; ++ if (d != dentry) ++ di_write_lock_child2(d); ++ ++ /* someone might update our dentry while we were sleeping */ ++ if (au_digen_test(d, sigen)) { ++ /* ++ * todo: consolidate with simple_reval_dpath(), ++ * do_refresh() and au_reval_for_attr(). ++ */ ++ di_read_lock_parent(parent, AuLock_IR); ++ err = au_refresh_dentry(d, parent); ++ di_read_unlock(parent, AuLock_IR); ++ } ++ ++ if (d != dentry) ++ di_write_unlock(d); ++ dput(parent); ++ if (unlikely(err)) ++ break; ++ } ++ ++ return err; ++} ++ ++/* ++ * if valid returns 1, otherwise 0. ++ */ ++static int aufs_d_revalidate(struct dentry *dentry, unsigned int flags) ++{ ++ int valid, err; ++ unsigned int sigen; ++ unsigned char do_udba; ++ struct super_block *sb; ++ struct inode *inode; ++ ++ /* todo: support rcu-walk? */ ++ if (flags & LOOKUP_RCU) ++ return -ECHILD; ++ ++ valid = 0; ++ if (unlikely(!au_di(dentry))) ++ goto out; ++ ++ valid = 1; ++ sb = dentry->d_sb; ++ /* ++ * todo: very ugly ++ * i_mutex of parent dir may be held, ++ * but we should not return 'invalid' due to busy. ++ */ ++ err = aufs_read_lock(dentry, AuLock_FLUSH | AuLock_DW | AuLock_NOPLM); ++ if (unlikely(err)) { ++ valid = err; ++ AuTraceErr(err); ++ goto out; ++ } ++ inode = dentry->d_inode; ++ if (unlikely(inode && is_bad_inode(inode))) { ++ err = -EINVAL; ++ AuTraceErr(err); ++ goto out_dgrade; ++ } ++ if (unlikely(au_dbrange_test(dentry))) { ++ err = -EINVAL; ++ AuTraceErr(err); ++ goto out_dgrade; ++ } ++ ++ sigen = au_sigen(sb); ++ if (au_digen_test(dentry, sigen)) { ++ AuDebugOn(IS_ROOT(dentry)); ++ err = au_reval_dpath(dentry, sigen); ++ if (unlikely(err)) { ++ AuTraceErr(err); ++ goto out_dgrade; ++ } ++ } ++ di_downgrade_lock(dentry, AuLock_IR); ++ ++ err = -EINVAL; ++ if (!(flags & (LOOKUP_OPEN | LOOKUP_EMPTY)) ++ && inode ++ && !(inode->i_state && I_LINKABLE) ++ && (IS_DEADDIR(inode) || !inode->i_nlink)) { ++ AuTraceErr(err); ++ goto out_inval; ++ } ++ ++ do_udba = !au_opt_test(au_mntflags(sb), UDBA_NONE); ++ if (do_udba && inode) { ++ aufs_bindex_t bstart = au_ibstart(inode); ++ struct inode *h_inode; ++ ++ if (bstart >= 0) { ++ h_inode = au_h_iptr(inode, bstart); ++ if (h_inode && au_test_higen(inode, h_inode)) { ++ AuTraceErr(err); ++ goto out_inval; ++ } ++ } ++ } ++ ++ err = h_d_revalidate(dentry, inode, flags, do_udba); ++ if (unlikely(!err && do_udba && au_dbstart(dentry) < 0)) { ++ err = -EIO; ++ AuDbg("both of real entry and whiteout found, %p, err %d\n", ++ dentry, err); ++ } ++ goto out_inval; ++ ++out_dgrade: ++ di_downgrade_lock(dentry, AuLock_IR); ++out_inval: ++ aufs_read_unlock(dentry, AuLock_IR); ++ AuTraceErr(err); ++ valid = !err; ++out: ++ if (!valid) { ++ AuDbg("%pd invalid, %d\n", dentry, valid); ++ d_drop(dentry); ++ } ++ return valid; ++} ++ ++static void aufs_d_release(struct dentry *dentry) ++{ ++ if (au_di(dentry)) { ++ au_di_fin(dentry); ++ au_hn_di_reinit(dentry); ++ } ++} ++ ++const struct dentry_operations aufs_dop = { ++ .d_revalidate = aufs_d_revalidate, ++ .d_weak_revalidate = aufs_d_revalidate, ++ .d_release = aufs_d_release ++}; ++ ++/* aufs_dop without d_revalidate */ ++const struct dentry_operations aufs_dop_noreval = { ++ .d_release = aufs_d_release ++}; +diff --git a/fs/aufs/dentry.h b/fs/aufs/dentry.h +new file mode 100644 +index 0000000..4006484 +--- /dev/null ++++ b/fs/aufs/dentry.h +@@ -0,0 +1,234 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * lookup and dentry operations ++ */ ++ ++#ifndef __AUFS_DENTRY_H__ ++#define __AUFS_DENTRY_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include "rwsem.h" ++ ++struct au_hdentry { ++ struct dentry *hd_dentry; ++ aufs_bindex_t hd_id; ++}; ++ ++struct au_dinfo { ++ atomic_t di_generation; ++ ++ struct au_rwsem di_rwsem; ++ aufs_bindex_t di_bstart, di_bend, di_bwh, di_bdiropq; ++ unsigned char di_tmpfile; /* to allow the different name */ ++ struct au_hdentry *di_hdentry; ++} ____cacheline_aligned_in_smp; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* dentry.c */ ++extern const struct dentry_operations aufs_dop, aufs_dop_noreval; ++struct au_branch; ++struct dentry *au_sio_lkup_one(struct qstr *name, struct dentry *parent); ++int au_h_verify(struct dentry *h_dentry, unsigned int udba, struct inode *h_dir, ++ struct dentry *h_parent, struct au_branch *br); ++ ++int au_lkup_dentry(struct dentry *dentry, aufs_bindex_t bstart, mode_t type); ++int au_lkup_neg(struct dentry *dentry, aufs_bindex_t bindex, int wh); ++int au_refresh_dentry(struct dentry *dentry, struct dentry *parent); ++int au_reval_dpath(struct dentry *dentry, unsigned int sigen); ++void au_refresh_dop(struct dentry *dentry, int force_reval); ++ ++/* dinfo.c */ ++void au_di_init_once(void *_di); ++struct au_dinfo *au_di_alloc(struct super_block *sb, unsigned int lsc); ++void au_di_free(struct au_dinfo *dinfo); ++void au_di_swap(struct au_dinfo *a, struct au_dinfo *b); ++void au_di_cp(struct au_dinfo *dst, struct au_dinfo *src); ++int au_di_init(struct dentry *dentry); ++void au_di_fin(struct dentry *dentry); ++int au_di_realloc(struct au_dinfo *dinfo, int nbr); ++ ++void di_read_lock(struct dentry *d, int flags, unsigned int lsc); ++void di_read_unlock(struct dentry *d, int flags); ++void di_downgrade_lock(struct dentry *d, int flags); ++void di_write_lock(struct dentry *d, unsigned int lsc); ++void di_write_unlock(struct dentry *d); ++void di_write_lock2_child(struct dentry *d1, struct dentry *d2, int isdir); ++void di_write_lock2_parent(struct dentry *d1, struct dentry *d2, int isdir); ++void di_write_unlock2(struct dentry *d1, struct dentry *d2); ++ ++struct dentry *au_h_dptr(struct dentry *dentry, aufs_bindex_t bindex); ++struct dentry *au_h_d_alias(struct dentry *dentry, aufs_bindex_t bindex); ++aufs_bindex_t au_dbtail(struct dentry *dentry); ++aufs_bindex_t au_dbtaildir(struct dentry *dentry); ++ ++void au_set_h_dptr(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_dentry); ++int au_digen_test(struct dentry *dentry, unsigned int sigen); ++int au_dbrange_test(struct dentry *dentry); ++void au_update_digen(struct dentry *dentry); ++void au_update_dbrange(struct dentry *dentry, int do_put_zero); ++void au_update_dbstart(struct dentry *dentry); ++void au_update_dbend(struct dentry *dentry); ++int au_find_dbindex(struct dentry *dentry, struct dentry *h_dentry); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct au_dinfo *au_di(struct dentry *dentry) ++{ ++ return dentry->d_fsdata; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* lock subclass for dinfo */ ++enum { ++ AuLsc_DI_CHILD, /* child first */ ++ AuLsc_DI_CHILD2, /* rename(2), link(2), and cpup at hnotify */ ++ AuLsc_DI_CHILD3, /* copyup dirs */ ++ AuLsc_DI_PARENT, ++ AuLsc_DI_PARENT2, ++ AuLsc_DI_PARENT3, ++ AuLsc_DI_TMP /* temp for replacing dinfo */ ++}; ++ ++/* ++ * di_read_lock_child, di_write_lock_child, ++ * di_read_lock_child2, di_write_lock_child2, ++ * di_read_lock_child3, di_write_lock_child3, ++ * di_read_lock_parent, di_write_lock_parent, ++ * di_read_lock_parent2, di_write_lock_parent2, ++ * di_read_lock_parent3, di_write_lock_parent3, ++ */ ++#define AuReadLockFunc(name, lsc) \ ++static inline void di_read_lock_##name(struct dentry *d, int flags) \ ++{ di_read_lock(d, flags, AuLsc_DI_##lsc); } ++ ++#define AuWriteLockFunc(name, lsc) \ ++static inline void di_write_lock_##name(struct dentry *d) \ ++{ di_write_lock(d, AuLsc_DI_##lsc); } ++ ++#define AuRWLockFuncs(name, lsc) \ ++ AuReadLockFunc(name, lsc) \ ++ AuWriteLockFunc(name, lsc) ++ ++AuRWLockFuncs(child, CHILD); ++AuRWLockFuncs(child2, CHILD2); ++AuRWLockFuncs(child3, CHILD3); ++AuRWLockFuncs(parent, PARENT); ++AuRWLockFuncs(parent2, PARENT2); ++AuRWLockFuncs(parent3, PARENT3); ++ ++#undef AuReadLockFunc ++#undef AuWriteLockFunc ++#undef AuRWLockFuncs ++ ++#define DiMustNoWaiters(d) AuRwMustNoWaiters(&au_di(d)->di_rwsem) ++#define DiMustAnyLock(d) AuRwMustAnyLock(&au_di(d)->di_rwsem) ++#define DiMustWriteLock(d) AuRwMustWriteLock(&au_di(d)->di_rwsem) ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* todo: memory barrier? */ ++static inline unsigned int au_digen(struct dentry *d) ++{ ++ return atomic_read(&au_di(d)->di_generation); ++} ++ ++static inline void au_h_dentry_init(struct au_hdentry *hdentry) ++{ ++ hdentry->hd_dentry = NULL; ++} ++ ++static inline void au_hdput(struct au_hdentry *hd) ++{ ++ if (hd) ++ dput(hd->hd_dentry); ++} ++ ++static inline aufs_bindex_t au_dbstart(struct dentry *dentry) ++{ ++ DiMustAnyLock(dentry); ++ return au_di(dentry)->di_bstart; ++} ++ ++static inline aufs_bindex_t au_dbend(struct dentry *dentry) ++{ ++ DiMustAnyLock(dentry); ++ return au_di(dentry)->di_bend; ++} ++ ++static inline aufs_bindex_t au_dbwh(struct dentry *dentry) ++{ ++ DiMustAnyLock(dentry); ++ return au_di(dentry)->di_bwh; ++} ++ ++static inline aufs_bindex_t au_dbdiropq(struct dentry *dentry) ++{ ++ DiMustAnyLock(dentry); ++ return au_di(dentry)->di_bdiropq; ++} ++ ++/* todo: hard/soft set? */ ++static inline void au_set_dbstart(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ DiMustWriteLock(dentry); ++ au_di(dentry)->di_bstart = bindex; ++} ++ ++static inline void au_set_dbend(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ DiMustWriteLock(dentry); ++ au_di(dentry)->di_bend = bindex; ++} ++ ++static inline void au_set_dbwh(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ DiMustWriteLock(dentry); ++ /* dbwh can be outside of bstart - bend range */ ++ au_di(dentry)->di_bwh = bindex; ++} ++ ++static inline void au_set_dbdiropq(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ DiMustWriteLock(dentry); ++ au_di(dentry)->di_bdiropq = bindex; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_HNOTIFY ++static inline void au_digen_dec(struct dentry *d) ++{ ++ atomic_dec(&au_di(d)->di_generation); ++} ++ ++static inline void au_hn_di_reinit(struct dentry *dentry) ++{ ++ dentry->d_fsdata = NULL; ++} ++#else ++AuStubVoid(au_hn_di_reinit, struct dentry *dentry __maybe_unused) ++#endif /* CONFIG_AUFS_HNOTIFY */ ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_DENTRY_H__ */ +diff --git a/fs/aufs/dinfo.c b/fs/aufs/dinfo.c +new file mode 100644 +index 0000000..28c02b3 +--- /dev/null ++++ b/fs/aufs/dinfo.c +@@ -0,0 +1,544 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * dentry private data ++ */ ++ ++#include "aufs.h" ++ ++void au_di_init_once(void *_dinfo) ++{ ++ struct au_dinfo *dinfo = _dinfo; ++ static struct lock_class_key aufs_di; ++ ++ au_rw_init(&dinfo->di_rwsem); ++ au_rw_class(&dinfo->di_rwsem, &aufs_di); ++} ++ ++struct au_dinfo *au_di_alloc(struct super_block *sb, unsigned int lsc) ++{ ++ struct au_dinfo *dinfo; ++ int nbr, i; ++ ++ dinfo = au_cache_alloc_dinfo(); ++ if (unlikely(!dinfo)) ++ goto out; ++ ++ nbr = au_sbend(sb) + 1; ++ if (nbr <= 0) ++ nbr = 1; ++ dinfo->di_hdentry = kcalloc(nbr, sizeof(*dinfo->di_hdentry), GFP_NOFS); ++ if (dinfo->di_hdentry) { ++ au_rw_write_lock_nested(&dinfo->di_rwsem, lsc); ++ dinfo->di_bstart = -1; ++ dinfo->di_bend = -1; ++ dinfo->di_bwh = -1; ++ dinfo->di_bdiropq = -1; ++ dinfo->di_tmpfile = 0; ++ for (i = 0; i < nbr; i++) ++ dinfo->di_hdentry[i].hd_id = -1; ++ goto out; ++ } ++ ++ au_cache_free_dinfo(dinfo); ++ dinfo = NULL; ++ ++out: ++ return dinfo; ++} ++ ++void au_di_free(struct au_dinfo *dinfo) ++{ ++ struct au_hdentry *p; ++ aufs_bindex_t bend, bindex; ++ ++ /* dentry may not be revalidated */ ++ bindex = dinfo->di_bstart; ++ if (bindex >= 0) { ++ bend = dinfo->di_bend; ++ p = dinfo->di_hdentry + bindex; ++ while (bindex++ <= bend) ++ au_hdput(p++); ++ } ++ kfree(dinfo->di_hdentry); ++ au_cache_free_dinfo(dinfo); ++} ++ ++void au_di_swap(struct au_dinfo *a, struct au_dinfo *b) ++{ ++ struct au_hdentry *p; ++ aufs_bindex_t bi; ++ ++ AuRwMustWriteLock(&a->di_rwsem); ++ AuRwMustWriteLock(&b->di_rwsem); ++ ++#define DiSwap(v, name) \ ++ do { \ ++ v = a->di_##name; \ ++ a->di_##name = b->di_##name; \ ++ b->di_##name = v; \ ++ } while (0) ++ ++ DiSwap(p, hdentry); ++ DiSwap(bi, bstart); ++ DiSwap(bi, bend); ++ DiSwap(bi, bwh); ++ DiSwap(bi, bdiropq); ++ /* smp_mb(); */ ++ ++#undef DiSwap ++} ++ ++void au_di_cp(struct au_dinfo *dst, struct au_dinfo *src) ++{ ++ AuRwMustWriteLock(&dst->di_rwsem); ++ AuRwMustWriteLock(&src->di_rwsem); ++ ++ dst->di_bstart = src->di_bstart; ++ dst->di_bend = src->di_bend; ++ dst->di_bwh = src->di_bwh; ++ dst->di_bdiropq = src->di_bdiropq; ++ /* smp_mb(); */ ++} ++ ++int au_di_init(struct dentry *dentry) ++{ ++ int err; ++ struct super_block *sb; ++ struct au_dinfo *dinfo; ++ ++ err = 0; ++ sb = dentry->d_sb; ++ dinfo = au_di_alloc(sb, AuLsc_DI_CHILD); ++ if (dinfo) { ++ atomic_set(&dinfo->di_generation, au_sigen(sb)); ++ /* smp_mb(); */ /* atomic_set */ ++ dentry->d_fsdata = dinfo; ++ } else ++ err = -ENOMEM; ++ ++ return err; ++} ++ ++void au_di_fin(struct dentry *dentry) ++{ ++ struct au_dinfo *dinfo; ++ ++ dinfo = au_di(dentry); ++ AuRwDestroy(&dinfo->di_rwsem); ++ au_di_free(dinfo); ++} ++ ++int au_di_realloc(struct au_dinfo *dinfo, int nbr) ++{ ++ int err, sz; ++ struct au_hdentry *hdp; ++ ++ AuRwMustWriteLock(&dinfo->di_rwsem); ++ ++ err = -ENOMEM; ++ sz = sizeof(*hdp) * (dinfo->di_bend + 1); ++ if (!sz) ++ sz = sizeof(*hdp); ++ hdp = au_kzrealloc(dinfo->di_hdentry, sz, sizeof(*hdp) * nbr, GFP_NOFS); ++ if (hdp) { ++ dinfo->di_hdentry = hdp; ++ err = 0; ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void do_ii_write_lock(struct inode *inode, unsigned int lsc) ++{ ++ switch (lsc) { ++ case AuLsc_DI_CHILD: ++ ii_write_lock_child(inode); ++ break; ++ case AuLsc_DI_CHILD2: ++ ii_write_lock_child2(inode); ++ break; ++ case AuLsc_DI_CHILD3: ++ ii_write_lock_child3(inode); ++ break; ++ case AuLsc_DI_PARENT: ++ ii_write_lock_parent(inode); ++ break; ++ case AuLsc_DI_PARENT2: ++ ii_write_lock_parent2(inode); ++ break; ++ case AuLsc_DI_PARENT3: ++ ii_write_lock_parent3(inode); ++ break; ++ default: ++ BUG(); ++ } ++} ++ ++static void do_ii_read_lock(struct inode *inode, unsigned int lsc) ++{ ++ switch (lsc) { ++ case AuLsc_DI_CHILD: ++ ii_read_lock_child(inode); ++ break; ++ case AuLsc_DI_CHILD2: ++ ii_read_lock_child2(inode); ++ break; ++ case AuLsc_DI_CHILD3: ++ ii_read_lock_child3(inode); ++ break; ++ case AuLsc_DI_PARENT: ++ ii_read_lock_parent(inode); ++ break; ++ case AuLsc_DI_PARENT2: ++ ii_read_lock_parent2(inode); ++ break; ++ case AuLsc_DI_PARENT3: ++ ii_read_lock_parent3(inode); ++ break; ++ default: ++ BUG(); ++ } ++} ++ ++void di_read_lock(struct dentry *d, int flags, unsigned int lsc) ++{ ++ au_rw_read_lock_nested(&au_di(d)->di_rwsem, lsc); ++ if (d->d_inode) { ++ if (au_ftest_lock(flags, IW)) ++ do_ii_write_lock(d->d_inode, lsc); ++ else if (au_ftest_lock(flags, IR)) ++ do_ii_read_lock(d->d_inode, lsc); ++ } ++} ++ ++void di_read_unlock(struct dentry *d, int flags) ++{ ++ if (d->d_inode) { ++ if (au_ftest_lock(flags, IW)) { ++ au_dbg_verify_dinode(d); ++ ii_write_unlock(d->d_inode); ++ } else if (au_ftest_lock(flags, IR)) { ++ au_dbg_verify_dinode(d); ++ ii_read_unlock(d->d_inode); ++ } ++ } ++ au_rw_read_unlock(&au_di(d)->di_rwsem); ++} ++ ++void di_downgrade_lock(struct dentry *d, int flags) ++{ ++ if (d->d_inode && au_ftest_lock(flags, IR)) ++ ii_downgrade_lock(d->d_inode); ++ au_rw_dgrade_lock(&au_di(d)->di_rwsem); ++} ++ ++void di_write_lock(struct dentry *d, unsigned int lsc) ++{ ++ au_rw_write_lock_nested(&au_di(d)->di_rwsem, lsc); ++ if (d->d_inode) ++ do_ii_write_lock(d->d_inode, lsc); ++} ++ ++void di_write_unlock(struct dentry *d) ++{ ++ au_dbg_verify_dinode(d); ++ if (d->d_inode) ++ ii_write_unlock(d->d_inode); ++ au_rw_write_unlock(&au_di(d)->di_rwsem); ++} ++ ++void di_write_lock2_child(struct dentry *d1, struct dentry *d2, int isdir) ++{ ++ AuDebugOn(d1 == d2 ++ || d1->d_inode == d2->d_inode ++ || d1->d_sb != d2->d_sb); ++ ++ if (isdir && au_test_subdir(d1, d2)) { ++ di_write_lock_child(d1); ++ di_write_lock_child2(d2); ++ } else { ++ /* there should be no races */ ++ di_write_lock_child(d2); ++ di_write_lock_child2(d1); ++ } ++} ++ ++void di_write_lock2_parent(struct dentry *d1, struct dentry *d2, int isdir) ++{ ++ AuDebugOn(d1 == d2 ++ || d1->d_inode == d2->d_inode ++ || d1->d_sb != d2->d_sb); ++ ++ if (isdir && au_test_subdir(d1, d2)) { ++ di_write_lock_parent(d1); ++ di_write_lock_parent2(d2); ++ } else { ++ /* there should be no races */ ++ di_write_lock_parent(d2); ++ di_write_lock_parent2(d1); ++ } ++} ++ ++void di_write_unlock2(struct dentry *d1, struct dentry *d2) ++{ ++ di_write_unlock(d1); ++ if (d1->d_inode == d2->d_inode) ++ au_rw_write_unlock(&au_di(d2)->di_rwsem); ++ else ++ di_write_unlock(d2); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct dentry *au_h_dptr(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ struct dentry *d; ++ ++ DiMustAnyLock(dentry); ++ ++ if (au_dbstart(dentry) < 0 || bindex < au_dbstart(dentry)) ++ return NULL; ++ AuDebugOn(bindex < 0); ++ d = au_di(dentry)->di_hdentry[0 + bindex].hd_dentry; ++ AuDebugOn(d && au_dcount(d) <= 0); ++ return d; ++} ++ ++/* ++ * extended version of au_h_dptr(). ++ * returns a hashed and positive (or linkable) h_dentry in bindex, NULL, or ++ * error. ++ */ ++struct dentry *au_h_d_alias(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ struct dentry *h_dentry; ++ struct inode *inode, *h_inode; ++ ++ inode = dentry->d_inode; ++ AuDebugOn(!inode); ++ ++ h_dentry = NULL; ++ if (au_dbstart(dentry) <= bindex ++ && bindex <= au_dbend(dentry)) ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (h_dentry && !au_d_linkable(h_dentry)) { ++ dget(h_dentry); ++ goto out; /* success */ ++ } ++ ++ AuDebugOn(bindex < au_ibstart(inode)); ++ AuDebugOn(au_ibend(inode) < bindex); ++ h_inode = au_h_iptr(inode, bindex); ++ h_dentry = d_find_alias(h_inode); ++ if (h_dentry) { ++ if (!IS_ERR(h_dentry)) { ++ if (!au_d_linkable(h_dentry)) ++ goto out; /* success */ ++ dput(h_dentry); ++ } else ++ goto out; ++ } ++ ++ if (au_opt_test(au_mntflags(dentry->d_sb), PLINK)) { ++ h_dentry = au_plink_lkup(inode, bindex); ++ AuDebugOn(!h_dentry); ++ if (!IS_ERR(h_dentry)) { ++ if (!au_d_hashed_positive(h_dentry)) ++ goto out; /* success */ ++ dput(h_dentry); ++ h_dentry = NULL; ++ } ++ } ++ ++out: ++ AuDbgDentry(h_dentry); ++ return h_dentry; ++} ++ ++aufs_bindex_t au_dbtail(struct dentry *dentry) ++{ ++ aufs_bindex_t bend, bwh; ++ ++ bend = au_dbend(dentry); ++ if (0 <= bend) { ++ bwh = au_dbwh(dentry); ++ if (!bwh) ++ return bwh; ++ if (0 < bwh && bwh < bend) ++ return bwh - 1; ++ } ++ return bend; ++} ++ ++aufs_bindex_t au_dbtaildir(struct dentry *dentry) ++{ ++ aufs_bindex_t bend, bopq; ++ ++ bend = au_dbtail(dentry); ++ if (0 <= bend) { ++ bopq = au_dbdiropq(dentry); ++ if (0 <= bopq && bopq < bend) ++ bend = bopq; ++ } ++ return bend; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_set_h_dptr(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_dentry) ++{ ++ struct au_hdentry *hd = au_di(dentry)->di_hdentry + bindex; ++ struct au_branch *br; ++ ++ DiMustWriteLock(dentry); ++ ++ au_hdput(hd); ++ hd->hd_dentry = h_dentry; ++ if (h_dentry) { ++ br = au_sbr(dentry->d_sb, bindex); ++ hd->hd_id = br->br_id; ++ } ++} ++ ++int au_dbrange_test(struct dentry *dentry) ++{ ++ int err; ++ aufs_bindex_t bstart, bend; ++ ++ err = 0; ++ bstart = au_dbstart(dentry); ++ bend = au_dbend(dentry); ++ if (bstart >= 0) ++ AuDebugOn(bend < 0 && bstart > bend); ++ else { ++ err = -EIO; ++ AuDebugOn(bend >= 0); ++ } ++ ++ return err; ++} ++ ++int au_digen_test(struct dentry *dentry, unsigned int sigen) ++{ ++ int err; ++ ++ err = 0; ++ if (unlikely(au_digen(dentry) != sigen ++ || au_iigen_test(dentry->d_inode, sigen))) ++ err = -EIO; ++ ++ return err; ++} ++ ++void au_update_digen(struct dentry *dentry) ++{ ++ atomic_set(&au_di(dentry)->di_generation, au_sigen(dentry->d_sb)); ++ /* smp_mb(); */ /* atomic_set */ ++} ++ ++void au_update_dbrange(struct dentry *dentry, int do_put_zero) ++{ ++ struct au_dinfo *dinfo; ++ struct dentry *h_d; ++ struct au_hdentry *hdp; ++ ++ DiMustWriteLock(dentry); ++ ++ dinfo = au_di(dentry); ++ if (!dinfo || dinfo->di_bstart < 0) ++ return; ++ ++ hdp = dinfo->di_hdentry; ++ if (do_put_zero) { ++ aufs_bindex_t bindex, bend; ++ ++ bend = dinfo->di_bend; ++ for (bindex = dinfo->di_bstart; bindex <= bend; bindex++) { ++ h_d = hdp[0 + bindex].hd_dentry; ++ if (h_d && !h_d->d_inode) ++ au_set_h_dptr(dentry, bindex, NULL); ++ } ++ } ++ ++ dinfo->di_bstart = -1; ++ while (++dinfo->di_bstart <= dinfo->di_bend) ++ if (hdp[0 + dinfo->di_bstart].hd_dentry) ++ break; ++ if (dinfo->di_bstart > dinfo->di_bend) { ++ dinfo->di_bstart = -1; ++ dinfo->di_bend = -1; ++ return; ++ } ++ ++ dinfo->di_bend++; ++ while (0 <= --dinfo->di_bend) ++ if (hdp[0 + dinfo->di_bend].hd_dentry) ++ break; ++ AuDebugOn(dinfo->di_bstart > dinfo->di_bend || dinfo->di_bend < 0); ++} ++ ++void au_update_dbstart(struct dentry *dentry) ++{ ++ aufs_bindex_t bindex, bend; ++ struct dentry *h_dentry; ++ ++ bend = au_dbend(dentry); ++ for (bindex = au_dbstart(dentry); bindex <= bend; bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!h_dentry) ++ continue; ++ if (h_dentry->d_inode) { ++ au_set_dbstart(dentry, bindex); ++ return; ++ } ++ au_set_h_dptr(dentry, bindex, NULL); ++ } ++} ++ ++void au_update_dbend(struct dentry *dentry) ++{ ++ aufs_bindex_t bindex, bstart; ++ struct dentry *h_dentry; ++ ++ bstart = au_dbstart(dentry); ++ for (bindex = au_dbend(dentry); bindex >= bstart; bindex--) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!h_dentry) ++ continue; ++ if (h_dentry->d_inode) { ++ au_set_dbend(dentry, bindex); ++ return; ++ } ++ au_set_h_dptr(dentry, bindex, NULL); ++ } ++} ++ ++int au_find_dbindex(struct dentry *dentry, struct dentry *h_dentry) ++{ ++ aufs_bindex_t bindex, bend; ++ ++ bend = au_dbend(dentry); ++ for (bindex = au_dbstart(dentry); bindex <= bend; bindex++) ++ if (au_h_dptr(dentry, bindex) == h_dentry) ++ return bindex; ++ return -1; ++} +diff --git a/fs/aufs/dir.c b/fs/aufs/dir.c +new file mode 100644 +index 0000000..3d61b05 +--- /dev/null ++++ b/fs/aufs/dir.c +@@ -0,0 +1,756 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * directory operations ++ */ ++ ++#include ++#include "aufs.h" ++ ++void au_add_nlink(struct inode *dir, struct inode *h_dir) ++{ ++ unsigned int nlink; ++ ++ AuDebugOn(!S_ISDIR(dir->i_mode) || !S_ISDIR(h_dir->i_mode)); ++ ++ nlink = dir->i_nlink; ++ nlink += h_dir->i_nlink - 2; ++ if (h_dir->i_nlink < 2) ++ nlink += 2; ++ smp_mb(); /* for i_nlink */ ++ /* 0 can happen in revaliding */ ++ set_nlink(dir, nlink); ++} ++ ++void au_sub_nlink(struct inode *dir, struct inode *h_dir) ++{ ++ unsigned int nlink; ++ ++ AuDebugOn(!S_ISDIR(dir->i_mode) || !S_ISDIR(h_dir->i_mode)); ++ ++ nlink = dir->i_nlink; ++ nlink -= h_dir->i_nlink - 2; ++ if (h_dir->i_nlink < 2) ++ nlink -= 2; ++ smp_mb(); /* for i_nlink */ ++ /* nlink == 0 means the branch-fs is broken */ ++ set_nlink(dir, nlink); ++} ++ ++loff_t au_dir_size(struct file *file, struct dentry *dentry) ++{ ++ loff_t sz; ++ aufs_bindex_t bindex, bend; ++ struct file *h_file; ++ struct dentry *h_dentry; ++ ++ sz = 0; ++ if (file) { ++ AuDebugOn(!d_is_dir(file->f_path.dentry)); ++ ++ bend = au_fbend_dir(file); ++ for (bindex = au_fbstart(file); ++ bindex <= bend && sz < KMALLOC_MAX_SIZE; ++ bindex++) { ++ h_file = au_hf_dir(file, bindex); ++ if (h_file && file_inode(h_file)) ++ sz += vfsub_f_size_read(h_file); ++ } ++ } else { ++ AuDebugOn(!dentry); ++ AuDebugOn(!d_is_dir(dentry)); ++ ++ bend = au_dbtaildir(dentry); ++ for (bindex = au_dbstart(dentry); ++ bindex <= bend && sz < KMALLOC_MAX_SIZE; ++ bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (h_dentry && h_dentry->d_inode) ++ sz += i_size_read(h_dentry->d_inode); ++ } ++ } ++ if (sz < KMALLOC_MAX_SIZE) ++ sz = roundup_pow_of_two(sz); ++ if (sz > KMALLOC_MAX_SIZE) ++ sz = KMALLOC_MAX_SIZE; ++ else if (sz < NAME_MAX) { ++ BUILD_BUG_ON(AUFS_RDBLK_DEF < NAME_MAX); ++ sz = AUFS_RDBLK_DEF; ++ } ++ return sz; ++} ++ ++struct au_dir_ts_arg { ++ struct dentry *dentry; ++ aufs_bindex_t brid; ++}; ++ ++static void au_do_dir_ts(void *arg) ++{ ++ struct au_dir_ts_arg *a = arg; ++ struct au_dtime dt; ++ struct path h_path; ++ struct inode *dir, *h_dir; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct au_hinode *hdir; ++ int err; ++ aufs_bindex_t bstart, bindex; ++ ++ sb = a->dentry->d_sb; ++ dir = a->dentry->d_inode; ++ if (!dir) ++ goto out; ++ /* no dir->i_mutex lock */ ++ aufs_read_lock(a->dentry, AuLock_DW); /* noflush */ ++ ++ bstart = au_ibstart(dir); ++ bindex = au_br_index(sb, a->brid); ++ if (bindex < bstart) ++ goto out_unlock; ++ ++ br = au_sbr(sb, bindex); ++ h_path.dentry = au_h_dptr(a->dentry, bindex); ++ if (!h_path.dentry) ++ goto out_unlock; ++ h_path.mnt = au_br_mnt(br); ++ au_dtime_store(&dt, a->dentry, &h_path); ++ ++ br = au_sbr(sb, bstart); ++ if (!au_br_writable(br->br_perm)) ++ goto out_unlock; ++ h_path.dentry = au_h_dptr(a->dentry, bstart); ++ h_path.mnt = au_br_mnt(br); ++ err = vfsub_mnt_want_write(h_path.mnt); ++ if (err) ++ goto out_unlock; ++ hdir = au_hi(dir, bstart); ++ au_hn_imtx_lock_nested(hdir, AuLsc_I_PARENT); ++ h_dir = au_h_iptr(dir, bstart); ++ if (h_dir->i_nlink ++ && timespec_compare(&h_dir->i_mtime, &dt.dt_mtime) < 0) { ++ dt.dt_h_path = h_path; ++ au_dtime_revert(&dt); ++ } ++ au_hn_imtx_unlock(hdir); ++ vfsub_mnt_drop_write(h_path.mnt); ++ au_cpup_attr_timesizes(dir); ++ ++out_unlock: ++ aufs_read_unlock(a->dentry, AuLock_DW); ++out: ++ dput(a->dentry); ++ au_nwt_done(&au_sbi(sb)->si_nowait); ++ kfree(arg); ++} ++ ++void au_dir_ts(struct inode *dir, aufs_bindex_t bindex) ++{ ++ int perm, wkq_err; ++ aufs_bindex_t bstart; ++ struct au_dir_ts_arg *arg; ++ struct dentry *dentry; ++ struct super_block *sb; ++ ++ IMustLock(dir); ++ ++ dentry = d_find_any_alias(dir); ++ AuDebugOn(!dentry); ++ sb = dentry->d_sb; ++ bstart = au_ibstart(dir); ++ if (bstart == bindex) { ++ au_cpup_attr_timesizes(dir); ++ goto out; ++ } ++ ++ perm = au_sbr_perm(sb, bstart); ++ if (!au_br_writable(perm)) ++ goto out; ++ ++ arg = kmalloc(sizeof(*arg), GFP_NOFS); ++ if (!arg) ++ goto out; ++ ++ arg->dentry = dget(dentry); /* will be dput-ted by au_do_dir_ts() */ ++ arg->brid = au_sbr_id(sb, bindex); ++ wkq_err = au_wkq_nowait(au_do_dir_ts, arg, sb, /*flags*/0); ++ if (unlikely(wkq_err)) { ++ pr_err("wkq %d\n", wkq_err); ++ dput(dentry); ++ kfree(arg); ++ } ++ ++out: ++ dput(dentry); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int reopen_dir(struct file *file) ++{ ++ int err; ++ unsigned int flags; ++ aufs_bindex_t bindex, btail, bstart; ++ struct dentry *dentry, *h_dentry; ++ struct file *h_file; ++ ++ /* open all lower dirs */ ++ dentry = file->f_dentry; ++ bstart = au_dbstart(dentry); ++ for (bindex = au_fbstart(file); bindex < bstart; bindex++) ++ au_set_h_fptr(file, bindex, NULL); ++ au_set_fbstart(file, bstart); ++ ++ btail = au_dbtaildir(dentry); ++ for (bindex = au_fbend_dir(file); btail < bindex; bindex--) ++ au_set_h_fptr(file, bindex, NULL); ++ au_set_fbend_dir(file, btail); ++ ++ flags = vfsub_file_flags(file); ++ for (bindex = bstart; bindex <= btail; bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!h_dentry) ++ continue; ++ h_file = au_hf_dir(file, bindex); ++ if (h_file) ++ continue; ++ ++ h_file = au_h_open(dentry, bindex, flags, file, /*force_wr*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; /* close all? */ ++ au_set_h_fptr(file, bindex, h_file); ++ } ++ au_update_figen(file); ++ /* todo: necessary? */ ++ /* file->f_ra = h_file->f_ra; */ ++ err = 0; ++ ++out: ++ return err; ++} ++ ++static int do_open_dir(struct file *file, int flags, struct file *h_file) ++{ ++ int err; ++ aufs_bindex_t bindex, btail; ++ struct dentry *dentry, *h_dentry; ++ struct vfsmount *mnt; ++ ++ FiMustWriteLock(file); ++ AuDebugOn(h_file); ++ ++ err = 0; ++ mnt = file->f_path.mnt; ++ dentry = file->f_dentry; ++ file->f_version = dentry->d_inode->i_version; ++ bindex = au_dbstart(dentry); ++ au_set_fbstart(file, bindex); ++ btail = au_dbtaildir(dentry); ++ au_set_fbend_dir(file, btail); ++ for (; !err && bindex <= btail; bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!h_dentry) ++ continue; ++ ++ err = vfsub_test_mntns(mnt, h_dentry->d_sb); ++ if (unlikely(err)) ++ break; ++ h_file = au_h_open(dentry, bindex, flags, file, /*force_wr*/0); ++ if (IS_ERR(h_file)) { ++ err = PTR_ERR(h_file); ++ break; ++ } ++ au_set_h_fptr(file, bindex, h_file); ++ } ++ au_update_figen(file); ++ /* todo: necessary? */ ++ /* file->f_ra = h_file->f_ra; */ ++ if (!err) ++ return 0; /* success */ ++ ++ /* close all */ ++ for (bindex = au_fbstart(file); bindex <= btail; bindex++) ++ au_set_h_fptr(file, bindex, NULL); ++ au_set_fbstart(file, -1); ++ au_set_fbend_dir(file, -1); ++ ++ return err; ++} ++ ++static int aufs_open_dir(struct inode *inode __maybe_unused, ++ struct file *file) ++{ ++ int err; ++ struct super_block *sb; ++ struct au_fidir *fidir; ++ ++ err = -ENOMEM; ++ sb = file->f_dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ fidir = au_fidir_alloc(sb); ++ if (fidir) { ++ struct au_do_open_args args = { ++ .open = do_open_dir, ++ .fidir = fidir ++ }; ++ err = au_do_open(file, &args); ++ if (unlikely(err)) ++ kfree(fidir); ++ } ++ si_read_unlock(sb); ++ return err; ++} ++ ++static int aufs_release_dir(struct inode *inode __maybe_unused, ++ struct file *file) ++{ ++ struct au_vdir *vdir_cache; ++ struct au_finfo *finfo; ++ struct au_fidir *fidir; ++ aufs_bindex_t bindex, bend; ++ ++ finfo = au_fi(file); ++ fidir = finfo->fi_hdir; ++ if (fidir) { ++ au_sphl_del(&finfo->fi_hlist, ++ &au_sbi(file->f_dentry->d_sb)->si_files); ++ vdir_cache = fidir->fd_vdir_cache; /* lock-free */ ++ if (vdir_cache) ++ au_vdir_free(vdir_cache); ++ ++ bindex = finfo->fi_btop; ++ if (bindex >= 0) { ++ /* ++ * calls fput() instead of filp_close(), ++ * since no dnotify or lock for the lower file. ++ */ ++ bend = fidir->fd_bbot; ++ for (; bindex <= bend; bindex++) ++ au_set_h_fptr(file, bindex, NULL); ++ } ++ kfree(fidir); ++ finfo->fi_hdir = NULL; ++ } ++ au_finfo_fin(file); ++ return 0; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_do_flush_dir(struct file *file, fl_owner_t id) ++{ ++ int err; ++ aufs_bindex_t bindex, bend; ++ struct file *h_file; ++ ++ err = 0; ++ bend = au_fbend_dir(file); ++ for (bindex = au_fbstart(file); !err && bindex <= bend; bindex++) { ++ h_file = au_hf_dir(file, bindex); ++ if (h_file) ++ err = vfsub_flush(h_file, id); ++ } ++ return err; ++} ++ ++static int aufs_flush_dir(struct file *file, fl_owner_t id) ++{ ++ return au_do_flush(file, id, au_do_flush_dir); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_do_fsync_dir_no_file(struct dentry *dentry, int datasync) ++{ ++ int err; ++ aufs_bindex_t bend, bindex; ++ struct inode *inode; ++ struct super_block *sb; ++ ++ err = 0; ++ sb = dentry->d_sb; ++ inode = dentry->d_inode; ++ IMustLock(inode); ++ bend = au_dbend(dentry); ++ for (bindex = au_dbstart(dentry); !err && bindex <= bend; bindex++) { ++ struct path h_path; ++ ++ if (au_test_ro(sb, bindex, inode)) ++ continue; ++ h_path.dentry = au_h_dptr(dentry, bindex); ++ if (!h_path.dentry) ++ continue; ++ ++ h_path.mnt = au_sbr_mnt(sb, bindex); ++ err = vfsub_fsync(NULL, &h_path, datasync); ++ } ++ ++ return err; ++} ++ ++static int au_do_fsync_dir(struct file *file, int datasync) ++{ ++ int err; ++ aufs_bindex_t bend, bindex; ++ struct file *h_file; ++ struct super_block *sb; ++ struct inode *inode; ++ ++ err = au_reval_and_lock_fdi(file, reopen_dir, /*wlock*/1); ++ if (unlikely(err)) ++ goto out; ++ ++ inode = file_inode(file); ++ sb = inode->i_sb; ++ bend = au_fbend_dir(file); ++ for (bindex = au_fbstart(file); !err && bindex <= bend; bindex++) { ++ h_file = au_hf_dir(file, bindex); ++ if (!h_file || au_test_ro(sb, bindex, inode)) ++ continue; ++ ++ err = vfsub_fsync(h_file, &h_file->f_path, datasync); ++ } ++ ++out: ++ return err; ++} ++ ++/* ++ * @file may be NULL ++ */ ++static int aufs_fsync_dir(struct file *file, loff_t start, loff_t end, ++ int datasync) ++{ ++ int err; ++ struct dentry *dentry; ++ struct super_block *sb; ++ struct mutex *mtx; ++ ++ err = 0; ++ dentry = file->f_dentry; ++ mtx = &dentry->d_inode->i_mutex; ++ mutex_lock(mtx); ++ sb = dentry->d_sb; ++ si_noflush_read_lock(sb); ++ if (file) ++ err = au_do_fsync_dir(file, datasync); ++ else { ++ di_write_lock_child(dentry); ++ err = au_do_fsync_dir_no_file(dentry, datasync); ++ } ++ au_cpup_attr_timesizes(dentry->d_inode); ++ di_write_unlock(dentry); ++ if (file) ++ fi_write_unlock(file); ++ ++ si_read_unlock(sb); ++ mutex_unlock(mtx); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int aufs_iterate(struct file *file, struct dir_context *ctx) ++{ ++ int err; ++ struct dentry *dentry; ++ struct inode *inode, *h_inode; ++ struct super_block *sb; ++ ++ AuDbg("%pD, ctx{%pf, %llu}\n", file, ctx->actor, ctx->pos); ++ ++ dentry = file->f_dentry; ++ inode = dentry->d_inode; ++ IMustLock(inode); ++ ++ sb = dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ err = au_reval_and_lock_fdi(file, reopen_dir, /*wlock*/1); ++ if (unlikely(err)) ++ goto out; ++ err = au_alive_dir(dentry); ++ if (!err) ++ err = au_vdir_init(file); ++ di_downgrade_lock(dentry, AuLock_IR); ++ if (unlikely(err)) ++ goto out_unlock; ++ ++ h_inode = au_h_iptr(inode, au_ibstart(inode)); ++ if (!au_test_nfsd()) { ++ err = au_vdir_fill_de(file, ctx); ++ fsstack_copy_attr_atime(inode, h_inode); ++ } else { ++ /* ++ * nfsd filldir may call lookup_one_len(), vfs_getattr(), ++ * encode_fh() and others. ++ */ ++ atomic_inc(&h_inode->i_count); ++ di_read_unlock(dentry, AuLock_IR); ++ si_read_unlock(sb); ++ err = au_vdir_fill_de(file, ctx); ++ fsstack_copy_attr_atime(inode, h_inode); ++ fi_write_unlock(file); ++ iput(h_inode); ++ ++ AuTraceErr(err); ++ return err; ++ } ++ ++out_unlock: ++ di_read_unlock(dentry, AuLock_IR); ++ fi_write_unlock(file); ++out: ++ si_read_unlock(sb); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define AuTestEmpty_WHONLY 1 ++#define AuTestEmpty_CALLED (1 << 1) ++#define AuTestEmpty_SHWH (1 << 2) ++#define au_ftest_testempty(flags, name) ((flags) & AuTestEmpty_##name) ++#define au_fset_testempty(flags, name) \ ++ do { (flags) |= AuTestEmpty_##name; } while (0) ++#define au_fclr_testempty(flags, name) \ ++ do { (flags) &= ~AuTestEmpty_##name; } while (0) ++ ++#ifndef CONFIG_AUFS_SHWH ++#undef AuTestEmpty_SHWH ++#define AuTestEmpty_SHWH 0 ++#endif ++ ++struct test_empty_arg { ++ struct dir_context ctx; ++ struct au_nhash *whlist; ++ unsigned int flags; ++ int err; ++ aufs_bindex_t bindex; ++}; ++ ++static int test_empty_cb(struct dir_context *ctx, const char *__name, ++ int namelen, loff_t offset __maybe_unused, u64 ino, ++ unsigned int d_type) ++{ ++ struct test_empty_arg *arg = container_of(ctx, struct test_empty_arg, ++ ctx); ++ char *name = (void *)__name; ++ ++ arg->err = 0; ++ au_fset_testempty(arg->flags, CALLED); ++ /* smp_mb(); */ ++ if (name[0] == '.' ++ && (namelen == 1 || (name[1] == '.' && namelen == 2))) ++ goto out; /* success */ ++ ++ if (namelen <= AUFS_WH_PFX_LEN ++ || memcmp(name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) { ++ if (au_ftest_testempty(arg->flags, WHONLY) ++ && !au_nhash_test_known_wh(arg->whlist, name, namelen)) ++ arg->err = -ENOTEMPTY; ++ goto out; ++ } ++ ++ name += AUFS_WH_PFX_LEN; ++ namelen -= AUFS_WH_PFX_LEN; ++ if (!au_nhash_test_known_wh(arg->whlist, name, namelen)) ++ arg->err = au_nhash_append_wh ++ (arg->whlist, name, namelen, ino, d_type, arg->bindex, ++ au_ftest_testempty(arg->flags, SHWH)); ++ ++out: ++ /* smp_mb(); */ ++ AuTraceErr(arg->err); ++ return arg->err; ++} ++ ++static int do_test_empty(struct dentry *dentry, struct test_empty_arg *arg) ++{ ++ int err; ++ struct file *h_file; ++ ++ h_file = au_h_open(dentry, arg->bindex, ++ O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_LARGEFILE, ++ /*file*/NULL, /*force_wr*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ err = 0; ++ if (!au_opt_test(au_mntflags(dentry->d_sb), UDBA_NONE) ++ && !file_inode(h_file)->i_nlink) ++ goto out_put; ++ ++ do { ++ arg->err = 0; ++ au_fclr_testempty(arg->flags, CALLED); ++ /* smp_mb(); */ ++ err = vfsub_iterate_dir(h_file, &arg->ctx); ++ if (err >= 0) ++ err = arg->err; ++ } while (!err && au_ftest_testempty(arg->flags, CALLED)); ++ ++out_put: ++ fput(h_file); ++ au_sbr_put(dentry->d_sb, arg->bindex); ++out: ++ return err; ++} ++ ++struct do_test_empty_args { ++ int *errp; ++ struct dentry *dentry; ++ struct test_empty_arg *arg; ++}; ++ ++static void call_do_test_empty(void *args) ++{ ++ struct do_test_empty_args *a = args; ++ *a->errp = do_test_empty(a->dentry, a->arg); ++} ++ ++static int sio_test_empty(struct dentry *dentry, struct test_empty_arg *arg) ++{ ++ int err, wkq_err; ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ ++ h_dentry = au_h_dptr(dentry, arg->bindex); ++ h_inode = h_dentry->d_inode; ++ /* todo: i_mode changes anytime? */ ++ mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD); ++ err = au_test_h_perm_sio(h_inode, MAY_EXEC | MAY_READ); ++ mutex_unlock(&h_inode->i_mutex); ++ if (!err) ++ err = do_test_empty(dentry, arg); ++ else { ++ struct do_test_empty_args args = { ++ .errp = &err, ++ .dentry = dentry, ++ .arg = arg ++ }; ++ unsigned int flags = arg->flags; ++ ++ wkq_err = au_wkq_wait(call_do_test_empty, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ arg->flags = flags; ++ } ++ ++ return err; ++} ++ ++int au_test_empty_lower(struct dentry *dentry) ++{ ++ int err; ++ unsigned int rdhash; ++ aufs_bindex_t bindex, bstart, btail; ++ struct au_nhash whlist; ++ struct test_empty_arg arg = { ++ .ctx = { ++ .actor = au_diractor(test_empty_cb) ++ } ++ }; ++ int (*test_empty)(struct dentry *dentry, struct test_empty_arg *arg); ++ ++ SiMustAnyLock(dentry->d_sb); ++ ++ rdhash = au_sbi(dentry->d_sb)->si_rdhash; ++ if (!rdhash) ++ rdhash = au_rdhash_est(au_dir_size(/*file*/NULL, dentry)); ++ err = au_nhash_alloc(&whlist, rdhash, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ ++ arg.flags = 0; ++ arg.whlist = &whlist; ++ bstart = au_dbstart(dentry); ++ if (au_opt_test(au_mntflags(dentry->d_sb), SHWH)) ++ au_fset_testempty(arg.flags, SHWH); ++ test_empty = do_test_empty; ++ if (au_opt_test(au_mntflags(dentry->d_sb), DIRPERM1)) ++ test_empty = sio_test_empty; ++ arg.bindex = bstart; ++ err = test_empty(dentry, &arg); ++ if (unlikely(err)) ++ goto out_whlist; ++ ++ au_fset_testempty(arg.flags, WHONLY); ++ btail = au_dbtaildir(dentry); ++ for (bindex = bstart + 1; !err && bindex <= btail; bindex++) { ++ struct dentry *h_dentry; ++ ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (h_dentry && h_dentry->d_inode) { ++ arg.bindex = bindex; ++ err = test_empty(dentry, &arg); ++ } ++ } ++ ++out_whlist: ++ au_nhash_wh_free(&whlist); ++out: ++ return err; ++} ++ ++int au_test_empty(struct dentry *dentry, struct au_nhash *whlist) ++{ ++ int err; ++ struct test_empty_arg arg = { ++ .ctx = { ++ .actor = au_diractor(test_empty_cb) ++ } ++ }; ++ aufs_bindex_t bindex, btail; ++ ++ err = 0; ++ arg.whlist = whlist; ++ arg.flags = AuTestEmpty_WHONLY; ++ if (au_opt_test(au_mntflags(dentry->d_sb), SHWH)) ++ au_fset_testempty(arg.flags, SHWH); ++ btail = au_dbtaildir(dentry); ++ for (bindex = au_dbstart(dentry); !err && bindex <= btail; bindex++) { ++ struct dentry *h_dentry; ++ ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (h_dentry && h_dentry->d_inode) { ++ arg.bindex = bindex; ++ err = sio_test_empty(dentry, &arg); ++ } ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++const struct file_operations aufs_dir_fop = { ++ .owner = THIS_MODULE, ++ .llseek = default_llseek, ++ .read = generic_read_dir, ++ .iterate = aufs_iterate, ++ .unlocked_ioctl = aufs_ioctl_dir, ++#ifdef CONFIG_COMPAT ++ .compat_ioctl = aufs_compat_ioctl_dir, ++#endif ++ .open = aufs_open_dir, ++ .release = aufs_release_dir, ++ .flush = aufs_flush_dir, ++ .fsync = aufs_fsync_dir ++}; +diff --git a/fs/aufs/dir.h b/fs/aufs/dir.h +new file mode 100644 +index 0000000..16821f9 +--- /dev/null ++++ b/fs/aufs/dir.h +@@ -0,0 +1,131 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * directory operations ++ */ ++ ++#ifndef __AUFS_DIR_H__ ++#define __AUFS_DIR_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* need to be faster and smaller */ ++ ++struct au_nhash { ++ unsigned int nh_num; ++ struct hlist_head *nh_head; ++}; ++ ++struct au_vdir_destr { ++ unsigned char len; ++ unsigned char name[0]; ++} __packed; ++ ++struct au_vdir_dehstr { ++ struct hlist_node hash; ++ struct au_vdir_destr *str; ++} ____cacheline_aligned_in_smp; ++ ++struct au_vdir_de { ++ ino_t de_ino; ++ unsigned char de_type; ++ /* caution: packed */ ++ struct au_vdir_destr de_str; ++} __packed; ++ ++struct au_vdir_wh { ++ struct hlist_node wh_hash; ++#ifdef CONFIG_AUFS_SHWH ++ ino_t wh_ino; ++ aufs_bindex_t wh_bindex; ++ unsigned char wh_type; ++#else ++ aufs_bindex_t wh_bindex; ++#endif ++ /* caution: packed */ ++ struct au_vdir_destr wh_str; ++} __packed; ++ ++union au_vdir_deblk_p { ++ unsigned char *deblk; ++ struct au_vdir_de *de; ++}; ++ ++struct au_vdir { ++ unsigned char **vd_deblk; ++ unsigned long vd_nblk; ++ struct { ++ unsigned long ul; ++ union au_vdir_deblk_p p; ++ } vd_last; ++ ++ unsigned long vd_version; ++ unsigned int vd_deblk_sz; ++ unsigned long vd_jiffy; ++} ____cacheline_aligned_in_smp; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* dir.c */ ++extern const struct file_operations aufs_dir_fop; ++void au_add_nlink(struct inode *dir, struct inode *h_dir); ++void au_sub_nlink(struct inode *dir, struct inode *h_dir); ++loff_t au_dir_size(struct file *file, struct dentry *dentry); ++void au_dir_ts(struct inode *dir, aufs_bindex_t bsrc); ++int au_test_empty_lower(struct dentry *dentry); ++int au_test_empty(struct dentry *dentry, struct au_nhash *whlist); ++ ++/* vdir.c */ ++unsigned int au_rdhash_est(loff_t sz); ++int au_nhash_alloc(struct au_nhash *nhash, unsigned int num_hash, gfp_t gfp); ++void au_nhash_wh_free(struct au_nhash *whlist); ++int au_nhash_test_longer_wh(struct au_nhash *whlist, aufs_bindex_t btgt, ++ int limit); ++int au_nhash_test_known_wh(struct au_nhash *whlist, char *name, int nlen); ++int au_nhash_append_wh(struct au_nhash *whlist, char *name, int nlen, ino_t ino, ++ unsigned int d_type, aufs_bindex_t bindex, ++ unsigned char shwh); ++void au_vdir_free(struct au_vdir *vdir); ++int au_vdir_init(struct file *file); ++int au_vdir_fill_de(struct file *file, struct dir_context *ctx); ++ ++/* ioctl.c */ ++long aufs_ioctl_dir(struct file *file, unsigned int cmd, unsigned long arg); ++ ++#ifdef CONFIG_AUFS_RDU ++/* rdu.c */ ++long au_rdu_ioctl(struct file *file, unsigned int cmd, unsigned long arg); ++#ifdef CONFIG_COMPAT ++long au_rdu_compat_ioctl(struct file *file, unsigned int cmd, ++ unsigned long arg); ++#endif ++#else ++AuStub(long, au_rdu_ioctl, return -EINVAL, struct file *file, ++ unsigned int cmd, unsigned long arg) ++#ifdef CONFIG_COMPAT ++AuStub(long, au_rdu_compat_ioctl, return -EINVAL, struct file *file, ++ unsigned int cmd, unsigned long arg) ++#endif ++#endif ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_DIR_H__ */ +diff --git a/fs/aufs/dynop.c b/fs/aufs/dynop.c +new file mode 100644 +index 0000000..d758805 +--- /dev/null ++++ b/fs/aufs/dynop.c +@@ -0,0 +1,379 @@ ++/* ++ * Copyright (C) 2010-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * dynamically customizable operations for regular files ++ */ ++ ++#include "aufs.h" ++ ++#define DyPrSym(key) AuDbgSym(key->dk_op.dy_hop) ++ ++/* ++ * How large will these lists be? ++ * Usually just a few elements, 20-30 at most for each, I guess. ++ */ ++static struct au_splhead dynop[AuDyLast]; ++ ++static struct au_dykey *dy_gfind_get(struct au_splhead *spl, const void *h_op) ++{ ++ struct au_dykey *key, *tmp; ++ struct list_head *head; ++ ++ key = NULL; ++ head = &spl->head; ++ rcu_read_lock(); ++ list_for_each_entry_rcu(tmp, head, dk_list) ++ if (tmp->dk_op.dy_hop == h_op) { ++ key = tmp; ++ kref_get(&key->dk_kref); ++ break; ++ } ++ rcu_read_unlock(); ++ ++ return key; ++} ++ ++static struct au_dykey *dy_bradd(struct au_branch *br, struct au_dykey *key) ++{ ++ struct au_dykey **k, *found; ++ const void *h_op = key->dk_op.dy_hop; ++ int i; ++ ++ found = NULL; ++ k = br->br_dykey; ++ for (i = 0; i < AuBrDynOp; i++) ++ if (k[i]) { ++ if (k[i]->dk_op.dy_hop == h_op) { ++ found = k[i]; ++ break; ++ } ++ } else ++ break; ++ if (!found) { ++ spin_lock(&br->br_dykey_lock); ++ for (; i < AuBrDynOp; i++) ++ if (k[i]) { ++ if (k[i]->dk_op.dy_hop == h_op) { ++ found = k[i]; ++ break; ++ } ++ } else { ++ k[i] = key; ++ break; ++ } ++ spin_unlock(&br->br_dykey_lock); ++ BUG_ON(i == AuBrDynOp); /* expand the array */ ++ } ++ ++ return found; ++} ++ ++/* kref_get() if @key is already added */ ++static struct au_dykey *dy_gadd(struct au_splhead *spl, struct au_dykey *key) ++{ ++ struct au_dykey *tmp, *found; ++ struct list_head *head; ++ const void *h_op = key->dk_op.dy_hop; ++ ++ found = NULL; ++ head = &spl->head; ++ spin_lock(&spl->spin); ++ list_for_each_entry(tmp, head, dk_list) ++ if (tmp->dk_op.dy_hop == h_op) { ++ kref_get(&tmp->dk_kref); ++ found = tmp; ++ break; ++ } ++ if (!found) ++ list_add_rcu(&key->dk_list, head); ++ spin_unlock(&spl->spin); ++ ++ if (!found) ++ DyPrSym(key); ++ return found; ++} ++ ++static void dy_free_rcu(struct rcu_head *rcu) ++{ ++ struct au_dykey *key; ++ ++ key = container_of(rcu, struct au_dykey, dk_rcu); ++ DyPrSym(key); ++ kfree(key); ++} ++ ++static void dy_free(struct kref *kref) ++{ ++ struct au_dykey *key; ++ struct au_splhead *spl; ++ ++ key = container_of(kref, struct au_dykey, dk_kref); ++ spl = dynop + key->dk_op.dy_type; ++ au_spl_del_rcu(&key->dk_list, spl); ++ call_rcu(&key->dk_rcu, dy_free_rcu); ++} ++ ++void au_dy_put(struct au_dykey *key) ++{ ++ kref_put(&key->dk_kref, dy_free); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define DyDbgSize(cnt, op) AuDebugOn(cnt != sizeof(op)/sizeof(void *)) ++ ++#ifdef CONFIG_AUFS_DEBUG ++#define DyDbgDeclare(cnt) unsigned int cnt = 0 ++#define DyDbgInc(cnt) do { cnt++; } while (0) ++#else ++#define DyDbgDeclare(cnt) do {} while (0) ++#define DyDbgInc(cnt) do {} while (0) ++#endif ++ ++#define DySet(func, dst, src, h_op, h_sb) do { \ ++ DyDbgInc(cnt); \ ++ if (h_op->func) { \ ++ if (src.func) \ ++ dst.func = src.func; \ ++ else \ ++ AuDbg("%s %s\n", au_sbtype(h_sb), #func); \ ++ } \ ++} while (0) ++ ++#define DySetForce(func, dst, src) do { \ ++ AuDebugOn(!src.func); \ ++ DyDbgInc(cnt); \ ++ dst.func = src.func; \ ++} while (0) ++ ++#define DySetAop(func) \ ++ DySet(func, dyaop->da_op, aufs_aop, h_aop, h_sb) ++#define DySetAopForce(func) \ ++ DySetForce(func, dyaop->da_op, aufs_aop) ++ ++static void dy_aop(struct au_dykey *key, const void *h_op, ++ struct super_block *h_sb __maybe_unused) ++{ ++ struct au_dyaop *dyaop = (void *)key; ++ const struct address_space_operations *h_aop = h_op; ++ DyDbgDeclare(cnt); ++ ++ AuDbg("%s\n", au_sbtype(h_sb)); ++ ++ DySetAop(writepage); ++ DySetAopForce(readpage); /* force */ ++ DySetAop(writepages); ++ DySetAop(set_page_dirty); ++ DySetAop(readpages); ++ DySetAop(write_begin); ++ DySetAop(write_end); ++ DySetAop(bmap); ++ DySetAop(invalidatepage); ++ DySetAop(releasepage); ++ DySetAop(freepage); ++ /* these two will be changed according to an aufs mount option */ ++ DySetAop(direct_IO); ++ DySetAop(get_xip_mem); ++ DySetAop(migratepage); ++ DySetAop(launder_page); ++ DySetAop(is_partially_uptodate); ++ DySetAop(is_dirty_writeback); ++ DySetAop(error_remove_page); ++ DySetAop(swap_activate); ++ DySetAop(swap_deactivate); ++ ++ DyDbgSize(cnt, *h_aop); ++ dyaop->da_get_xip_mem = h_aop->get_xip_mem; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void dy_bug(struct kref *kref) ++{ ++ BUG(); ++} ++ ++static struct au_dykey *dy_get(struct au_dynop *op, struct au_branch *br) ++{ ++ struct au_dykey *key, *old; ++ struct au_splhead *spl; ++ struct op { ++ unsigned int sz; ++ void (*set)(struct au_dykey *key, const void *h_op, ++ struct super_block *h_sb __maybe_unused); ++ }; ++ static const struct op a[] = { ++ [AuDy_AOP] = { ++ .sz = sizeof(struct au_dyaop), ++ .set = dy_aop ++ } ++ }; ++ const struct op *p; ++ ++ spl = dynop + op->dy_type; ++ key = dy_gfind_get(spl, op->dy_hop); ++ if (key) ++ goto out_add; /* success */ ++ ++ p = a + op->dy_type; ++ key = kzalloc(p->sz, GFP_NOFS); ++ if (unlikely(!key)) { ++ key = ERR_PTR(-ENOMEM); ++ goto out; ++ } ++ ++ key->dk_op.dy_hop = op->dy_hop; ++ kref_init(&key->dk_kref); ++ p->set(key, op->dy_hop, au_br_sb(br)); ++ old = dy_gadd(spl, key); ++ if (old) { ++ kfree(key); ++ key = old; ++ } ++ ++out_add: ++ old = dy_bradd(br, key); ++ if (old) ++ /* its ref-count should never be zero here */ ++ kref_put(&key->dk_kref, dy_bug); ++out: ++ return key; ++} ++ ++/* ---------------------------------------------------------------------- */ ++/* ++ * Aufs prohibits O_DIRECT by defaut even if the branch supports it. ++ * This behaviour is necessary to return an error from open(O_DIRECT) instead ++ * of the succeeding I/O. The dio mount option enables O_DIRECT and makes ++ * open(O_DIRECT) always succeed, but the succeeding I/O may return an error. ++ * See the aufs manual in detail. ++ * ++ * To keep this behaviour, aufs has to set NULL to ->get_xip_mem too, and the ++ * performance of fadvise() and madvise() may be affected. ++ */ ++static void dy_adx(struct au_dyaop *dyaop, int do_dx) ++{ ++ if (!do_dx) { ++ dyaop->da_op.direct_IO = NULL; ++ dyaop->da_op.get_xip_mem = NULL; ++ } else { ++ dyaop->da_op.direct_IO = aufs_aop.direct_IO; ++ dyaop->da_op.get_xip_mem = aufs_aop.get_xip_mem; ++ if (!dyaop->da_get_xip_mem) ++ dyaop->da_op.get_xip_mem = NULL; ++ } ++} ++ ++static struct au_dyaop *dy_aget(struct au_branch *br, ++ const struct address_space_operations *h_aop, ++ int do_dx) ++{ ++ struct au_dyaop *dyaop; ++ struct au_dynop op; ++ ++ op.dy_type = AuDy_AOP; ++ op.dy_haop = h_aop; ++ dyaop = (void *)dy_get(&op, br); ++ if (IS_ERR(dyaop)) ++ goto out; ++ dy_adx(dyaop, do_dx); ++ ++out: ++ return dyaop; ++} ++ ++int au_dy_iaop(struct inode *inode, aufs_bindex_t bindex, ++ struct inode *h_inode) ++{ ++ int err, do_dx; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct au_dyaop *dyaop; ++ ++ AuDebugOn(!S_ISREG(h_inode->i_mode)); ++ IiMustWriteLock(inode); ++ ++ sb = inode->i_sb; ++ br = au_sbr(sb, bindex); ++ do_dx = !!au_opt_test(au_mntflags(sb), DIO); ++ dyaop = dy_aget(br, h_inode->i_mapping->a_ops, do_dx); ++ err = PTR_ERR(dyaop); ++ if (IS_ERR(dyaop)) ++ /* unnecessary to call dy_fput() */ ++ goto out; ++ ++ err = 0; ++ inode->i_mapping->a_ops = &dyaop->da_op; ++ ++out: ++ return err; ++} ++ ++/* ++ * Is it safe to replace a_ops during the inode/file is in operation? ++ * Yes, I hope so. ++ */ ++int au_dy_irefresh(struct inode *inode) ++{ ++ int err; ++ aufs_bindex_t bstart; ++ struct inode *h_inode; ++ ++ err = 0; ++ if (S_ISREG(inode->i_mode)) { ++ bstart = au_ibstart(inode); ++ h_inode = au_h_iptr(inode, bstart); ++ err = au_dy_iaop(inode, bstart, h_inode); ++ } ++ return err; ++} ++ ++void au_dy_arefresh(int do_dx) ++{ ++ struct au_splhead *spl; ++ struct list_head *head; ++ struct au_dykey *key; ++ ++ spl = dynop + AuDy_AOP; ++ head = &spl->head; ++ spin_lock(&spl->spin); ++ list_for_each_entry(key, head, dk_list) ++ dy_adx((void *)key, do_dx); ++ spin_unlock(&spl->spin); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void __init au_dy_init(void) ++{ ++ int i; ++ ++ /* make sure that 'struct au_dykey *' can be any type */ ++ BUILD_BUG_ON(offsetof(struct au_dyaop, da_key)); ++ ++ for (i = 0; i < AuDyLast; i++) ++ au_spl_init(dynop + i); ++} ++ ++void au_dy_fin(void) ++{ ++ int i; ++ ++ for (i = 0; i < AuDyLast; i++) ++ WARN_ON(!list_empty(&dynop[i].head)); ++} +diff --git a/fs/aufs/dynop.h b/fs/aufs/dynop.h +new file mode 100644 +index 0000000..cdf1499 +--- /dev/null ++++ b/fs/aufs/dynop.h +@@ -0,0 +1,76 @@ ++/* ++ * Copyright (C) 2010-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * dynamically customizable operations (for regular files only) ++ */ ++ ++#ifndef __AUFS_DYNOP_H__ ++#define __AUFS_DYNOP_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++ ++enum {AuDy_AOP, AuDyLast}; ++ ++struct au_dynop { ++ int dy_type; ++ union { ++ const void *dy_hop; ++ const struct address_space_operations *dy_haop; ++ }; ++}; ++ ++struct au_dykey { ++ union { ++ struct list_head dk_list; ++ struct rcu_head dk_rcu; ++ }; ++ struct au_dynop dk_op; ++ ++ /* ++ * during I am in the branch local array, kref is gotten. when the ++ * branch is removed, kref is put. ++ */ ++ struct kref dk_kref; ++}; ++ ++/* stop unioning since their sizes are very different from each other */ ++struct au_dyaop { ++ struct au_dykey da_key; ++ struct address_space_operations da_op; /* not const */ ++ int (*da_get_xip_mem)(struct address_space *, pgoff_t, int, ++ void **, unsigned long *); ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* dynop.c */ ++struct au_branch; ++void au_dy_put(struct au_dykey *key); ++int au_dy_iaop(struct inode *inode, aufs_bindex_t bindex, ++ struct inode *h_inode); ++int au_dy_irefresh(struct inode *inode); ++void au_dy_arefresh(int do_dio); ++ ++void __init au_dy_init(void); ++void au_dy_fin(void); ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_DYNOP_H__ */ +diff --git a/fs/aufs/export.c b/fs/aufs/export.c +new file mode 100644 +index 0000000..c5bfa76 +--- /dev/null ++++ b/fs/aufs/export.c +@@ -0,0 +1,831 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * export via nfs ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "../fs/mount.h" ++#include "aufs.h" ++ ++union conv { ++#ifdef CONFIG_AUFS_INO_T_64 ++ __u32 a[2]; ++#else ++ __u32 a[1]; ++#endif ++ ino_t ino; ++}; ++ ++static ino_t decode_ino(__u32 *a) ++{ ++ union conv u; ++ ++ BUILD_BUG_ON(sizeof(u.ino) != sizeof(u.a)); ++ u.a[0] = a[0]; ++#ifdef CONFIG_AUFS_INO_T_64 ++ u.a[1] = a[1]; ++#endif ++ return u.ino; ++} ++ ++static void encode_ino(__u32 *a, ino_t ino) ++{ ++ union conv u; ++ ++ u.ino = ino; ++ a[0] = u.a[0]; ++#ifdef CONFIG_AUFS_INO_T_64 ++ a[1] = u.a[1]; ++#endif ++} ++ ++/* NFS file handle */ ++enum { ++ Fh_br_id, ++ Fh_sigen, ++#ifdef CONFIG_AUFS_INO_T_64 ++ /* support 64bit inode number */ ++ Fh_ino1, ++ Fh_ino2, ++ Fh_dir_ino1, ++ Fh_dir_ino2, ++#else ++ Fh_ino1, ++ Fh_dir_ino1, ++#endif ++ Fh_igen, ++ Fh_h_type, ++ Fh_tail, ++ ++ Fh_ino = Fh_ino1, ++ Fh_dir_ino = Fh_dir_ino1 ++}; ++ ++static int au_test_anon(struct dentry *dentry) ++{ ++ /* note: read d_flags without d_lock */ ++ return !!(dentry->d_flags & DCACHE_DISCONNECTED); ++} ++ ++int au_test_nfsd(void) ++{ ++ int ret; ++ struct task_struct *tsk = current; ++ char comm[sizeof(tsk->comm)]; ++ ++ ret = 0; ++ if (tsk->flags & PF_KTHREAD) { ++ get_task_comm(comm, tsk); ++ ret = !strcmp(comm, "nfsd"); ++ } ++ ++ return ret; ++} ++ ++/* ---------------------------------------------------------------------- */ ++/* inode generation external table */ ++ ++void au_xigen_inc(struct inode *inode) ++{ ++ loff_t pos; ++ ssize_t sz; ++ __u32 igen; ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ ++ sb = inode->i_sb; ++ AuDebugOn(!au_opt_test(au_mntflags(sb), XINO)); ++ ++ sbinfo = au_sbi(sb); ++ pos = inode->i_ino; ++ pos *= sizeof(igen); ++ igen = inode->i_generation + 1; ++ sz = xino_fwrite(sbinfo->si_xwrite, sbinfo->si_xigen, &igen, ++ sizeof(igen), &pos); ++ if (sz == sizeof(igen)) ++ return; /* success */ ++ ++ if (unlikely(sz >= 0)) ++ AuIOErr("xigen error (%zd)\n", sz); ++} ++ ++int au_xigen_new(struct inode *inode) ++{ ++ int err; ++ loff_t pos; ++ ssize_t sz; ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ struct file *file; ++ ++ err = 0; ++ /* todo: dirty, at mount time */ ++ if (inode->i_ino == AUFS_ROOT_INO) ++ goto out; ++ sb = inode->i_sb; ++ SiMustAnyLock(sb); ++ if (unlikely(!au_opt_test(au_mntflags(sb), XINO))) ++ goto out; ++ ++ err = -EFBIG; ++ pos = inode->i_ino; ++ if (unlikely(au_loff_max / sizeof(inode->i_generation) - 1 < pos)) { ++ AuIOErr1("too large i%lld\n", pos); ++ goto out; ++ } ++ pos *= sizeof(inode->i_generation); ++ ++ err = 0; ++ sbinfo = au_sbi(sb); ++ file = sbinfo->si_xigen; ++ BUG_ON(!file); ++ ++ if (vfsub_f_size_read(file) ++ < pos + sizeof(inode->i_generation)) { ++ inode->i_generation = atomic_inc_return(&sbinfo->si_xigen_next); ++ sz = xino_fwrite(sbinfo->si_xwrite, file, &inode->i_generation, ++ sizeof(inode->i_generation), &pos); ++ } else ++ sz = xino_fread(sbinfo->si_xread, file, &inode->i_generation, ++ sizeof(inode->i_generation), &pos); ++ if (sz == sizeof(inode->i_generation)) ++ goto out; /* success */ ++ ++ err = sz; ++ if (unlikely(sz >= 0)) { ++ err = -EIO; ++ AuIOErr("xigen error (%zd)\n", sz); ++ } ++ ++out: ++ return err; ++} ++ ++int au_xigen_set(struct super_block *sb, struct file *base) ++{ ++ int err; ++ struct au_sbinfo *sbinfo; ++ struct file *file; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ file = au_xino_create2(base, sbinfo->si_xigen); ++ err = PTR_ERR(file); ++ if (IS_ERR(file)) ++ goto out; ++ err = 0; ++ if (sbinfo->si_xigen) ++ fput(sbinfo->si_xigen); ++ sbinfo->si_xigen = file; ++ ++out: ++ return err; ++} ++ ++void au_xigen_clr(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ if (sbinfo->si_xigen) { ++ fput(sbinfo->si_xigen); ++ sbinfo->si_xigen = NULL; ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct dentry *decode_by_ino(struct super_block *sb, ino_t ino, ++ ino_t dir_ino) ++{ ++ struct dentry *dentry, *d; ++ struct inode *inode; ++ unsigned int sigen; ++ ++ dentry = NULL; ++ inode = ilookup(sb, ino); ++ if (!inode) ++ goto out; ++ ++ dentry = ERR_PTR(-ESTALE); ++ sigen = au_sigen(sb); ++ if (unlikely(is_bad_inode(inode) ++ || IS_DEADDIR(inode) ++ || sigen != au_iigen(inode, NULL))) ++ goto out_iput; ++ ++ dentry = NULL; ++ if (!dir_ino || S_ISDIR(inode->i_mode)) ++ dentry = d_find_alias(inode); ++ else { ++ spin_lock(&inode->i_lock); ++ hlist_for_each_entry(d, &inode->i_dentry, d_u.d_alias) { ++ spin_lock(&d->d_lock); ++ if (!au_test_anon(d) ++ && d->d_parent->d_inode->i_ino == dir_ino) { ++ dentry = dget_dlock(d); ++ spin_unlock(&d->d_lock); ++ break; ++ } ++ spin_unlock(&d->d_lock); ++ } ++ spin_unlock(&inode->i_lock); ++ } ++ if (unlikely(dentry && au_digen_test(dentry, sigen))) { ++ /* need to refresh */ ++ dput(dentry); ++ dentry = NULL; ++ } ++ ++out_iput: ++ iput(inode); ++out: ++ AuTraceErrPtr(dentry); ++ return dentry; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* todo: dirty? */ ++/* if exportfs_decode_fh() passed vfsmount*, we could be happy */ ++ ++struct au_compare_mnt_args { ++ /* input */ ++ struct super_block *sb; ++ ++ /* output */ ++ struct vfsmount *mnt; ++}; ++ ++static int au_compare_mnt(struct vfsmount *mnt, void *arg) ++{ ++ struct au_compare_mnt_args *a = arg; ++ ++ if (mnt->mnt_sb != a->sb) ++ return 0; ++ a->mnt = mntget(mnt); ++ return 1; ++} ++ ++static struct vfsmount *au_mnt_get(struct super_block *sb) ++{ ++ int err; ++ struct path root; ++ struct au_compare_mnt_args args = { ++ .sb = sb ++ }; ++ ++ get_fs_root(current->fs, &root); ++ rcu_read_lock(); ++ err = iterate_mounts(au_compare_mnt, &args, root.mnt); ++ rcu_read_unlock(); ++ path_put(&root); ++ AuDebugOn(!err); ++ AuDebugOn(!args.mnt); ++ return args.mnt; ++} ++ ++struct au_nfsd_si_lock { ++ unsigned int sigen; ++ aufs_bindex_t bindex, br_id; ++ unsigned char force_lock; ++}; ++ ++static int si_nfsd_read_lock(struct super_block *sb, ++ struct au_nfsd_si_lock *nsi_lock) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ ++ si_read_lock(sb, AuLock_FLUSH); ++ ++ /* branch id may be wrapped around */ ++ err = 0; ++ bindex = au_br_index(sb, nsi_lock->br_id); ++ if (bindex >= 0 && nsi_lock->sigen + AUFS_BRANCH_MAX > au_sigen(sb)) ++ goto out; /* success */ ++ ++ err = -ESTALE; ++ bindex = -1; ++ if (!nsi_lock->force_lock) ++ si_read_unlock(sb); ++ ++out: ++ nsi_lock->bindex = bindex; ++ return err; ++} ++ ++struct find_name_by_ino { ++ struct dir_context ctx; ++ int called, found; ++ ino_t ino; ++ char *name; ++ int namelen; ++}; ++ ++static int ++find_name_by_ino(struct dir_context *ctx, const char *name, int namelen, ++ loff_t offset, u64 ino, unsigned int d_type) ++{ ++ struct find_name_by_ino *a = container_of(ctx, struct find_name_by_ino, ++ ctx); ++ ++ a->called++; ++ if (a->ino != ino) ++ return 0; ++ ++ memcpy(a->name, name, namelen); ++ a->namelen = namelen; ++ a->found = 1; ++ return 1; ++} ++ ++static struct dentry *au_lkup_by_ino(struct path *path, ino_t ino, ++ struct au_nfsd_si_lock *nsi_lock) ++{ ++ struct dentry *dentry, *parent; ++ struct file *file; ++ struct inode *dir; ++ struct find_name_by_ino arg = { ++ .ctx = { ++ .actor = au_diractor(find_name_by_ino) ++ } ++ }; ++ int err; ++ ++ parent = path->dentry; ++ if (nsi_lock) ++ si_read_unlock(parent->d_sb); ++ file = vfsub_dentry_open(path, au_dir_roflags); ++ dentry = (void *)file; ++ if (IS_ERR(file)) ++ goto out; ++ ++ dentry = ERR_PTR(-ENOMEM); ++ arg.name = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!arg.name)) ++ goto out_file; ++ arg.ino = ino; ++ arg.found = 0; ++ do { ++ arg.called = 0; ++ /* smp_mb(); */ ++ err = vfsub_iterate_dir(file, &arg.ctx); ++ } while (!err && !arg.found && arg.called); ++ dentry = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out_name; ++ /* instead of ENOENT */ ++ dentry = ERR_PTR(-ESTALE); ++ if (!arg.found) ++ goto out_name; ++ ++ /* do not call vfsub_lkup_one() */ ++ dir = parent->d_inode; ++ mutex_lock(&dir->i_mutex); ++ dentry = vfsub_lookup_one_len(arg.name, parent, arg.namelen); ++ mutex_unlock(&dir->i_mutex); ++ AuTraceErrPtr(dentry); ++ if (IS_ERR(dentry)) ++ goto out_name; ++ AuDebugOn(au_test_anon(dentry)); ++ if (unlikely(!dentry->d_inode)) { ++ dput(dentry); ++ dentry = ERR_PTR(-ENOENT); ++ } ++ ++out_name: ++ free_page((unsigned long)arg.name); ++out_file: ++ fput(file); ++out: ++ if (unlikely(nsi_lock ++ && si_nfsd_read_lock(parent->d_sb, nsi_lock) < 0)) ++ if (!IS_ERR(dentry)) { ++ dput(dentry); ++ dentry = ERR_PTR(-ESTALE); ++ } ++ AuTraceErrPtr(dentry); ++ return dentry; ++} ++ ++static struct dentry *decode_by_dir_ino(struct super_block *sb, ino_t ino, ++ ino_t dir_ino, ++ struct au_nfsd_si_lock *nsi_lock) ++{ ++ struct dentry *dentry; ++ struct path path; ++ ++ if (dir_ino != AUFS_ROOT_INO) { ++ path.dentry = decode_by_ino(sb, dir_ino, 0); ++ dentry = path.dentry; ++ if (!path.dentry || IS_ERR(path.dentry)) ++ goto out; ++ AuDebugOn(au_test_anon(path.dentry)); ++ } else ++ path.dentry = dget(sb->s_root); ++ ++ path.mnt = au_mnt_get(sb); ++ dentry = au_lkup_by_ino(&path, ino, nsi_lock); ++ path_put(&path); ++ ++out: ++ AuTraceErrPtr(dentry); ++ return dentry; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int h_acceptable(void *expv, struct dentry *dentry) ++{ ++ return 1; ++} ++ ++static char *au_build_path(struct dentry *h_parent, struct path *h_rootpath, ++ char *buf, int len, struct super_block *sb) ++{ ++ char *p; ++ int n; ++ struct path path; ++ ++ p = d_path(h_rootpath, buf, len); ++ if (IS_ERR(p)) ++ goto out; ++ n = strlen(p); ++ ++ path.mnt = h_rootpath->mnt; ++ path.dentry = h_parent; ++ p = d_path(&path, buf, len); ++ if (IS_ERR(p)) ++ goto out; ++ if (n != 1) ++ p += n; ++ ++ path.mnt = au_mnt_get(sb); ++ path.dentry = sb->s_root; ++ p = d_path(&path, buf, len - strlen(p)); ++ mntput(path.mnt); ++ if (IS_ERR(p)) ++ goto out; ++ if (n != 1) ++ p[strlen(p)] = '/'; ++ ++out: ++ AuTraceErrPtr(p); ++ return p; ++} ++ ++static ++struct dentry *decode_by_path(struct super_block *sb, ino_t ino, __u32 *fh, ++ int fh_len, struct au_nfsd_si_lock *nsi_lock) ++{ ++ struct dentry *dentry, *h_parent, *root; ++ struct super_block *h_sb; ++ char *pathname, *p; ++ struct vfsmount *h_mnt; ++ struct au_branch *br; ++ int err; ++ struct path path; ++ ++ br = au_sbr(sb, nsi_lock->bindex); ++ h_mnt = au_br_mnt(br); ++ h_sb = h_mnt->mnt_sb; ++ /* todo: call lower fh_to_dentry()? fh_to_parent()? */ ++ h_parent = exportfs_decode_fh(h_mnt, (void *)(fh + Fh_tail), ++ fh_len - Fh_tail, fh[Fh_h_type], ++ h_acceptable, /*context*/NULL); ++ dentry = h_parent; ++ if (unlikely(!h_parent || IS_ERR(h_parent))) { ++ AuWarn1("%s decode_fh failed, %ld\n", ++ au_sbtype(h_sb), PTR_ERR(h_parent)); ++ goto out; ++ } ++ dentry = NULL; ++ if (unlikely(au_test_anon(h_parent))) { ++ AuWarn1("%s decode_fh returned a disconnected dentry\n", ++ au_sbtype(h_sb)); ++ goto out_h_parent; ++ } ++ ++ dentry = ERR_PTR(-ENOMEM); ++ pathname = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!pathname)) ++ goto out_h_parent; ++ ++ root = sb->s_root; ++ path.mnt = h_mnt; ++ di_read_lock_parent(root, !AuLock_IR); ++ path.dentry = au_h_dptr(root, nsi_lock->bindex); ++ di_read_unlock(root, !AuLock_IR); ++ p = au_build_path(h_parent, &path, pathname, PAGE_SIZE, sb); ++ dentry = (void *)p; ++ if (IS_ERR(p)) ++ goto out_pathname; ++ ++ si_read_unlock(sb); ++ err = vfsub_kern_path(p, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path); ++ dentry = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out_relock; ++ ++ dentry = ERR_PTR(-ENOENT); ++ AuDebugOn(au_test_anon(path.dentry)); ++ if (unlikely(!path.dentry->d_inode)) ++ goto out_path; ++ ++ if (ino != path.dentry->d_inode->i_ino) ++ dentry = au_lkup_by_ino(&path, ino, /*nsi_lock*/NULL); ++ else ++ dentry = dget(path.dentry); ++ ++out_path: ++ path_put(&path); ++out_relock: ++ if (unlikely(si_nfsd_read_lock(sb, nsi_lock) < 0)) ++ if (!IS_ERR(dentry)) { ++ dput(dentry); ++ dentry = ERR_PTR(-ESTALE); ++ } ++out_pathname: ++ free_page((unsigned long)pathname); ++out_h_parent: ++ dput(h_parent); ++out: ++ AuTraceErrPtr(dentry); ++ return dentry; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct dentry * ++aufs_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len, ++ int fh_type) ++{ ++ struct dentry *dentry; ++ __u32 *fh = fid->raw; ++ struct au_branch *br; ++ ino_t ino, dir_ino; ++ struct au_nfsd_si_lock nsi_lock = { ++ .force_lock = 0 ++ }; ++ ++ dentry = ERR_PTR(-ESTALE); ++ /* it should never happen, but the file handle is unreliable */ ++ if (unlikely(fh_len < Fh_tail)) ++ goto out; ++ nsi_lock.sigen = fh[Fh_sigen]; ++ nsi_lock.br_id = fh[Fh_br_id]; ++ ++ /* branch id may be wrapped around */ ++ br = NULL; ++ if (unlikely(si_nfsd_read_lock(sb, &nsi_lock))) ++ goto out; ++ nsi_lock.force_lock = 1; ++ ++ /* is this inode still cached? */ ++ ino = decode_ino(fh + Fh_ino); ++ /* it should never happen */ ++ if (unlikely(ino == AUFS_ROOT_INO)) ++ goto out_unlock; ++ ++ dir_ino = decode_ino(fh + Fh_dir_ino); ++ dentry = decode_by_ino(sb, ino, dir_ino); ++ if (IS_ERR(dentry)) ++ goto out_unlock; ++ if (dentry) ++ goto accept; ++ ++ /* is the parent dir cached? */ ++ br = au_sbr(sb, nsi_lock.bindex); ++ atomic_inc(&br->br_count); ++ dentry = decode_by_dir_ino(sb, ino, dir_ino, &nsi_lock); ++ if (IS_ERR(dentry)) ++ goto out_unlock; ++ if (dentry) ++ goto accept; ++ ++ /* lookup path */ ++ dentry = decode_by_path(sb, ino, fh, fh_len, &nsi_lock); ++ if (IS_ERR(dentry)) ++ goto out_unlock; ++ if (unlikely(!dentry)) ++ /* todo?: make it ESTALE */ ++ goto out_unlock; ++ ++accept: ++ if (!au_digen_test(dentry, au_sigen(sb)) ++ && dentry->d_inode->i_generation == fh[Fh_igen]) ++ goto out_unlock; /* success */ ++ ++ dput(dentry); ++ dentry = ERR_PTR(-ESTALE); ++out_unlock: ++ if (br) ++ atomic_dec(&br->br_count); ++ si_read_unlock(sb); ++out: ++ AuTraceErrPtr(dentry); ++ return dentry; ++} ++ ++#if 0 /* reserved for future use */ ++/* support subtreecheck option */ ++static struct dentry *aufs_fh_to_parent(struct super_block *sb, struct fid *fid, ++ int fh_len, int fh_type) ++{ ++ struct dentry *parent; ++ __u32 *fh = fid->raw; ++ ino_t dir_ino; ++ ++ dir_ino = decode_ino(fh + Fh_dir_ino); ++ parent = decode_by_ino(sb, dir_ino, 0); ++ if (IS_ERR(parent)) ++ goto out; ++ if (!parent) ++ parent = decode_by_path(sb, au_br_index(sb, fh[Fh_br_id]), ++ dir_ino, fh, fh_len); ++ ++out: ++ AuTraceErrPtr(parent); ++ return parent; ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int aufs_encode_fh(struct inode *inode, __u32 *fh, int *max_len, ++ struct inode *dir) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ struct super_block *sb, *h_sb; ++ struct dentry *dentry, *parent, *h_parent; ++ struct inode *h_dir; ++ struct au_branch *br; ++ ++ err = -ENOSPC; ++ if (unlikely(*max_len <= Fh_tail)) { ++ AuWarn1("NFSv2 client (max_len %d)?\n", *max_len); ++ goto out; ++ } ++ ++ err = FILEID_ROOT; ++ if (inode->i_ino == AUFS_ROOT_INO) { ++ AuDebugOn(inode->i_ino != AUFS_ROOT_INO); ++ goto out; ++ } ++ ++ h_parent = NULL; ++ sb = inode->i_sb; ++ err = si_read_lock(sb, AuLock_FLUSH); ++ if (unlikely(err)) ++ goto out; ++ ++#ifdef CONFIG_AUFS_DEBUG ++ if (unlikely(!au_opt_test(au_mntflags(sb), XINO))) ++ AuWarn1("NFS-exporting requires xino\n"); ++#endif ++ err = -EIO; ++ parent = NULL; ++ ii_read_lock_child(inode); ++ bindex = au_ibstart(inode); ++ if (!dir) { ++ dentry = d_find_any_alias(inode); ++ if (unlikely(!dentry)) ++ goto out_unlock; ++ AuDebugOn(au_test_anon(dentry)); ++ parent = dget_parent(dentry); ++ dput(dentry); ++ if (unlikely(!parent)) ++ goto out_unlock; ++ dir = parent->d_inode; ++ } ++ ++ ii_read_lock_parent(dir); ++ h_dir = au_h_iptr(dir, bindex); ++ ii_read_unlock(dir); ++ if (unlikely(!h_dir)) ++ goto out_parent; ++ h_parent = d_find_any_alias(h_dir); ++ if (unlikely(!h_parent)) ++ goto out_hparent; ++ ++ err = -EPERM; ++ br = au_sbr(sb, bindex); ++ h_sb = au_br_sb(br); ++ if (unlikely(!h_sb->s_export_op)) { ++ AuErr1("%s branch is not exportable\n", au_sbtype(h_sb)); ++ goto out_hparent; ++ } ++ ++ fh[Fh_br_id] = br->br_id; ++ fh[Fh_sigen] = au_sigen(sb); ++ encode_ino(fh + Fh_ino, inode->i_ino); ++ encode_ino(fh + Fh_dir_ino, dir->i_ino); ++ fh[Fh_igen] = inode->i_generation; ++ ++ *max_len -= Fh_tail; ++ fh[Fh_h_type] = exportfs_encode_fh(h_parent, (void *)(fh + Fh_tail), ++ max_len, ++ /*connectable or subtreecheck*/0); ++ err = fh[Fh_h_type]; ++ *max_len += Fh_tail; ++ /* todo: macros? */ ++ if (err != FILEID_INVALID) ++ err = 99; ++ else ++ AuWarn1("%s encode_fh failed\n", au_sbtype(h_sb)); ++ ++out_hparent: ++ dput(h_parent); ++out_parent: ++ dput(parent); ++out_unlock: ++ ii_read_unlock(inode); ++ si_read_unlock(sb); ++out: ++ if (unlikely(err < 0)) ++ err = FILEID_INVALID; ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int aufs_commit_metadata(struct inode *inode) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ struct super_block *sb; ++ struct inode *h_inode; ++ int (*f)(struct inode *inode); ++ ++ sb = inode->i_sb; ++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); ++ ii_write_lock_child(inode); ++ bindex = au_ibstart(inode); ++ AuDebugOn(bindex < 0); ++ h_inode = au_h_iptr(inode, bindex); ++ ++ f = h_inode->i_sb->s_export_op->commit_metadata; ++ if (f) ++ err = f(h_inode); ++ else { ++ struct writeback_control wbc = { ++ .sync_mode = WB_SYNC_ALL, ++ .nr_to_write = 0 /* metadata only */ ++ }; ++ ++ err = sync_inode(h_inode, &wbc); ++ } ++ ++ au_cpup_attr_timesizes(inode); ++ ii_write_unlock(inode); ++ si_read_unlock(sb); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct export_operations aufs_export_op = { ++ .fh_to_dentry = aufs_fh_to_dentry, ++ /* .fh_to_parent = aufs_fh_to_parent, */ ++ .encode_fh = aufs_encode_fh, ++ .commit_metadata = aufs_commit_metadata ++}; ++ ++void au_export_init(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ __u32 u; ++ ++ sb->s_export_op = &aufs_export_op; ++ sbinfo = au_sbi(sb); ++ sbinfo->si_xigen = NULL; ++ get_random_bytes(&u, sizeof(u)); ++ BUILD_BUG_ON(sizeof(u) != sizeof(int)); ++ atomic_set(&sbinfo->si_xigen_next, u); ++} +diff --git a/fs/aufs/f_op.c b/fs/aufs/f_op.c +new file mode 100644 +index 0000000..b08981a +--- /dev/null ++++ b/fs/aufs/f_op.c +@@ -0,0 +1,781 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * file and vm operations ++ */ ++ ++#include ++#include ++#include ++#include ++#include "aufs.h" ++ ++int au_do_open_nondir(struct file *file, int flags, struct file *h_file) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ struct dentry *dentry, *h_dentry; ++ struct au_finfo *finfo; ++ struct inode *h_inode; ++ ++ FiMustWriteLock(file); ++ ++ err = 0; ++ dentry = file->f_dentry; ++ AuDebugOn(IS_ERR_OR_NULL(dentry)); ++ finfo = au_fi(file); ++ memset(&finfo->fi_htop, 0, sizeof(finfo->fi_htop)); ++ atomic_set(&finfo->fi_mmapped, 0); ++ bindex = au_dbstart(dentry); ++ if (!h_file) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ err = vfsub_test_mntns(file->f_path.mnt, h_dentry->d_sb); ++ if (unlikely(err)) ++ goto out; ++ h_file = au_h_open(dentry, bindex, flags, file, /*force_wr*/0); ++ } else { ++ h_dentry = h_file->f_dentry; ++ err = vfsub_test_mntns(file->f_path.mnt, h_dentry->d_sb); ++ if (unlikely(err)) ++ goto out; ++ get_file(h_file); ++ } ++ if (IS_ERR(h_file)) ++ err = PTR_ERR(h_file); ++ else { ++ if ((flags & __O_TMPFILE) ++ && !(flags & O_EXCL)) { ++ h_inode = file_inode(h_file); ++ spin_lock(&h_inode->i_lock); ++ h_inode->i_state |= I_LINKABLE; ++ spin_unlock(&h_inode->i_lock); ++ } ++ au_set_fbstart(file, bindex); ++ au_set_h_fptr(file, bindex, h_file); ++ au_update_figen(file); ++ /* todo: necessary? */ ++ /* file->f_ra = h_file->f_ra; */ ++ } ++ ++out: ++ return err; ++} ++ ++static int aufs_open_nondir(struct inode *inode __maybe_unused, ++ struct file *file) ++{ ++ int err; ++ struct super_block *sb; ++ struct au_do_open_args args = { ++ .open = au_do_open_nondir ++ }; ++ ++ AuDbg("%pD, f_flags 0x%x, f_mode 0x%x\n", ++ file, vfsub_file_flags(file), file->f_mode); ++ ++ sb = file->f_dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ err = au_do_open(file, &args); ++ si_read_unlock(sb); ++ return err; ++} ++ ++int aufs_release_nondir(struct inode *inode __maybe_unused, struct file *file) ++{ ++ struct au_finfo *finfo; ++ aufs_bindex_t bindex; ++ ++ finfo = au_fi(file); ++ au_sphl_del(&finfo->fi_hlist, &au_sbi(file->f_dentry->d_sb)->si_files); ++ bindex = finfo->fi_btop; ++ if (bindex >= 0) ++ au_set_h_fptr(file, bindex, NULL); ++ ++ au_finfo_fin(file); ++ return 0; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_do_flush_nondir(struct file *file, fl_owner_t id) ++{ ++ int err; ++ struct file *h_file; ++ ++ err = 0; ++ h_file = au_hf_top(file); ++ if (h_file) ++ err = vfsub_flush(h_file, id); ++ return err; ++} ++ ++static int aufs_flush_nondir(struct file *file, fl_owner_t id) ++{ ++ return au_do_flush(file, id, au_do_flush_nondir); ++} ++ ++/* ---------------------------------------------------------------------- */ ++/* ++ * read and write functions acquire [fdi]_rwsem once, but release before ++ * mmap_sem. This is because to stop a race condition between mmap(2). ++ * Releasing these aufs-rwsem should be safe, no branch-mamagement (by keeping ++ * si_rwsem), no harmful copy-up should happen. Actually copy-up may happen in ++ * read functions after [fdi]_rwsem are released, but it should be harmless. ++ */ ++ ++/* Callers should call au_read_post() or fput() in the end */ ++struct file *au_read_pre(struct file *file, int keep_fi) ++{ ++ struct file *h_file; ++ int err; ++ ++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/0); ++ if (!err) { ++ di_read_unlock(file->f_dentry, AuLock_IR); ++ h_file = au_hf_top(file); ++ get_file(h_file); ++ if (!keep_fi) ++ fi_read_unlock(file); ++ } else ++ h_file = ERR_PTR(err); ++ ++ return h_file; ++} ++ ++static void au_read_post(struct inode *inode, struct file *h_file) ++{ ++ /* update without lock, I don't think it a problem */ ++ fsstack_copy_attr_atime(inode, file_inode(h_file)); ++ fput(h_file); ++} ++ ++struct au_write_pre { ++ blkcnt_t blks; ++ aufs_bindex_t bstart; ++}; ++ ++/* ++ * return with iinfo is write-locked ++ * callers should call au_write_post() or iinfo_write_unlock() + fput() in the ++ * end ++ */ ++static struct file *au_write_pre(struct file *file, int do_ready, ++ struct au_write_pre *wpre) ++{ ++ struct file *h_file; ++ struct dentry *dentry; ++ int err; ++ struct au_pin pin; ++ ++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1); ++ h_file = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out; ++ ++ dentry = file->f_dentry; ++ if (do_ready) { ++ err = au_ready_to_write(file, -1, &pin); ++ if (unlikely(err)) { ++ h_file = ERR_PTR(err); ++ di_write_unlock(dentry); ++ goto out_fi; ++ } ++ } ++ ++ di_downgrade_lock(dentry, /*flags*/0); ++ if (wpre) ++ wpre->bstart = au_fbstart(file); ++ h_file = au_hf_top(file); ++ get_file(h_file); ++ if (wpre) ++ wpre->blks = file_inode(h_file)->i_blocks; ++ if (do_ready) ++ au_unpin(&pin); ++ di_read_unlock(dentry, /*flags*/0); ++ ++out_fi: ++ fi_write_unlock(file); ++out: ++ return h_file; ++} ++ ++static void au_write_post(struct inode *inode, struct file *h_file, ++ struct au_write_pre *wpre, ssize_t written) ++{ ++ struct inode *h_inode; ++ ++ au_cpup_attr_timesizes(inode); ++ AuDebugOn(au_ibstart(inode) != wpre->bstart); ++ h_inode = file_inode(h_file); ++ inode->i_mode = h_inode->i_mode; ++ ii_write_unlock(inode); ++ fput(h_file); ++ ++ /* AuDbg("blks %llu, %llu\n", (u64)blks, (u64)h_inode->i_blocks); */ ++ if (written > 0) ++ au_fhsm_wrote(inode->i_sb, wpre->bstart, ++ /*force*/h_inode->i_blocks > wpre->blks); ++} ++ ++static ssize_t aufs_read(struct file *file, char __user *buf, size_t count, ++ loff_t *ppos) ++{ ++ ssize_t err; ++ struct inode *inode; ++ struct file *h_file; ++ struct super_block *sb; ++ ++ inode = file_inode(file); ++ sb = inode->i_sb; ++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); ++ ++ h_file = au_read_pre(file, /*keep_fi*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ /* filedata may be obsoleted by concurrent copyup, but no problem */ ++ err = vfsub_read_u(h_file, buf, count, ppos); ++ /* todo: necessary? */ ++ /* file->f_ra = h_file->f_ra; */ ++ au_read_post(inode, h_file); ++ ++out: ++ si_read_unlock(sb); ++ return err; ++} ++ ++/* ++ * todo: very ugly ++ * it locks both of i_mutex and si_rwsem for read in safe. ++ * if the plink maintenance mode continues forever (that is the problem), ++ * may loop forever. ++ */ ++static void au_mtx_and_read_lock(struct inode *inode) ++{ ++ int err; ++ struct super_block *sb = inode->i_sb; ++ ++ while (1) { ++ mutex_lock(&inode->i_mutex); ++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (!err) ++ break; ++ mutex_unlock(&inode->i_mutex); ++ si_read_lock(sb, AuLock_NOPLMW); ++ si_read_unlock(sb); ++ } ++} ++ ++static ssize_t aufs_write(struct file *file, const char __user *ubuf, ++ size_t count, loff_t *ppos) ++{ ++ ssize_t err; ++ struct au_write_pre wpre; ++ struct inode *inode; ++ struct file *h_file; ++ char __user *buf = (char __user *)ubuf; ++ ++ inode = file_inode(file); ++ au_mtx_and_read_lock(inode); ++ ++ h_file = au_write_pre(file, /*do_ready*/1, &wpre); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ err = vfsub_write_u(h_file, buf, count, ppos); ++ au_write_post(inode, h_file, &wpre, err); ++ ++out: ++ si_read_unlock(inode->i_sb); ++ mutex_unlock(&inode->i_mutex); ++ return err; ++} ++ ++static ssize_t au_do_iter(struct file *h_file, int rw, struct kiocb *kio, ++ struct iov_iter *iov_iter) ++{ ++ ssize_t err; ++ struct file *file; ++ ssize_t (*iter)(struct kiocb *, struct iov_iter *); ++ ssize_t (*aio)(struct kiocb *, const struct iovec *, unsigned long, ++ loff_t); ++ ++ err = security_file_permission(h_file, rw); ++ if (unlikely(err)) ++ goto out; ++ ++ err = -ENOSYS; ++ iter = NULL; ++ aio = NULL; ++ if (rw == MAY_READ) { ++ iter = h_file->f_op->read_iter; ++ aio = h_file->f_op->aio_read; ++ } else if (rw == MAY_WRITE) { ++ iter = h_file->f_op->write_iter; ++ aio = h_file->f_op->aio_write; ++ } ++ ++ file = kio->ki_filp; ++ kio->ki_filp = h_file; ++ if (iter) { ++ lockdep_off(); ++ err = iter(kio, iov_iter); ++ lockdep_on(); ++ } else if (aio) { ++ lockdep_off(); ++ err = aio(kio, iov_iter->iov, iov_iter->nr_segs, kio->ki_pos); ++ lockdep_on(); ++ } else ++ /* currently there is no such fs */ ++ WARN_ON_ONCE(1); ++ kio->ki_filp = file; ++ ++out: ++ return err; ++} ++ ++static ssize_t aufs_read_iter(struct kiocb *kio, struct iov_iter *iov_iter) ++{ ++ ssize_t err; ++ struct file *file, *h_file; ++ struct inode *inode; ++ struct super_block *sb; ++ ++ file = kio->ki_filp; ++ inode = file_inode(file); ++ sb = inode->i_sb; ++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); ++ ++ h_file = au_read_pre(file, /*keep_fi*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ err = au_do_iter(h_file, MAY_READ, kio, iov_iter); ++ /* todo: necessary? */ ++ /* file->f_ra = h_file->f_ra; */ ++ au_read_post(inode, h_file); ++ ++out: ++ si_read_unlock(sb); ++ return err; ++} ++ ++static ssize_t aufs_write_iter(struct kiocb *kio, struct iov_iter *iov_iter) ++{ ++ ssize_t err; ++ struct au_write_pre wpre; ++ struct inode *inode; ++ struct file *file, *h_file; ++ ++ file = kio->ki_filp; ++ inode = file_inode(file); ++ au_mtx_and_read_lock(inode); ++ ++ h_file = au_write_pre(file, /*do_ready*/1, &wpre); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ err = au_do_iter(h_file, MAY_WRITE, kio, iov_iter); ++ au_write_post(inode, h_file, &wpre, err); ++ ++out: ++ si_read_unlock(inode->i_sb); ++ mutex_unlock(&inode->i_mutex); ++ return err; ++} ++ ++static ssize_t aufs_splice_read(struct file *file, loff_t *ppos, ++ struct pipe_inode_info *pipe, size_t len, ++ unsigned int flags) ++{ ++ ssize_t err; ++ struct file *h_file; ++ struct inode *inode; ++ struct super_block *sb; ++ ++ inode = file_inode(file); ++ sb = inode->i_sb; ++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); ++ ++ h_file = au_read_pre(file, /*keep_fi*/1); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ if (au_test_loopback_kthread()) { ++ au_warn_loopback(h_file->f_dentry->d_sb); ++ if (file->f_mapping != h_file->f_mapping) { ++ file->f_mapping = h_file->f_mapping; ++ smp_mb(); /* unnecessary? */ ++ } ++ } ++ fi_read_unlock(file); ++ ++ err = vfsub_splice_to(h_file, ppos, pipe, len, flags); ++ /* todo: necessasry? */ ++ /* file->f_ra = h_file->f_ra; */ ++ au_read_post(inode, h_file); ++ ++out: ++ si_read_unlock(sb); ++ return err; ++} ++ ++static ssize_t ++aufs_splice_write(struct pipe_inode_info *pipe, struct file *file, loff_t *ppos, ++ size_t len, unsigned int flags) ++{ ++ ssize_t err; ++ struct au_write_pre wpre; ++ struct inode *inode; ++ struct file *h_file; ++ ++ inode = file_inode(file); ++ au_mtx_and_read_lock(inode); ++ ++ h_file = au_write_pre(file, /*do_ready*/1, &wpre); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ err = vfsub_splice_from(pipe, h_file, ppos, len, flags); ++ au_write_post(inode, h_file, &wpre, err); ++ ++out: ++ si_read_unlock(inode->i_sb); ++ mutex_unlock(&inode->i_mutex); ++ return err; ++} ++ ++static long aufs_fallocate(struct file *file, int mode, loff_t offset, ++ loff_t len) ++{ ++ long err; ++ struct au_write_pre wpre; ++ struct inode *inode; ++ struct file *h_file; ++ ++ inode = file_inode(file); ++ au_mtx_and_read_lock(inode); ++ ++ h_file = au_write_pre(file, /*do_ready*/1, &wpre); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ lockdep_off(); ++ err = do_fallocate(h_file, mode, offset, len); ++ lockdep_on(); ++ au_write_post(inode, h_file, &wpre, /*written*/1); ++ ++out: ++ si_read_unlock(inode->i_sb); ++ mutex_unlock(&inode->i_mutex); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * The locking order around current->mmap_sem. ++ * - in most and regular cases ++ * file I/O syscall -- aufs_read() or something ++ * -- si_rwsem for read -- mmap_sem ++ * (Note that [fdi]i_rwsem are released before mmap_sem). ++ * - in mmap case ++ * mmap(2) -- mmap_sem -- aufs_mmap() -- si_rwsem for read -- [fdi]i_rwsem ++ * This AB-BA order is definitly bad, but is not a problem since "si_rwsem for ++ * read" allows muliple processes to acquire it and [fdi]i_rwsem are not held in ++ * file I/O. Aufs needs to stop lockdep in aufs_mmap() though. ++ * It means that when aufs acquires si_rwsem for write, the process should never ++ * acquire mmap_sem. ++ * ++ * Actually aufs_iterate() holds [fdi]i_rwsem before mmap_sem, but this is not a ++ * problem either since any directory is not able to be mmap-ed. ++ * The similar scenario is applied to aufs_readlink() too. ++ */ ++ ++#if 0 /* stop calling security_file_mmap() */ ++/* cf. linux/include/linux/mman.h: calc_vm_prot_bits() */ ++#define AuConv_VM_PROT(f, b) _calc_vm_trans(f, VM_##b, PROT_##b) ++ ++static unsigned long au_arch_prot_conv(unsigned long flags) ++{ ++ /* currently ppc64 only */ ++#ifdef CONFIG_PPC64 ++ /* cf. linux/arch/powerpc/include/asm/mman.h */ ++ AuDebugOn(arch_calc_vm_prot_bits(-1) != VM_SAO); ++ return AuConv_VM_PROT(flags, SAO); ++#else ++ AuDebugOn(arch_calc_vm_prot_bits(-1)); ++ return 0; ++#endif ++} ++ ++static unsigned long au_prot_conv(unsigned long flags) ++{ ++ return AuConv_VM_PROT(flags, READ) ++ | AuConv_VM_PROT(flags, WRITE) ++ | AuConv_VM_PROT(flags, EXEC) ++ | au_arch_prot_conv(flags); ++} ++ ++/* cf. linux/include/linux/mman.h: calc_vm_flag_bits() */ ++#define AuConv_VM_MAP(f, b) _calc_vm_trans(f, VM_##b, MAP_##b) ++ ++static unsigned long au_flag_conv(unsigned long flags) ++{ ++ return AuConv_VM_MAP(flags, GROWSDOWN) ++ | AuConv_VM_MAP(flags, DENYWRITE) ++ | AuConv_VM_MAP(flags, LOCKED); ++} ++#endif ++ ++static int aufs_mmap(struct file *file, struct vm_area_struct *vma) ++{ ++ int err; ++ const unsigned char wlock ++ = (file->f_mode & FMODE_WRITE) && (vma->vm_flags & VM_SHARED); ++ struct super_block *sb; ++ struct file *h_file; ++ struct inode *inode; ++ ++ AuDbgVmRegion(file, vma); ++ ++ inode = file_inode(file); ++ sb = inode->i_sb; ++ lockdep_off(); ++ si_read_lock(sb, AuLock_NOPLMW); ++ ++ h_file = au_write_pre(file, wlock, /*wpre*/NULL); ++ lockdep_on(); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ err = 0; ++ au_set_mmapped(file); ++ au_vm_file_reset(vma, h_file); ++ /* ++ * we cannot call security_mmap_file() here since it may acquire ++ * mmap_sem or i_mutex. ++ * ++ * err = security_mmap_file(h_file, au_prot_conv(vma->vm_flags), ++ * au_flag_conv(vma->vm_flags)); ++ */ ++ if (!err) ++ err = h_file->f_op->mmap(h_file, vma); ++ if (!err) { ++ au_vm_prfile_set(vma, file); ++ fsstack_copy_attr_atime(inode, file_inode(h_file)); ++ goto out_fput; /* success */ ++ } ++ au_unset_mmapped(file); ++ au_vm_file_reset(vma, file); ++ ++out_fput: ++ lockdep_off(); ++ ii_write_unlock(inode); ++ lockdep_on(); ++ fput(h_file); ++out: ++ lockdep_off(); ++ si_read_unlock(sb); ++ lockdep_on(); ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int aufs_fsync_nondir(struct file *file, loff_t start, loff_t end, ++ int datasync) ++{ ++ int err; ++ struct au_write_pre wpre; ++ struct inode *inode; ++ struct file *h_file; ++ ++ err = 0; /* -EBADF; */ /* posix? */ ++ if (unlikely(!(file->f_mode & FMODE_WRITE))) ++ goto out; ++ ++ inode = file_inode(file); ++ au_mtx_and_read_lock(inode); ++ ++ h_file = au_write_pre(file, /*do_ready*/1, &wpre); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out_unlock; ++ ++ err = vfsub_fsync(h_file, &h_file->f_path, datasync); ++ au_write_post(inode, h_file, &wpre, /*written*/0); ++ ++out_unlock: ++ si_read_unlock(inode->i_sb); ++ mutex_unlock(&inode->i_mutex); ++out: ++ return err; ++} ++ ++/* no one supports this operation, currently */ ++#if 0 ++static int aufs_aio_fsync_nondir(struct kiocb *kio, int datasync) ++{ ++ int err; ++ struct au_write_pre wpre; ++ struct inode *inode; ++ struct file *file, *h_file; ++ ++ err = 0; /* -EBADF; */ /* posix? */ ++ if (unlikely(!(file->f_mode & FMODE_WRITE))) ++ goto out; ++ ++ file = kio->ki_filp; ++ inode = file_inode(file); ++ au_mtx_and_read_lock(inode); ++ ++ h_file = au_write_pre(file, /*do_ready*/1, &wpre); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out_unlock; ++ ++ err = -ENOSYS; ++ h_file = au_hf_top(file); ++ if (h_file->f_op->aio_fsync) { ++ struct mutex *h_mtx; ++ ++ h_mtx = &file_inode(h_file)->i_mutex; ++ if (!is_sync_kiocb(kio)) { ++ get_file(h_file); ++ fput(file); ++ } ++ kio->ki_filp = h_file; ++ err = h_file->f_op->aio_fsync(kio, datasync); ++ mutex_lock_nested(h_mtx, AuLsc_I_CHILD); ++ if (!err) ++ vfsub_update_h_iattr(&h_file->f_path, /*did*/NULL); ++ /*ignore*/ ++ mutex_unlock(h_mtx); ++ } ++ au_write_post(inode, h_file, &wpre, /*written*/0); ++ ++out_unlock: ++ si_read_unlock(inode->sb); ++ mutex_unlock(&inode->i_mutex); ++out: ++ return err; ++} ++#endif ++ ++static int aufs_fasync(int fd, struct file *file, int flag) ++{ ++ int err; ++ struct file *h_file; ++ struct super_block *sb; ++ ++ sb = file->f_dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); ++ ++ h_file = au_read_pre(file, /*keep_fi*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ if (h_file->f_op->fasync) ++ err = h_file->f_op->fasync(fd, h_file, flag); ++ fput(h_file); /* instead of au_read_post() */ ++ ++out: ++ si_read_unlock(sb); ++ return err; ++} ++ ++static int aufs_setfl(struct file *file, unsigned long arg) ++{ ++ int err; ++ struct file *h_file; ++ struct super_block *sb; ++ ++ sb = file->f_dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); ++ ++ h_file = au_read_pre(file, /*keep_fi*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ arg |= vfsub_file_flags(file) & FASYNC; /* stop calling h_file->fasync */ ++ err = setfl(/*unused fd*/-1, h_file, arg); ++ fput(h_file); /* instead of au_read_post() */ ++ ++out: ++ si_read_unlock(sb); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* no one supports this operation, currently */ ++#if 0 ++static ssize_t aufs_sendpage(struct file *file, struct page *page, int offset, ++ size_t len, loff_t *pos, int more) ++{ ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++const struct file_operations aufs_file_fop = { ++ .owner = THIS_MODULE, ++ ++ .llseek = default_llseek, ++ ++ .read = aufs_read, ++ .write = aufs_write, ++ .read_iter = aufs_read_iter, ++ .write_iter = aufs_write_iter, ++ ++#ifdef CONFIG_AUFS_POLL ++ .poll = aufs_poll, ++#endif ++ .unlocked_ioctl = aufs_ioctl_nondir, ++#ifdef CONFIG_COMPAT ++ .compat_ioctl = aufs_compat_ioctl_nondir, ++#endif ++ .mmap = aufs_mmap, ++ .open = aufs_open_nondir, ++ .flush = aufs_flush_nondir, ++ .release = aufs_release_nondir, ++ .fsync = aufs_fsync_nondir, ++ /* .aio_fsync = aufs_aio_fsync_nondir, */ ++ .fasync = aufs_fasync, ++ /* .sendpage = aufs_sendpage, */ ++ .setfl = aufs_setfl, ++ .splice_write = aufs_splice_write, ++ .splice_read = aufs_splice_read, ++#if 0 ++ .aio_splice_write = aufs_aio_splice_write, ++ .aio_splice_read = aufs_aio_splice_read, ++#endif ++ .fallocate = aufs_fallocate ++}; +diff --git a/fs/aufs/fhsm.c b/fs/aufs/fhsm.c +new file mode 100644 +index 0000000..5b3ad74 +--- /dev/null ++++ b/fs/aufs/fhsm.c +@@ -0,0 +1,426 @@ ++/* ++ * Copyright (C) 2011-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * File-based Hierarchy Storage Management ++ */ ++ ++#include ++#include ++#include ++#include ++#include "aufs.h" ++ ++static aufs_bindex_t au_fhsm_bottom(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ ++ SiMustAnyLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ fhsm = &sbinfo->si_fhsm; ++ AuDebugOn(!fhsm); ++ return fhsm->fhsm_bottom; ++} ++ ++void au_fhsm_set_bottom(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ fhsm = &sbinfo->si_fhsm; ++ AuDebugOn(!fhsm); ++ fhsm->fhsm_bottom = bindex; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_fhsm_test_jiffy(struct au_sbinfo *sbinfo, struct au_branch *br) ++{ ++ struct au_br_fhsm *bf; ++ ++ bf = br->br_fhsm; ++ MtxMustLock(&bf->bf_lock); ++ ++ return !bf->bf_readable ++ || time_after(jiffies, ++ bf->bf_jiffy + sbinfo->si_fhsm.fhsm_expire); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_fhsm_notify(struct super_block *sb, int val) ++{ ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ ++ SiMustAnyLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ fhsm = &sbinfo->si_fhsm; ++ if (au_fhsm_pid(fhsm) ++ && atomic_read(&fhsm->fhsm_readable) != -1) { ++ atomic_set(&fhsm->fhsm_readable, val); ++ if (val) ++ wake_up(&fhsm->fhsm_wqh); ++ } ++} ++ ++static int au_fhsm_stfs(struct super_block *sb, aufs_bindex_t bindex, ++ struct aufs_stfs *rstfs, int do_lock, int do_notify) ++{ ++ int err; ++ struct au_branch *br; ++ struct au_br_fhsm *bf; ++ ++ br = au_sbr(sb, bindex); ++ AuDebugOn(au_br_rdonly(br)); ++ bf = br->br_fhsm; ++ AuDebugOn(!bf); ++ ++ if (do_lock) ++ mutex_lock(&bf->bf_lock); ++ else ++ MtxMustLock(&bf->bf_lock); ++ ++ /* sb->s_root for NFS is unreliable */ ++ err = au_br_stfs(br, &bf->bf_stfs); ++ if (unlikely(err)) { ++ AuErr1("FHSM failed (%d), b%d, ignored.\n", bindex, err); ++ goto out; ++ } ++ ++ bf->bf_jiffy = jiffies; ++ bf->bf_readable = 1; ++ if (do_notify) ++ au_fhsm_notify(sb, /*val*/1); ++ if (rstfs) ++ *rstfs = bf->bf_stfs; ++ ++out: ++ if (do_lock) ++ mutex_unlock(&bf->bf_lock); ++ au_fhsm_notify(sb, /*val*/1); ++ ++ return err; ++} ++ ++void au_fhsm_wrote(struct super_block *sb, aufs_bindex_t bindex, int force) ++{ ++ int err; ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ struct au_branch *br; ++ struct au_br_fhsm *bf; ++ ++ AuDbg("b%d, force %d\n", bindex, force); ++ SiMustAnyLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ fhsm = &sbinfo->si_fhsm; ++ if (!au_ftest_si(sbinfo, FHSM) ++ || fhsm->fhsm_bottom == bindex) ++ return; ++ ++ br = au_sbr(sb, bindex); ++ bf = br->br_fhsm; ++ AuDebugOn(!bf); ++ mutex_lock(&bf->bf_lock); ++ if (force ++ || au_fhsm_pid(fhsm) ++ || au_fhsm_test_jiffy(sbinfo, br)) ++ err = au_fhsm_stfs(sb, bindex, /*rstfs*/NULL, /*do_lock*/0, ++ /*do_notify*/1); ++ mutex_unlock(&bf->bf_lock); ++} ++ ++void au_fhsm_wrote_all(struct super_block *sb, int force) ++{ ++ aufs_bindex_t bindex, bend; ++ struct au_branch *br; ++ ++ /* exclude the bottom */ ++ bend = au_fhsm_bottom(sb); ++ for (bindex = 0; bindex < bend; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (au_br_fhsm(br->br_perm)) ++ au_fhsm_wrote(sb, bindex, force); ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static unsigned int au_fhsm_poll(struct file *file, ++ struct poll_table_struct *wait) ++{ ++ unsigned int mask; ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ ++ mask = 0; ++ sbinfo = file->private_data; ++ fhsm = &sbinfo->si_fhsm; ++ poll_wait(file, &fhsm->fhsm_wqh, wait); ++ if (atomic_read(&fhsm->fhsm_readable)) ++ mask = POLLIN /* | POLLRDNORM */; ++ ++ AuTraceErr((int)mask); ++ return mask; ++} ++ ++static int au_fhsm_do_read_one(struct aufs_stbr __user *stbr, ++ struct aufs_stfs *stfs, __s16 brid) ++{ ++ int err; ++ ++ err = copy_to_user(&stbr->stfs, stfs, sizeof(*stfs)); ++ if (!err) ++ err = __put_user(brid, &stbr->brid); ++ if (unlikely(err)) ++ err = -EFAULT; ++ ++ return err; ++} ++ ++static ssize_t au_fhsm_do_read(struct super_block *sb, ++ struct aufs_stbr __user *stbr, size_t count) ++{ ++ ssize_t err; ++ int nstbr; ++ aufs_bindex_t bindex, bend; ++ struct au_branch *br; ++ struct au_br_fhsm *bf; ++ ++ /* except the bottom branch */ ++ err = 0; ++ nstbr = 0; ++ bend = au_fhsm_bottom(sb); ++ for (bindex = 0; !err && bindex < bend; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (!au_br_fhsm(br->br_perm)) ++ continue; ++ ++ bf = br->br_fhsm; ++ mutex_lock(&bf->bf_lock); ++ if (bf->bf_readable) { ++ err = -EFAULT; ++ if (count >= sizeof(*stbr)) ++ err = au_fhsm_do_read_one(stbr++, &bf->bf_stfs, ++ br->br_id); ++ if (!err) { ++ bf->bf_readable = 0; ++ count -= sizeof(*stbr); ++ nstbr++; ++ } ++ } ++ mutex_unlock(&bf->bf_lock); ++ } ++ if (!err) ++ err = sizeof(*stbr) * nstbr; ++ ++ return err; ++} ++ ++static ssize_t au_fhsm_read(struct file *file, char __user *buf, size_t count, ++ loff_t *pos) ++{ ++ ssize_t err; ++ int readable; ++ aufs_bindex_t nfhsm, bindex, bend; ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ struct au_branch *br; ++ struct super_block *sb; ++ ++ err = 0; ++ sbinfo = file->private_data; ++ fhsm = &sbinfo->si_fhsm; ++need_data: ++ spin_lock_irq(&fhsm->fhsm_wqh.lock); ++ if (!atomic_read(&fhsm->fhsm_readable)) { ++ if (vfsub_file_flags(file) & O_NONBLOCK) ++ err = -EAGAIN; ++ else ++ err = wait_event_interruptible_locked_irq ++ (fhsm->fhsm_wqh, ++ atomic_read(&fhsm->fhsm_readable)); ++ } ++ spin_unlock_irq(&fhsm->fhsm_wqh.lock); ++ if (unlikely(err)) ++ goto out; ++ ++ /* sb may already be dead */ ++ au_rw_read_lock(&sbinfo->si_rwsem); ++ readable = atomic_read(&fhsm->fhsm_readable); ++ if (readable > 0) { ++ sb = sbinfo->si_sb; ++ AuDebugOn(!sb); ++ /* exclude the bottom branch */ ++ nfhsm = 0; ++ bend = au_fhsm_bottom(sb); ++ for (bindex = 0; bindex < bend; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (au_br_fhsm(br->br_perm)) ++ nfhsm++; ++ } ++ err = -EMSGSIZE; ++ if (nfhsm * sizeof(struct aufs_stbr) <= count) { ++ atomic_set(&fhsm->fhsm_readable, 0); ++ err = au_fhsm_do_read(sbinfo->si_sb, (void __user *)buf, ++ count); ++ } ++ } ++ au_rw_read_unlock(&sbinfo->si_rwsem); ++ if (!readable) ++ goto need_data; ++ ++out: ++ return err; ++} ++ ++static int au_fhsm_release(struct inode *inode, struct file *file) ++{ ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ ++ /* sb may already be dead */ ++ sbinfo = file->private_data; ++ fhsm = &sbinfo->si_fhsm; ++ spin_lock(&fhsm->fhsm_spin); ++ fhsm->fhsm_pid = 0; ++ spin_unlock(&fhsm->fhsm_spin); ++ kobject_put(&sbinfo->si_kobj); ++ ++ return 0; ++} ++ ++static const struct file_operations au_fhsm_fops = { ++ .owner = THIS_MODULE, ++ .llseek = noop_llseek, ++ .read = au_fhsm_read, ++ .poll = au_fhsm_poll, ++ .release = au_fhsm_release ++}; ++ ++int au_fhsm_fd(struct super_block *sb, int oflags) ++{ ++ int err, fd; ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ ++ err = -EPERM; ++ if (unlikely(!capable(CAP_SYS_ADMIN))) ++ goto out; ++ ++ err = -EINVAL; ++ if (unlikely(oflags & ~(O_CLOEXEC | O_NONBLOCK))) ++ goto out; ++ ++ err = 0; ++ sbinfo = au_sbi(sb); ++ fhsm = &sbinfo->si_fhsm; ++ spin_lock(&fhsm->fhsm_spin); ++ if (!fhsm->fhsm_pid) ++ fhsm->fhsm_pid = current->pid; ++ else ++ err = -EBUSY; ++ spin_unlock(&fhsm->fhsm_spin); ++ if (unlikely(err)) ++ goto out; ++ ++ oflags |= O_RDONLY; ++ /* oflags |= FMODE_NONOTIFY; */ ++ fd = anon_inode_getfd("[aufs_fhsm]", &au_fhsm_fops, sbinfo, oflags); ++ err = fd; ++ if (unlikely(fd < 0)) ++ goto out_pid; ++ ++ /* succeed reglardless 'fhsm' status */ ++ kobject_get(&sbinfo->si_kobj); ++ si_noflush_read_lock(sb); ++ if (au_ftest_si(sbinfo, FHSM)) ++ au_fhsm_wrote_all(sb, /*force*/0); ++ si_read_unlock(sb); ++ goto out; /* success */ ++ ++out_pid: ++ spin_lock(&fhsm->fhsm_spin); ++ fhsm->fhsm_pid = 0; ++ spin_unlock(&fhsm->fhsm_spin); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_fhsm_br_alloc(struct au_branch *br) ++{ ++ int err; ++ ++ err = 0; ++ br->br_fhsm = kmalloc(sizeof(*br->br_fhsm), GFP_NOFS); ++ if (br->br_fhsm) ++ au_br_fhsm_init(br->br_fhsm); ++ else ++ err = -ENOMEM; ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_fhsm_fin(struct super_block *sb) ++{ ++ au_fhsm_notify(sb, /*val*/-1); ++} ++ ++void au_fhsm_init(struct au_sbinfo *sbinfo) ++{ ++ struct au_fhsm *fhsm; ++ ++ fhsm = &sbinfo->si_fhsm; ++ spin_lock_init(&fhsm->fhsm_spin); ++ init_waitqueue_head(&fhsm->fhsm_wqh); ++ atomic_set(&fhsm->fhsm_readable, 0); ++ fhsm->fhsm_expire ++ = msecs_to_jiffies(AUFS_FHSM_CACHE_DEF_SEC * MSEC_PER_SEC); ++ fhsm->fhsm_bottom = -1; ++} ++ ++void au_fhsm_set(struct au_sbinfo *sbinfo, unsigned int sec) ++{ ++ sbinfo->si_fhsm.fhsm_expire ++ = msecs_to_jiffies(sec * MSEC_PER_SEC); ++} ++ ++void au_fhsm_show(struct seq_file *seq, struct au_sbinfo *sbinfo) ++{ ++ unsigned int u; ++ ++ if (!au_ftest_si(sbinfo, FHSM)) ++ return; ++ ++ u = jiffies_to_msecs(sbinfo->si_fhsm.fhsm_expire) / MSEC_PER_SEC; ++ if (u != AUFS_FHSM_CACHE_DEF_SEC) ++ seq_printf(seq, ",fhsm_sec=%u", u); ++} +diff --git a/fs/aufs/file.c b/fs/aufs/file.c +new file mode 100644 +index 0000000..12c7620 +--- /dev/null ++++ b/fs/aufs/file.c +@@ -0,0 +1,857 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * handling file/dir, and address_space operation ++ */ ++ ++#ifdef CONFIG_AUFS_DEBUG ++#include ++#endif ++#include ++#include "aufs.h" ++ ++/* drop flags for writing */ ++unsigned int au_file_roflags(unsigned int flags) ++{ ++ flags &= ~(O_WRONLY | O_RDWR | O_APPEND | O_CREAT | O_TRUNC); ++ flags |= O_RDONLY | O_NOATIME; ++ return flags; ++} ++ ++/* common functions to regular file and dir */ ++struct file *au_h_open(struct dentry *dentry, aufs_bindex_t bindex, int flags, ++ struct file *file, int force_wr) ++{ ++ struct file *h_file; ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct path h_path; ++ int err; ++ ++ /* a race condition can happen between open and unlink/rmdir */ ++ h_file = ERR_PTR(-ENOENT); ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (au_test_nfsd() && !h_dentry) ++ goto out; ++ h_inode = h_dentry->d_inode; ++ if (au_test_nfsd() && !h_inode) ++ goto out; ++ spin_lock(&h_dentry->d_lock); ++ err = (!d_unhashed(dentry) && d_unlinked(h_dentry)) ++ || !h_inode ++ /* || !dentry->d_inode->i_nlink */ ++ ; ++ spin_unlock(&h_dentry->d_lock); ++ if (unlikely(err)) ++ goto out; ++ ++ sb = dentry->d_sb; ++ br = au_sbr(sb, bindex); ++ err = au_br_test_oflag(flags, br); ++ h_file = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out; ++ ++ /* drop flags for writing */ ++ if (au_test_ro(sb, bindex, dentry->d_inode)) { ++ if (force_wr && !(flags & O_WRONLY)) ++ force_wr = 0; ++ flags = au_file_roflags(flags); ++ if (force_wr) { ++ h_file = ERR_PTR(-EROFS); ++ flags = au_file_roflags(flags); ++ if (unlikely(vfsub_native_ro(h_inode) ++ || IS_APPEND(h_inode))) ++ goto out; ++ flags &= ~O_ACCMODE; ++ flags |= O_WRONLY; ++ } ++ } ++ flags &= ~O_CREAT; ++ atomic_inc(&br->br_count); ++ h_path.dentry = h_dentry; ++ h_path.mnt = au_br_mnt(br); ++ h_file = vfsub_dentry_open(&h_path, flags); ++ if (IS_ERR(h_file)) ++ goto out_br; ++ ++ if (flags & __FMODE_EXEC) { ++ err = deny_write_access(h_file); ++ if (unlikely(err)) { ++ fput(h_file); ++ h_file = ERR_PTR(err); ++ goto out_br; ++ } ++ } ++ fsnotify_open(h_file); ++ goto out; /* success */ ++ ++out_br: ++ atomic_dec(&br->br_count); ++out: ++ return h_file; ++} ++ ++static int au_cmoo(struct dentry *dentry) ++{ ++ int err, cmoo; ++ unsigned int udba; ++ struct path h_path; ++ struct au_pin pin; ++ struct au_cp_generic cpg = { ++ .dentry = dentry, ++ .bdst = -1, ++ .bsrc = -1, ++ .len = -1, ++ .pin = &pin, ++ .flags = AuCpup_DTIME | AuCpup_HOPEN ++ }; ++ struct inode *inode, *delegated; ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ pid_t pid; ++ struct au_branch *br; ++ struct dentry *parent; ++ struct au_hinode *hdir; ++ ++ DiMustWriteLock(dentry); ++ inode = dentry->d_inode; ++ IiMustWriteLock(inode); ++ ++ err = 0; ++ if (IS_ROOT(dentry)) ++ goto out; ++ cpg.bsrc = au_dbstart(dentry); ++ if (!cpg.bsrc) ++ goto out; ++ ++ sb = dentry->d_sb; ++ sbinfo = au_sbi(sb); ++ fhsm = &sbinfo->si_fhsm; ++ pid = au_fhsm_pid(fhsm); ++ if (pid ++ && (current->pid == pid ++ || current->real_parent->pid == pid)) ++ goto out; ++ ++ br = au_sbr(sb, cpg.bsrc); ++ cmoo = au_br_cmoo(br->br_perm); ++ if (!cmoo) ++ goto out; ++ if (!S_ISREG(inode->i_mode)) ++ cmoo &= AuBrAttr_COO_ALL; ++ if (!cmoo) ++ goto out; ++ ++ parent = dget_parent(dentry); ++ di_write_lock_parent(parent); ++ err = au_wbr_do_copyup_bu(dentry, cpg.bsrc - 1); ++ cpg.bdst = err; ++ if (unlikely(err < 0)) { ++ err = 0; /* there is no upper writable branch */ ++ goto out_dgrade; ++ } ++ AuDbg("bsrc %d, bdst %d\n", cpg.bsrc, cpg.bdst); ++ ++ /* do not respect the coo attrib for the target branch */ ++ err = au_cpup_dirs(dentry, cpg.bdst); ++ if (unlikely(err)) ++ goto out_dgrade; ++ ++ di_downgrade_lock(parent, AuLock_IR); ++ udba = au_opt_udba(sb); ++ err = au_pin(&pin, dentry, cpg.bdst, udba, ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ err = au_sio_cpup_simple(&cpg); ++ au_unpin(&pin); ++ if (unlikely(err)) ++ goto out_parent; ++ if (!(cmoo & AuBrWAttr_MOO)) ++ goto out_parent; /* success */ ++ ++ err = au_pin(&pin, dentry, cpg.bsrc, udba, ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ h_path.mnt = au_br_mnt(br); ++ h_path.dentry = au_h_dptr(dentry, cpg.bsrc); ++ hdir = au_hi(parent->d_inode, cpg.bsrc); ++ delegated = NULL; ++ err = vfsub_unlink(hdir->hi_inode, &h_path, &delegated, /*force*/1); ++ au_unpin(&pin); ++ /* todo: keep h_dentry or not? */ ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ if (unlikely(err)) { ++ pr_err("unlink %pd after coo failed (%d), ignored\n", ++ dentry, err); ++ err = 0; ++ } ++ goto out_parent; /* success */ ++ ++out_dgrade: ++ di_downgrade_lock(parent, AuLock_IR); ++out_parent: ++ di_read_unlock(parent, AuLock_IR); ++ dput(parent); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_do_open(struct file *file, struct au_do_open_args *args) ++{ ++ int err, no_lock = args->no_lock; ++ struct dentry *dentry; ++ struct au_finfo *finfo; ++ ++ if (!no_lock) ++ err = au_finfo_init(file, args->fidir); ++ else { ++ lockdep_off(); ++ err = au_finfo_init(file, args->fidir); ++ lockdep_on(); ++ } ++ if (unlikely(err)) ++ goto out; ++ ++ dentry = file->f_dentry; ++ AuDebugOn(IS_ERR_OR_NULL(dentry)); ++ if (!no_lock) { ++ di_write_lock_child(dentry); ++ err = au_cmoo(dentry); ++ di_downgrade_lock(dentry, AuLock_IR); ++ if (!err) ++ err = args->open(file, vfsub_file_flags(file), NULL); ++ di_read_unlock(dentry, AuLock_IR); ++ } else { ++ err = au_cmoo(dentry); ++ if (!err) ++ err = args->open(file, vfsub_file_flags(file), ++ args->h_file); ++ if (!err && au_fbstart(file) != au_dbstart(dentry)) ++ /* ++ * cmoo happens after h_file was opened. ++ * need to refresh file later. ++ */ ++ atomic_dec(&au_fi(file)->fi_generation); ++ } ++ ++ finfo = au_fi(file); ++ if (!err) { ++ finfo->fi_file = file; ++ au_sphl_add(&finfo->fi_hlist, ++ &au_sbi(file->f_dentry->d_sb)->si_files); ++ } ++ if (!no_lock) ++ fi_write_unlock(file); ++ else { ++ lockdep_off(); ++ fi_write_unlock(file); ++ lockdep_on(); ++ } ++ if (unlikely(err)) { ++ finfo->fi_hdir = NULL; ++ au_finfo_fin(file); ++ } ++ ++out: ++ return err; ++} ++ ++int au_reopen_nondir(struct file *file) ++{ ++ int err; ++ aufs_bindex_t bstart; ++ struct dentry *dentry; ++ struct file *h_file, *h_file_tmp; ++ ++ dentry = file->f_dentry; ++ bstart = au_dbstart(dentry); ++ h_file_tmp = NULL; ++ if (au_fbstart(file) == bstart) { ++ h_file = au_hf_top(file); ++ if (file->f_mode == h_file->f_mode) ++ return 0; /* success */ ++ h_file_tmp = h_file; ++ get_file(h_file_tmp); ++ au_set_h_fptr(file, bstart, NULL); ++ } ++ AuDebugOn(au_fi(file)->fi_hdir); ++ /* ++ * it can happen ++ * file exists on both of rw and ro ++ * open --> dbstart and fbstart are both 0 ++ * prepend a branch as rw, "rw" become ro ++ * remove rw/file ++ * delete the top branch, "rw" becomes rw again ++ * --> dbstart is 1, fbstart is still 0 ++ * write --> fbstart is 0 but dbstart is 1 ++ */ ++ /* AuDebugOn(au_fbstart(file) < bstart); */ ++ ++ h_file = au_h_open(dentry, bstart, vfsub_file_flags(file) & ~O_TRUNC, ++ file, /*force_wr*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) { ++ if (h_file_tmp) { ++ atomic_inc(&au_sbr(dentry->d_sb, bstart)->br_count); ++ au_set_h_fptr(file, bstart, h_file_tmp); ++ h_file_tmp = NULL; ++ } ++ goto out; /* todo: close all? */ ++ } ++ ++ err = 0; ++ au_set_fbstart(file, bstart); ++ au_set_h_fptr(file, bstart, h_file); ++ au_update_figen(file); ++ /* todo: necessary? */ ++ /* file->f_ra = h_file->f_ra; */ ++ ++out: ++ if (h_file_tmp) ++ fput(h_file_tmp); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_reopen_wh(struct file *file, aufs_bindex_t btgt, ++ struct dentry *hi_wh) ++{ ++ int err; ++ aufs_bindex_t bstart; ++ struct au_dinfo *dinfo; ++ struct dentry *h_dentry; ++ struct au_hdentry *hdp; ++ ++ dinfo = au_di(file->f_dentry); ++ AuRwMustWriteLock(&dinfo->di_rwsem); ++ ++ bstart = dinfo->di_bstart; ++ dinfo->di_bstart = btgt; ++ hdp = dinfo->di_hdentry; ++ h_dentry = hdp[0 + btgt].hd_dentry; ++ hdp[0 + btgt].hd_dentry = hi_wh; ++ err = au_reopen_nondir(file); ++ hdp[0 + btgt].hd_dentry = h_dentry; ++ dinfo->di_bstart = bstart; ++ ++ return err; ++} ++ ++static int au_ready_to_write_wh(struct file *file, loff_t len, ++ aufs_bindex_t bcpup, struct au_pin *pin) ++{ ++ int err; ++ struct inode *inode, *h_inode; ++ struct dentry *h_dentry, *hi_wh; ++ struct au_cp_generic cpg = { ++ .dentry = file->f_dentry, ++ .bdst = bcpup, ++ .bsrc = -1, ++ .len = len, ++ .pin = pin ++ }; ++ ++ au_update_dbstart(cpg.dentry); ++ inode = cpg.dentry->d_inode; ++ h_inode = NULL; ++ if (au_dbstart(cpg.dentry) <= bcpup ++ && au_dbend(cpg.dentry) >= bcpup) { ++ h_dentry = au_h_dptr(cpg.dentry, bcpup); ++ if (h_dentry) ++ h_inode = h_dentry->d_inode; ++ } ++ hi_wh = au_hi_wh(inode, bcpup); ++ if (!hi_wh && !h_inode) ++ err = au_sio_cpup_wh(&cpg, file); ++ else ++ /* already copied-up after unlink */ ++ err = au_reopen_wh(file, bcpup, hi_wh); ++ ++ if (!err ++ && (inode->i_nlink > 1 ++ || (inode->i_state & I_LINKABLE)) ++ && au_opt_test(au_mntflags(cpg.dentry->d_sb), PLINK)) ++ au_plink_append(inode, bcpup, au_h_dptr(cpg.dentry, bcpup)); ++ ++ return err; ++} ++ ++/* ++ * prepare the @file for writing. ++ */ ++int au_ready_to_write(struct file *file, loff_t len, struct au_pin *pin) ++{ ++ int err; ++ aufs_bindex_t dbstart; ++ struct dentry *parent; ++ struct inode *inode; ++ struct super_block *sb; ++ struct file *h_file; ++ struct au_cp_generic cpg = { ++ .dentry = file->f_dentry, ++ .bdst = -1, ++ .bsrc = -1, ++ .len = len, ++ .pin = pin, ++ .flags = AuCpup_DTIME ++ }; ++ ++ sb = cpg.dentry->d_sb; ++ inode = cpg.dentry->d_inode; ++ cpg.bsrc = au_fbstart(file); ++ err = au_test_ro(sb, cpg.bsrc, inode); ++ if (!err && (au_hf_top(file)->f_mode & FMODE_WRITE)) { ++ err = au_pin(pin, cpg.dentry, cpg.bsrc, AuOpt_UDBA_NONE, ++ /*flags*/0); ++ goto out; ++ } ++ ++ /* need to cpup or reopen */ ++ parent = dget_parent(cpg.dentry); ++ di_write_lock_parent(parent); ++ err = AuWbrCopyup(au_sbi(sb), cpg.dentry); ++ cpg.bdst = err; ++ if (unlikely(err < 0)) ++ goto out_dgrade; ++ err = 0; ++ ++ if (!d_unhashed(cpg.dentry) && !au_h_dptr(parent, cpg.bdst)) { ++ err = au_cpup_dirs(cpg.dentry, cpg.bdst); ++ if (unlikely(err)) ++ goto out_dgrade; ++ } ++ ++ err = au_pin(pin, cpg.dentry, cpg.bdst, AuOpt_UDBA_NONE, ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (unlikely(err)) ++ goto out_dgrade; ++ ++ dbstart = au_dbstart(cpg.dentry); ++ if (dbstart <= cpg.bdst) ++ cpg.bsrc = cpg.bdst; ++ ++ if (dbstart <= cpg.bdst /* just reopen */ ++ || !d_unhashed(cpg.dentry) /* copyup and reopen */ ++ ) { ++ h_file = au_h_open_pre(cpg.dentry, cpg.bsrc, /*force_wr*/0); ++ if (IS_ERR(h_file)) ++ err = PTR_ERR(h_file); ++ else { ++ di_downgrade_lock(parent, AuLock_IR); ++ if (dbstart > cpg.bdst) ++ err = au_sio_cpup_simple(&cpg); ++ if (!err) ++ err = au_reopen_nondir(file); ++ au_h_open_post(cpg.dentry, cpg.bsrc, h_file); ++ } ++ } else { /* copyup as wh and reopen */ ++ /* ++ * since writable hfsplus branch is not supported, ++ * h_open_pre/post() are unnecessary. ++ */ ++ err = au_ready_to_write_wh(file, len, cpg.bdst, pin); ++ di_downgrade_lock(parent, AuLock_IR); ++ } ++ ++ if (!err) { ++ au_pin_set_parent_lflag(pin, /*lflag*/0); ++ goto out_dput; /* success */ ++ } ++ au_unpin(pin); ++ goto out_unlock; ++ ++out_dgrade: ++ di_downgrade_lock(parent, AuLock_IR); ++out_unlock: ++ di_read_unlock(parent, AuLock_IR); ++out_dput: ++ dput(parent); ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_do_flush(struct file *file, fl_owner_t id, ++ int (*flush)(struct file *file, fl_owner_t id)) ++{ ++ int err; ++ struct super_block *sb; ++ struct inode *inode; ++ ++ inode = file_inode(file); ++ sb = inode->i_sb; ++ si_noflush_read_lock(sb); ++ fi_read_lock(file); ++ ii_read_lock_child(inode); ++ ++ err = flush(file, id); ++ au_cpup_attr_timesizes(inode); ++ ++ ii_read_unlock(inode); ++ fi_read_unlock(file); ++ si_read_unlock(sb); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_file_refresh_by_inode(struct file *file, int *need_reopen) ++{ ++ int err; ++ struct au_pin pin; ++ struct au_finfo *finfo; ++ struct dentry *parent, *hi_wh; ++ struct inode *inode; ++ struct super_block *sb; ++ struct au_cp_generic cpg = { ++ .dentry = file->f_dentry, ++ .bdst = -1, ++ .bsrc = -1, ++ .len = -1, ++ .pin = &pin, ++ .flags = AuCpup_DTIME ++ }; ++ ++ FiMustWriteLock(file); ++ ++ err = 0; ++ finfo = au_fi(file); ++ sb = cpg.dentry->d_sb; ++ inode = cpg.dentry->d_inode; ++ cpg.bdst = au_ibstart(inode); ++ if (cpg.bdst == finfo->fi_btop || IS_ROOT(cpg.dentry)) ++ goto out; ++ ++ parent = dget_parent(cpg.dentry); ++ if (au_test_ro(sb, cpg.bdst, inode)) { ++ di_read_lock_parent(parent, !AuLock_IR); ++ err = AuWbrCopyup(au_sbi(sb), cpg.dentry); ++ cpg.bdst = err; ++ di_read_unlock(parent, !AuLock_IR); ++ if (unlikely(err < 0)) ++ goto out_parent; ++ err = 0; ++ } ++ ++ di_read_lock_parent(parent, AuLock_IR); ++ hi_wh = au_hi_wh(inode, cpg.bdst); ++ if (!S_ISDIR(inode->i_mode) ++ && au_opt_test(au_mntflags(sb), PLINK) ++ && au_plink_test(inode) ++ && !d_unhashed(cpg.dentry) ++ && cpg.bdst < au_dbstart(cpg.dentry)) { ++ err = au_test_and_cpup_dirs(cpg.dentry, cpg.bdst); ++ if (unlikely(err)) ++ goto out_unlock; ++ ++ /* always superio. */ ++ err = au_pin(&pin, cpg.dentry, cpg.bdst, AuOpt_UDBA_NONE, ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (!err) { ++ err = au_sio_cpup_simple(&cpg); ++ au_unpin(&pin); ++ } ++ } else if (hi_wh) { ++ /* already copied-up after unlink */ ++ err = au_reopen_wh(file, cpg.bdst, hi_wh); ++ *need_reopen = 0; ++ } ++ ++out_unlock: ++ di_read_unlock(parent, AuLock_IR); ++out_parent: ++ dput(parent); ++out: ++ return err; ++} ++ ++static void au_do_refresh_dir(struct file *file) ++{ ++ aufs_bindex_t bindex, bend, new_bindex, brid; ++ struct au_hfile *p, tmp, *q; ++ struct au_finfo *finfo; ++ struct super_block *sb; ++ struct au_fidir *fidir; ++ ++ FiMustWriteLock(file); ++ ++ sb = file->f_dentry->d_sb; ++ finfo = au_fi(file); ++ fidir = finfo->fi_hdir; ++ AuDebugOn(!fidir); ++ p = fidir->fd_hfile + finfo->fi_btop; ++ brid = p->hf_br->br_id; ++ bend = fidir->fd_bbot; ++ for (bindex = finfo->fi_btop; bindex <= bend; bindex++, p++) { ++ if (!p->hf_file) ++ continue; ++ ++ new_bindex = au_br_index(sb, p->hf_br->br_id); ++ if (new_bindex == bindex) ++ continue; ++ if (new_bindex < 0) { ++ au_set_h_fptr(file, bindex, NULL); ++ continue; ++ } ++ ++ /* swap two lower inode, and loop again */ ++ q = fidir->fd_hfile + new_bindex; ++ tmp = *q; ++ *q = *p; ++ *p = tmp; ++ if (tmp.hf_file) { ++ bindex--; ++ p--; ++ } ++ } ++ ++ p = fidir->fd_hfile; ++ if (!au_test_mmapped(file) && !d_unlinked(file->f_dentry)) { ++ bend = au_sbend(sb); ++ for (finfo->fi_btop = 0; finfo->fi_btop <= bend; ++ finfo->fi_btop++, p++) ++ if (p->hf_file) { ++ if (file_inode(p->hf_file)) ++ break; ++ au_hfput(p, file); ++ } ++ } else { ++ bend = au_br_index(sb, brid); ++ for (finfo->fi_btop = 0; finfo->fi_btop < bend; ++ finfo->fi_btop++, p++) ++ if (p->hf_file) ++ au_hfput(p, file); ++ bend = au_sbend(sb); ++ } ++ ++ p = fidir->fd_hfile + bend; ++ for (fidir->fd_bbot = bend; fidir->fd_bbot >= finfo->fi_btop; ++ fidir->fd_bbot--, p--) ++ if (p->hf_file) { ++ if (file_inode(p->hf_file)) ++ break; ++ au_hfput(p, file); ++ } ++ AuDebugOn(fidir->fd_bbot < finfo->fi_btop); ++} ++ ++/* ++ * after branch manipulating, refresh the file. ++ */ ++static int refresh_file(struct file *file, int (*reopen)(struct file *file)) ++{ ++ int err, need_reopen; ++ aufs_bindex_t bend, bindex; ++ struct dentry *dentry; ++ struct au_finfo *finfo; ++ struct au_hfile *hfile; ++ ++ dentry = file->f_dentry; ++ finfo = au_fi(file); ++ if (!finfo->fi_hdir) { ++ hfile = &finfo->fi_htop; ++ AuDebugOn(!hfile->hf_file); ++ bindex = au_br_index(dentry->d_sb, hfile->hf_br->br_id); ++ AuDebugOn(bindex < 0); ++ if (bindex != finfo->fi_btop) ++ au_set_fbstart(file, bindex); ++ } else { ++ err = au_fidir_realloc(finfo, au_sbend(dentry->d_sb) + 1); ++ if (unlikely(err)) ++ goto out; ++ au_do_refresh_dir(file); ++ } ++ ++ err = 0; ++ need_reopen = 1; ++ if (!au_test_mmapped(file)) ++ err = au_file_refresh_by_inode(file, &need_reopen); ++ if (!err && need_reopen && !d_unlinked(dentry)) ++ err = reopen(file); ++ if (!err) { ++ au_update_figen(file); ++ goto out; /* success */ ++ } ++ ++ /* error, close all lower files */ ++ if (finfo->fi_hdir) { ++ bend = au_fbend_dir(file); ++ for (bindex = au_fbstart(file); bindex <= bend; bindex++) ++ au_set_h_fptr(file, bindex, NULL); ++ } ++ ++out: ++ return err; ++} ++ ++/* common function to regular file and dir */ ++int au_reval_and_lock_fdi(struct file *file, int (*reopen)(struct file *file), ++ int wlock) ++{ ++ int err; ++ unsigned int sigen, figen; ++ aufs_bindex_t bstart; ++ unsigned char pseudo_link; ++ struct dentry *dentry; ++ struct inode *inode; ++ ++ err = 0; ++ dentry = file->f_dentry; ++ inode = dentry->d_inode; ++ sigen = au_sigen(dentry->d_sb); ++ fi_write_lock(file); ++ figen = au_figen(file); ++ di_write_lock_child(dentry); ++ bstart = au_dbstart(dentry); ++ pseudo_link = (bstart != au_ibstart(inode)); ++ if (sigen == figen && !pseudo_link && au_fbstart(file) == bstart) { ++ if (!wlock) { ++ di_downgrade_lock(dentry, AuLock_IR); ++ fi_downgrade_lock(file); ++ } ++ goto out; /* success */ ++ } ++ ++ AuDbg("sigen %d, figen %d\n", sigen, figen); ++ if (au_digen_test(dentry, sigen)) { ++ err = au_reval_dpath(dentry, sigen); ++ AuDebugOn(!err && au_digen_test(dentry, sigen)); ++ } ++ ++ if (!err) ++ err = refresh_file(file, reopen); ++ if (!err) { ++ if (!wlock) { ++ di_downgrade_lock(dentry, AuLock_IR); ++ fi_downgrade_lock(file); ++ } ++ } else { ++ di_write_unlock(dentry); ++ fi_write_unlock(file); ++ } ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* cf. aufs_nopage() */ ++/* for madvise(2) */ ++static int aufs_readpage(struct file *file __maybe_unused, struct page *page) ++{ ++ unlock_page(page); ++ return 0; ++} ++ ++/* it will never be called, but necessary to support O_DIRECT */ ++static ssize_t aufs_direct_IO(int rw, struct kiocb *iocb, ++ struct iov_iter *iter, loff_t offset) ++{ BUG(); return 0; } ++ ++/* ++ * it will never be called, but madvise and fadvise behaves differently ++ * when get_xip_mem is defined ++ */ ++static int aufs_get_xip_mem(struct address_space *mapping, pgoff_t pgoff, ++ int create, void **kmem, unsigned long *pfn) ++{ BUG(); return 0; } ++ ++/* they will never be called. */ ++#ifdef CONFIG_AUFS_DEBUG ++static int aufs_write_begin(struct file *file, struct address_space *mapping, ++ loff_t pos, unsigned len, unsigned flags, ++ struct page **pagep, void **fsdata) ++{ AuUnsupport(); return 0; } ++static int aufs_write_end(struct file *file, struct address_space *mapping, ++ loff_t pos, unsigned len, unsigned copied, ++ struct page *page, void *fsdata) ++{ AuUnsupport(); return 0; } ++static int aufs_writepage(struct page *page, struct writeback_control *wbc) ++{ AuUnsupport(); return 0; } ++ ++static int aufs_set_page_dirty(struct page *page) ++{ AuUnsupport(); return 0; } ++static void aufs_invalidatepage(struct page *page, unsigned int offset, ++ unsigned int length) ++{ AuUnsupport(); } ++static int aufs_releasepage(struct page *page, gfp_t gfp) ++{ AuUnsupport(); return 0; } ++#if 0 /* called by memory compaction regardless file */ ++static int aufs_migratepage(struct address_space *mapping, struct page *newpage, ++ struct page *page, enum migrate_mode mode) ++{ AuUnsupport(); return 0; } ++#endif ++static int aufs_launder_page(struct page *page) ++{ AuUnsupport(); return 0; } ++static int aufs_is_partially_uptodate(struct page *page, ++ unsigned long from, ++ unsigned long count) ++{ AuUnsupport(); return 0; } ++static void aufs_is_dirty_writeback(struct page *page, bool *dirty, ++ bool *writeback) ++{ AuUnsupport(); } ++static int aufs_error_remove_page(struct address_space *mapping, ++ struct page *page) ++{ AuUnsupport(); return 0; } ++static int aufs_swap_activate(struct swap_info_struct *sis, struct file *file, ++ sector_t *span) ++{ AuUnsupport(); return 0; } ++static void aufs_swap_deactivate(struct file *file) ++{ AuUnsupport(); } ++#endif /* CONFIG_AUFS_DEBUG */ ++ ++const struct address_space_operations aufs_aop = { ++ .readpage = aufs_readpage, ++ .direct_IO = aufs_direct_IO, ++ .get_xip_mem = aufs_get_xip_mem, ++#ifdef CONFIG_AUFS_DEBUG ++ .writepage = aufs_writepage, ++ /* no writepages, because of writepage */ ++ .set_page_dirty = aufs_set_page_dirty, ++ /* no readpages, because of readpage */ ++ .write_begin = aufs_write_begin, ++ .write_end = aufs_write_end, ++ /* no bmap, no block device */ ++ .invalidatepage = aufs_invalidatepage, ++ .releasepage = aufs_releasepage, ++ /* is fallback_migrate_page ok? */ ++ /* .migratepage = aufs_migratepage, */ ++ .launder_page = aufs_launder_page, ++ .is_partially_uptodate = aufs_is_partially_uptodate, ++ .is_dirty_writeback = aufs_is_dirty_writeback, ++ .error_remove_page = aufs_error_remove_page, ++ .swap_activate = aufs_swap_activate, ++ .swap_deactivate = aufs_swap_deactivate ++#endif /* CONFIG_AUFS_DEBUG */ ++}; +diff --git a/fs/aufs/file.h b/fs/aufs/file.h +new file mode 100644 +index 0000000..564be91 +--- /dev/null ++++ b/fs/aufs/file.h +@@ -0,0 +1,291 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * file operations ++ */ ++ ++#ifndef __AUFS_FILE_H__ ++#define __AUFS_FILE_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++#include "rwsem.h" ++ ++struct au_branch; ++struct au_hfile { ++ struct file *hf_file; ++ struct au_branch *hf_br; ++}; ++ ++struct au_vdir; ++struct au_fidir { ++ aufs_bindex_t fd_bbot; ++ aufs_bindex_t fd_nent; ++ struct au_vdir *fd_vdir_cache; ++ struct au_hfile fd_hfile[]; ++}; ++ ++static inline int au_fidir_sz(int nent) ++{ ++ AuDebugOn(nent < 0); ++ return sizeof(struct au_fidir) + sizeof(struct au_hfile) * nent; ++} ++ ++struct au_finfo { ++ atomic_t fi_generation; ++ ++ struct au_rwsem fi_rwsem; ++ aufs_bindex_t fi_btop; ++ ++ /* do not union them */ ++ struct { /* for non-dir */ ++ struct au_hfile fi_htop; ++ atomic_t fi_mmapped; ++ }; ++ struct au_fidir *fi_hdir; /* for dir only */ ++ ++ struct hlist_node fi_hlist; ++ struct file *fi_file; /* very ugly */ ++} ____cacheline_aligned_in_smp; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* file.c */ ++extern const struct address_space_operations aufs_aop; ++unsigned int au_file_roflags(unsigned int flags); ++struct file *au_h_open(struct dentry *dentry, aufs_bindex_t bindex, int flags, ++ struct file *file, int force_wr); ++struct au_do_open_args { ++ int no_lock; ++ int (*open)(struct file *file, int flags, ++ struct file *h_file); ++ struct au_fidir *fidir; ++ struct file *h_file; ++}; ++int au_do_open(struct file *file, struct au_do_open_args *args); ++int au_reopen_nondir(struct file *file); ++struct au_pin; ++int au_ready_to_write(struct file *file, loff_t len, struct au_pin *pin); ++int au_reval_and_lock_fdi(struct file *file, int (*reopen)(struct file *file), ++ int wlock); ++int au_do_flush(struct file *file, fl_owner_t id, ++ int (*flush)(struct file *file, fl_owner_t id)); ++ ++/* poll.c */ ++#ifdef CONFIG_AUFS_POLL ++unsigned int aufs_poll(struct file *file, poll_table *wait); ++#endif ++ ++#ifdef CONFIG_AUFS_BR_HFSPLUS ++/* hfsplus.c */ ++struct file *au_h_open_pre(struct dentry *dentry, aufs_bindex_t bindex, ++ int force_wr); ++void au_h_open_post(struct dentry *dentry, aufs_bindex_t bindex, ++ struct file *h_file); ++#else ++AuStub(struct file *, au_h_open_pre, return NULL, struct dentry *dentry, ++ aufs_bindex_t bindex, int force_wr) ++AuStubVoid(au_h_open_post, struct dentry *dentry, aufs_bindex_t bindex, ++ struct file *h_file); ++#endif ++ ++/* f_op.c */ ++extern const struct file_operations aufs_file_fop; ++int au_do_open_nondir(struct file *file, int flags, struct file *h_file); ++int aufs_release_nondir(struct inode *inode __maybe_unused, struct file *file); ++struct file *au_read_pre(struct file *file, int keep_fi); ++ ++/* finfo.c */ ++void au_hfput(struct au_hfile *hf, struct file *file); ++void au_set_h_fptr(struct file *file, aufs_bindex_t bindex, ++ struct file *h_file); ++ ++void au_update_figen(struct file *file); ++struct au_fidir *au_fidir_alloc(struct super_block *sb); ++int au_fidir_realloc(struct au_finfo *finfo, int nbr); ++ ++void au_fi_init_once(void *_fi); ++void au_finfo_fin(struct file *file); ++int au_finfo_init(struct file *file, struct au_fidir *fidir); ++ ++/* ioctl.c */ ++long aufs_ioctl_nondir(struct file *file, unsigned int cmd, unsigned long arg); ++#ifdef CONFIG_COMPAT ++long aufs_compat_ioctl_dir(struct file *file, unsigned int cmd, ++ unsigned long arg); ++long aufs_compat_ioctl_nondir(struct file *file, unsigned int cmd, ++ unsigned long arg); ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct au_finfo *au_fi(struct file *file) ++{ ++ return file->private_data; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * fi_read_lock, fi_write_lock, ++ * fi_read_unlock, fi_write_unlock, fi_downgrade_lock ++ */ ++AuSimpleRwsemFuncs(fi, struct file *f, &au_fi(f)->fi_rwsem); ++ ++#define FiMustNoWaiters(f) AuRwMustNoWaiters(&au_fi(f)->fi_rwsem) ++#define FiMustAnyLock(f) AuRwMustAnyLock(&au_fi(f)->fi_rwsem) ++#define FiMustWriteLock(f) AuRwMustWriteLock(&au_fi(f)->fi_rwsem) ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* todo: hard/soft set? */ ++static inline aufs_bindex_t au_fbstart(struct file *file) ++{ ++ FiMustAnyLock(file); ++ return au_fi(file)->fi_btop; ++} ++ ++static inline aufs_bindex_t au_fbend_dir(struct file *file) ++{ ++ FiMustAnyLock(file); ++ AuDebugOn(!au_fi(file)->fi_hdir); ++ return au_fi(file)->fi_hdir->fd_bbot; ++} ++ ++static inline struct au_vdir *au_fvdir_cache(struct file *file) ++{ ++ FiMustAnyLock(file); ++ AuDebugOn(!au_fi(file)->fi_hdir); ++ return au_fi(file)->fi_hdir->fd_vdir_cache; ++} ++ ++static inline void au_set_fbstart(struct file *file, aufs_bindex_t bindex) ++{ ++ FiMustWriteLock(file); ++ au_fi(file)->fi_btop = bindex; ++} ++ ++static inline void au_set_fbend_dir(struct file *file, aufs_bindex_t bindex) ++{ ++ FiMustWriteLock(file); ++ AuDebugOn(!au_fi(file)->fi_hdir); ++ au_fi(file)->fi_hdir->fd_bbot = bindex; ++} ++ ++static inline void au_set_fvdir_cache(struct file *file, ++ struct au_vdir *vdir_cache) ++{ ++ FiMustWriteLock(file); ++ AuDebugOn(!au_fi(file)->fi_hdir); ++ au_fi(file)->fi_hdir->fd_vdir_cache = vdir_cache; ++} ++ ++static inline struct file *au_hf_top(struct file *file) ++{ ++ FiMustAnyLock(file); ++ AuDebugOn(au_fi(file)->fi_hdir); ++ return au_fi(file)->fi_htop.hf_file; ++} ++ ++static inline struct file *au_hf_dir(struct file *file, aufs_bindex_t bindex) ++{ ++ FiMustAnyLock(file); ++ AuDebugOn(!au_fi(file)->fi_hdir); ++ return au_fi(file)->fi_hdir->fd_hfile[0 + bindex].hf_file; ++} ++ ++/* todo: memory barrier? */ ++static inline unsigned int au_figen(struct file *f) ++{ ++ return atomic_read(&au_fi(f)->fi_generation); ++} ++ ++static inline void au_set_mmapped(struct file *f) ++{ ++ if (atomic_inc_return(&au_fi(f)->fi_mmapped)) ++ return; ++ pr_warn("fi_mmapped wrapped around\n"); ++ while (!atomic_inc_return(&au_fi(f)->fi_mmapped)) ++ ; ++} ++ ++static inline void au_unset_mmapped(struct file *f) ++{ ++ atomic_dec(&au_fi(f)->fi_mmapped); ++} ++ ++static inline int au_test_mmapped(struct file *f) ++{ ++ return atomic_read(&au_fi(f)->fi_mmapped); ++} ++ ++/* customize vma->vm_file */ ++ ++static inline void au_do_vm_file_reset(struct vm_area_struct *vma, ++ struct file *file) ++{ ++ struct file *f; ++ ++ f = vma->vm_file; ++ get_file(file); ++ vma->vm_file = file; ++ fput(f); ++} ++ ++#ifdef CONFIG_MMU ++#define AuDbgVmRegion(file, vma) do {} while (0) ++ ++static inline void au_vm_file_reset(struct vm_area_struct *vma, ++ struct file *file) ++{ ++ au_do_vm_file_reset(vma, file); ++} ++#else ++#define AuDbgVmRegion(file, vma) \ ++ AuDebugOn((vma)->vm_region && (vma)->vm_region->vm_file != (file)) ++ ++static inline void au_vm_file_reset(struct vm_area_struct *vma, ++ struct file *file) ++{ ++ struct file *f; ++ ++ au_do_vm_file_reset(vma, file); ++ f = vma->vm_region->vm_file; ++ get_file(file); ++ vma->vm_region->vm_file = file; ++ fput(f); ++} ++#endif /* CONFIG_MMU */ ++ ++/* handle vma->vm_prfile */ ++static inline void au_vm_prfile_set(struct vm_area_struct *vma, ++ struct file *file) ++{ ++ get_file(file); ++ vma->vm_prfile = file; ++#ifndef CONFIG_MMU ++ get_file(file); ++ vma->vm_region->vm_prfile = file; ++#endif ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_FILE_H__ */ +diff --git a/fs/aufs/finfo.c b/fs/aufs/finfo.c +new file mode 100644 +index 0000000..7e25db3 +--- /dev/null ++++ b/fs/aufs/finfo.c +@@ -0,0 +1,156 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * file private data ++ */ ++ ++#include "aufs.h" ++ ++void au_hfput(struct au_hfile *hf, struct file *file) ++{ ++ /* todo: direct access f_flags */ ++ if (vfsub_file_flags(file) & __FMODE_EXEC) ++ allow_write_access(hf->hf_file); ++ fput(hf->hf_file); ++ hf->hf_file = NULL; ++ atomic_dec(&hf->hf_br->br_count); ++ hf->hf_br = NULL; ++} ++ ++void au_set_h_fptr(struct file *file, aufs_bindex_t bindex, struct file *val) ++{ ++ struct au_finfo *finfo = au_fi(file); ++ struct au_hfile *hf; ++ struct au_fidir *fidir; ++ ++ fidir = finfo->fi_hdir; ++ if (!fidir) { ++ AuDebugOn(finfo->fi_btop != bindex); ++ hf = &finfo->fi_htop; ++ } else ++ hf = fidir->fd_hfile + bindex; ++ ++ if (hf && hf->hf_file) ++ au_hfput(hf, file); ++ if (val) { ++ FiMustWriteLock(file); ++ AuDebugOn(IS_ERR_OR_NULL(file->f_dentry)); ++ hf->hf_file = val; ++ hf->hf_br = au_sbr(file->f_dentry->d_sb, bindex); ++ } ++} ++ ++void au_update_figen(struct file *file) ++{ ++ atomic_set(&au_fi(file)->fi_generation, au_digen(file->f_dentry)); ++ /* smp_mb(); */ /* atomic_set */ ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_fidir *au_fidir_alloc(struct super_block *sb) ++{ ++ struct au_fidir *fidir; ++ int nbr; ++ ++ nbr = au_sbend(sb) + 1; ++ if (nbr < 2) ++ nbr = 2; /* initial allocate for 2 branches */ ++ fidir = kzalloc(au_fidir_sz(nbr), GFP_NOFS); ++ if (fidir) { ++ fidir->fd_bbot = -1; ++ fidir->fd_nent = nbr; ++ } ++ ++ return fidir; ++} ++ ++int au_fidir_realloc(struct au_finfo *finfo, int nbr) ++{ ++ int err; ++ struct au_fidir *fidir, *p; ++ ++ AuRwMustWriteLock(&finfo->fi_rwsem); ++ fidir = finfo->fi_hdir; ++ AuDebugOn(!fidir); ++ ++ err = -ENOMEM; ++ p = au_kzrealloc(fidir, au_fidir_sz(fidir->fd_nent), au_fidir_sz(nbr), ++ GFP_NOFS); ++ if (p) { ++ p->fd_nent = nbr; ++ finfo->fi_hdir = p; ++ err = 0; ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_finfo_fin(struct file *file) ++{ ++ struct au_finfo *finfo; ++ ++ au_nfiles_dec(file->f_dentry->d_sb); ++ ++ finfo = au_fi(file); ++ AuDebugOn(finfo->fi_hdir); ++ AuRwDestroy(&finfo->fi_rwsem); ++ au_cache_free_finfo(finfo); ++} ++ ++void au_fi_init_once(void *_finfo) ++{ ++ struct au_finfo *finfo = _finfo; ++ static struct lock_class_key aufs_fi; ++ ++ au_rw_init(&finfo->fi_rwsem); ++ au_rw_class(&finfo->fi_rwsem, &aufs_fi); ++} ++ ++int au_finfo_init(struct file *file, struct au_fidir *fidir) ++{ ++ int err; ++ struct au_finfo *finfo; ++ struct dentry *dentry; ++ ++ err = -ENOMEM; ++ dentry = file->f_dentry; ++ finfo = au_cache_alloc_finfo(); ++ if (unlikely(!finfo)) ++ goto out; ++ ++ err = 0; ++ au_nfiles_inc(dentry->d_sb); ++ /* verbose coding for lock class name */ ++ if (!fidir) ++ au_rw_class(&finfo->fi_rwsem, au_lc_key + AuLcNonDir_FIINFO); ++ else ++ au_rw_class(&finfo->fi_rwsem, au_lc_key + AuLcDir_FIINFO); ++ au_rw_write_lock(&finfo->fi_rwsem); ++ finfo->fi_btop = -1; ++ finfo->fi_hdir = fidir; ++ atomic_set(&finfo->fi_generation, au_digen(dentry)); ++ /* smp_mb(); */ /* atomic_set */ ++ ++ file->private_data = finfo; ++ ++out: ++ return err; ++} +diff --git a/fs/aufs/fstype.h b/fs/aufs/fstype.h +new file mode 100644 +index 0000000..2842400 +--- /dev/null ++++ b/fs/aufs/fstype.h +@@ -0,0 +1,400 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * judging filesystem type ++ */ ++ ++#ifndef __AUFS_FSTYPE_H__ ++#define __AUFS_FSTYPE_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++#include ++ ++static inline int au_test_aufs(struct super_block *sb) ++{ ++ return sb->s_magic == AUFS_SUPER_MAGIC; ++} ++ ++static inline const char *au_sbtype(struct super_block *sb) ++{ ++ return sb->s_type->name; ++} ++ ++static inline int au_test_iso9660(struct super_block *sb __maybe_unused) ++{ ++#if defined(CONFIG_ISO9660_FS) || defined(CONFIG_ISO9660_FS_MODULE) ++ return sb->s_magic == ISOFS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_romfs(struct super_block *sb __maybe_unused) ++{ ++#if defined(CONFIG_ROMFS_FS) || defined(CONFIG_ROMFS_FS_MODULE) ++ return sb->s_magic == ROMFS_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_cramfs(struct super_block *sb __maybe_unused) ++{ ++#if defined(CONFIG_CRAMFS) || defined(CONFIG_CRAMFS_MODULE) ++ return sb->s_magic == CRAMFS_MAGIC; ++#endif ++ return 0; ++} ++ ++static inline int au_test_nfs(struct super_block *sb __maybe_unused) ++{ ++#if defined(CONFIG_NFS_FS) || defined(CONFIG_NFS_FS_MODULE) ++ return sb->s_magic == NFS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_fuse(struct super_block *sb __maybe_unused) ++{ ++#if defined(CONFIG_FUSE_FS) || defined(CONFIG_FUSE_FS_MODULE) ++ return sb->s_magic == FUSE_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_xfs(struct super_block *sb __maybe_unused) ++{ ++#if defined(CONFIG_XFS_FS) || defined(CONFIG_XFS_FS_MODULE) ++ return sb->s_magic == XFS_SB_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_tmpfs(struct super_block *sb __maybe_unused) ++{ ++#ifdef CONFIG_TMPFS ++ return sb->s_magic == TMPFS_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_ecryptfs(struct super_block *sb __maybe_unused) ++{ ++#if defined(CONFIG_ECRYPT_FS) || defined(CONFIG_ECRYPT_FS_MODULE) ++ return !strcmp(au_sbtype(sb), "ecryptfs"); ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_ramfs(struct super_block *sb) ++{ ++ return sb->s_magic == RAMFS_MAGIC; ++} ++ ++static inline int au_test_ubifs(struct super_block *sb __maybe_unused) ++{ ++#if defined(CONFIG_UBIFS_FS) || defined(CONFIG_UBIFS_FS_MODULE) ++ return sb->s_magic == UBIFS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_procfs(struct super_block *sb __maybe_unused) ++{ ++#ifdef CONFIG_PROC_FS ++ return sb->s_magic == PROC_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_sysfs(struct super_block *sb __maybe_unused) ++{ ++#ifdef CONFIG_SYSFS ++ return sb->s_magic == SYSFS_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_configfs(struct super_block *sb __maybe_unused) ++{ ++#if defined(CONFIG_CONFIGFS_FS) || defined(CONFIG_CONFIGFS_FS_MODULE) ++ return sb->s_magic == CONFIGFS_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_minix(struct super_block *sb __maybe_unused) ++{ ++#if defined(CONFIG_MINIX_FS) || defined(CONFIG_MINIX_FS_MODULE) ++ return sb->s_magic == MINIX3_SUPER_MAGIC ++ || sb->s_magic == MINIX2_SUPER_MAGIC ++ || sb->s_magic == MINIX2_SUPER_MAGIC2 ++ || sb->s_magic == MINIX_SUPER_MAGIC ++ || sb->s_magic == MINIX_SUPER_MAGIC2; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_fat(struct super_block *sb __maybe_unused) ++{ ++#if defined(CONFIG_FAT_FS) || defined(CONFIG_FAT_FS_MODULE) ++ return sb->s_magic == MSDOS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_msdos(struct super_block *sb) ++{ ++ return au_test_fat(sb); ++} ++ ++static inline int au_test_vfat(struct super_block *sb) ++{ ++ return au_test_fat(sb); ++} ++ ++static inline int au_test_securityfs(struct super_block *sb __maybe_unused) ++{ ++#ifdef CONFIG_SECURITYFS ++ return sb->s_magic == SECURITYFS_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_squashfs(struct super_block *sb __maybe_unused) ++{ ++#if defined(CONFIG_SQUASHFS) || defined(CONFIG_SQUASHFS_MODULE) ++ return sb->s_magic == SQUASHFS_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_btrfs(struct super_block *sb __maybe_unused) ++{ ++#if defined(CONFIG_BTRFS_FS) || defined(CONFIG_BTRFS_FS_MODULE) ++ return sb->s_magic == BTRFS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_xenfs(struct super_block *sb __maybe_unused) ++{ ++#if defined(CONFIG_XENFS) || defined(CONFIG_XENFS_MODULE) ++ return sb->s_magic == XENFS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_debugfs(struct super_block *sb __maybe_unused) ++{ ++#ifdef CONFIG_DEBUG_FS ++ return sb->s_magic == DEBUGFS_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_nilfs(struct super_block *sb __maybe_unused) ++{ ++#if defined(CONFIG_NILFS) || defined(CONFIG_NILFS_MODULE) ++ return sb->s_magic == NILFS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_hfsplus(struct super_block *sb __maybe_unused) ++{ ++#if defined(CONFIG_HFSPLUS_FS) || defined(CONFIG_HFSPLUS_FS_MODULE) ++ return sb->s_magic == HFSPLUS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++/* ---------------------------------------------------------------------- */ ++/* ++ * they can't be an aufs branch. ++ */ ++static inline int au_test_fs_unsuppoted(struct super_block *sb) ++{ ++ return ++#ifndef CONFIG_AUFS_BR_RAMFS ++ au_test_ramfs(sb) || ++#endif ++ au_test_procfs(sb) ++ || au_test_sysfs(sb) ++ || au_test_configfs(sb) ++ || au_test_debugfs(sb) ++ || au_test_securityfs(sb) ++ || au_test_xenfs(sb) ++ || au_test_ecryptfs(sb) ++ /* || !strcmp(au_sbtype(sb), "unionfs") */ ++ || au_test_aufs(sb); /* will be supported in next version */ ++} ++ ++static inline int au_test_fs_remote(struct super_block *sb) ++{ ++ return !au_test_tmpfs(sb) ++#ifdef CONFIG_AUFS_BR_RAMFS ++ && !au_test_ramfs(sb) ++#endif ++ && !(sb->s_type->fs_flags & FS_REQUIRES_DEV); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * Note: these functions (below) are created after reading ->getattr() in all ++ * filesystems under linux/fs. it means we have to do so in every update... ++ */ ++ ++/* ++ * some filesystems require getattr to refresh the inode attributes before ++ * referencing. ++ * in most cases, we can rely on the inode attribute in NFS (or every remote fs) ++ * and leave the work for d_revalidate() ++ */ ++static inline int au_test_fs_refresh_iattr(struct super_block *sb) ++{ ++ return au_test_nfs(sb) ++ || au_test_fuse(sb) ++ /* || au_test_btrfs(sb) */ /* untested */ ++ ; ++} ++ ++/* ++ * filesystems which don't maintain i_size or i_blocks. ++ */ ++static inline int au_test_fs_bad_iattr_size(struct super_block *sb) ++{ ++ return au_test_xfs(sb) ++ || au_test_btrfs(sb) ++ || au_test_ubifs(sb) ++ || au_test_hfsplus(sb) /* maintained, but incorrect */ ++ /* || au_test_minix(sb) */ /* untested */ ++ ; ++} ++ ++/* ++ * filesystems which don't store the correct value in some of their inode ++ * attributes. ++ */ ++static inline int au_test_fs_bad_iattr(struct super_block *sb) ++{ ++ return au_test_fs_bad_iattr_size(sb) ++ || au_test_fat(sb) ++ || au_test_msdos(sb) ++ || au_test_vfat(sb); ++} ++ ++/* they don't check i_nlink in link(2) */ ++static inline int au_test_fs_no_limit_nlink(struct super_block *sb) ++{ ++ return au_test_tmpfs(sb) ++#ifdef CONFIG_AUFS_BR_RAMFS ++ || au_test_ramfs(sb) ++#endif ++ || au_test_ubifs(sb) ++ || au_test_hfsplus(sb); ++} ++ ++/* ++ * filesystems which sets S_NOATIME and S_NOCMTIME. ++ */ ++static inline int au_test_fs_notime(struct super_block *sb) ++{ ++ return au_test_nfs(sb) ++ || au_test_fuse(sb) ++ || au_test_ubifs(sb) ++ ; ++} ++ ++/* temporary support for i#1 in cramfs */ ++static inline int au_test_fs_unique_ino(struct inode *inode) ++{ ++ if (au_test_cramfs(inode->i_sb)) ++ return inode->i_ino != 1; ++ return 1; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * the filesystem where the xino files placed must support i/o after unlink and ++ * maintain i_size and i_blocks. ++ */ ++static inline int au_test_fs_bad_xino(struct super_block *sb) ++{ ++ return au_test_fs_remote(sb) ++ || au_test_fs_bad_iattr_size(sb) ++ /* don't want unnecessary work for xino */ ++ || au_test_aufs(sb) ++ || au_test_ecryptfs(sb) ++ || au_test_nilfs(sb); ++} ++ ++static inline int au_test_fs_trunc_xino(struct super_block *sb) ++{ ++ return au_test_tmpfs(sb) ++ || au_test_ramfs(sb); ++} ++ ++/* ++ * test if the @sb is real-readonly. ++ */ ++static inline int au_test_fs_rr(struct super_block *sb) ++{ ++ return au_test_squashfs(sb) ++ || au_test_iso9660(sb) ++ || au_test_cramfs(sb) ++ || au_test_romfs(sb); ++} ++ ++/* ++ * test if the @inode is nfs with 'noacl' option ++ * NFS always sets MS_POSIXACL regardless its mount option 'noacl.' ++ */ ++static inline int au_test_nfs_noacl(struct inode *inode) ++{ ++ return au_test_nfs(inode->i_sb) ++ /* && IS_POSIXACL(inode) */ ++ && !nfs_server_capable(inode, NFS_CAP_ACLS); ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_FSTYPE_H__ */ +diff --git a/fs/aufs/hfsnotify.c b/fs/aufs/hfsnotify.c +new file mode 100644 +index 0000000..6fa79b0 +--- /dev/null ++++ b/fs/aufs/hfsnotify.c +@@ -0,0 +1,288 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * fsnotify for the lower directories ++ */ ++ ++#include "aufs.h" ++ ++/* FS_IN_IGNORED is unnecessary */ ++static const __u32 AuHfsnMask = (FS_MOVED_TO | FS_MOVED_FROM | FS_DELETE ++ | FS_CREATE | FS_EVENT_ON_CHILD); ++static DECLARE_WAIT_QUEUE_HEAD(au_hfsn_wq); ++static __cacheline_aligned_in_smp atomic64_t au_hfsn_ifree = ATOMIC64_INIT(0); ++ ++static void au_hfsn_free_mark(struct fsnotify_mark *mark) ++{ ++ struct au_hnotify *hn = container_of(mark, struct au_hnotify, ++ hn_mark); ++ AuDbg("here\n"); ++ au_cache_free_hnotify(hn); ++ smp_mb__before_atomic(); ++ if (atomic64_dec_and_test(&au_hfsn_ifree)) ++ wake_up(&au_hfsn_wq); ++} ++ ++static int au_hfsn_alloc(struct au_hinode *hinode) ++{ ++ int err; ++ struct au_hnotify *hn; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct fsnotify_mark *mark; ++ aufs_bindex_t bindex; ++ ++ hn = hinode->hi_notify; ++ sb = hn->hn_aufs_inode->i_sb; ++ bindex = au_br_index(sb, hinode->hi_id); ++ br = au_sbr(sb, bindex); ++ AuDebugOn(!br->br_hfsn); ++ ++ mark = &hn->hn_mark; ++ fsnotify_init_mark(mark, au_hfsn_free_mark); ++ mark->mask = AuHfsnMask; ++ /* ++ * by udba rename or rmdir, aufs assign a new inode to the known ++ * h_inode, so specify 1 to allow dups. ++ */ ++ lockdep_off(); ++ err = fsnotify_add_mark(mark, br->br_hfsn->hfsn_group, hinode->hi_inode, ++ /*mnt*/NULL, /*allow_dups*/1); ++ /* even if err */ ++ fsnotify_put_mark(mark); ++ lockdep_on(); ++ ++ return err; ++} ++ ++static int au_hfsn_free(struct au_hinode *hinode, struct au_hnotify *hn) ++{ ++ struct fsnotify_mark *mark; ++ unsigned long long ull; ++ struct fsnotify_group *group; ++ ++ ull = atomic64_inc_return(&au_hfsn_ifree); ++ BUG_ON(!ull); ++ ++ mark = &hn->hn_mark; ++ spin_lock(&mark->lock); ++ group = mark->group; ++ fsnotify_get_group(group); ++ spin_unlock(&mark->lock); ++ lockdep_off(); ++ fsnotify_destroy_mark(mark, group); ++ fsnotify_put_group(group); ++ lockdep_on(); ++ ++ /* free hn by myself */ ++ return 0; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_hfsn_ctl(struct au_hinode *hinode, int do_set) ++{ ++ struct fsnotify_mark *mark; ++ ++ mark = &hinode->hi_notify->hn_mark; ++ spin_lock(&mark->lock); ++ if (do_set) { ++ AuDebugOn(mark->mask & AuHfsnMask); ++ mark->mask |= AuHfsnMask; ++ } else { ++ AuDebugOn(!(mark->mask & AuHfsnMask)); ++ mark->mask &= ~AuHfsnMask; ++ } ++ spin_unlock(&mark->lock); ++ /* fsnotify_recalc_inode_mask(hinode->hi_inode); */ ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* #define AuDbgHnotify */ ++#ifdef AuDbgHnotify ++static char *au_hfsn_name(u32 mask) ++{ ++#ifdef CONFIG_AUFS_DEBUG ++#define test_ret(flag) \ ++ do { \ ++ if (mask & flag) \ ++ return #flag; \ ++ } while (0) ++ test_ret(FS_ACCESS); ++ test_ret(FS_MODIFY); ++ test_ret(FS_ATTRIB); ++ test_ret(FS_CLOSE_WRITE); ++ test_ret(FS_CLOSE_NOWRITE); ++ test_ret(FS_OPEN); ++ test_ret(FS_MOVED_FROM); ++ test_ret(FS_MOVED_TO); ++ test_ret(FS_CREATE); ++ test_ret(FS_DELETE); ++ test_ret(FS_DELETE_SELF); ++ test_ret(FS_MOVE_SELF); ++ test_ret(FS_UNMOUNT); ++ test_ret(FS_Q_OVERFLOW); ++ test_ret(FS_IN_IGNORED); ++ test_ret(FS_ISDIR); ++ test_ret(FS_IN_ONESHOT); ++ test_ret(FS_EVENT_ON_CHILD); ++ return ""; ++#undef test_ret ++#else ++ return "??"; ++#endif ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_hfsn_free_group(struct fsnotify_group *group) ++{ ++ struct au_br_hfsnotify *hfsn = group->private; ++ ++ AuDbg("here\n"); ++ kfree(hfsn); ++} ++ ++static int au_hfsn_handle_event(struct fsnotify_group *group, ++ struct inode *inode, ++ struct fsnotify_mark *inode_mark, ++ struct fsnotify_mark *vfsmount_mark, ++ u32 mask, void *data, int data_type, ++ const unsigned char *file_name, u32 cookie) ++{ ++ int err; ++ struct au_hnotify *hnotify; ++ struct inode *h_dir, *h_inode; ++ struct qstr h_child_qstr = QSTR_INIT(file_name, strlen(file_name)); ++ ++ AuDebugOn(data_type != FSNOTIFY_EVENT_INODE); ++ ++ err = 0; ++ /* if FS_UNMOUNT happens, there must be another bug */ ++ AuDebugOn(mask & FS_UNMOUNT); ++ if (mask & (FS_IN_IGNORED | FS_UNMOUNT)) ++ goto out; ++ ++ h_dir = inode; ++ h_inode = NULL; ++#ifdef AuDbgHnotify ++ au_debug_on(); ++ if (1 || h_child_qstr.len != sizeof(AUFS_XINO_FNAME) - 1 ++ || strncmp(h_child_qstr.name, AUFS_XINO_FNAME, h_child_qstr.len)) { ++ AuDbg("i%lu, mask 0x%x %s, hcname %.*s, hi%lu\n", ++ h_dir->i_ino, mask, au_hfsn_name(mask), ++ AuLNPair(&h_child_qstr), h_inode ? h_inode->i_ino : 0); ++ /* WARN_ON(1); */ ++ } ++ au_debug_off(); ++#endif ++ ++ AuDebugOn(!inode_mark); ++ hnotify = container_of(inode_mark, struct au_hnotify, hn_mark); ++ err = au_hnotify(h_dir, hnotify, mask, &h_child_qstr, h_inode); ++ ++out: ++ return err; ++} ++ ++static struct fsnotify_ops au_hfsn_ops = { ++ .handle_event = au_hfsn_handle_event, ++ .free_group_priv = au_hfsn_free_group ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_hfsn_fin_br(struct au_branch *br) ++{ ++ struct au_br_hfsnotify *hfsn; ++ ++ hfsn = br->br_hfsn; ++ if (hfsn) { ++ lockdep_off(); ++ fsnotify_put_group(hfsn->hfsn_group); ++ lockdep_on(); ++ } ++} ++ ++static int au_hfsn_init_br(struct au_branch *br, int perm) ++{ ++ int err; ++ struct fsnotify_group *group; ++ struct au_br_hfsnotify *hfsn; ++ ++ err = 0; ++ br->br_hfsn = NULL; ++ if (!au_br_hnotifyable(perm)) ++ goto out; ++ ++ err = -ENOMEM; ++ hfsn = kmalloc(sizeof(*hfsn), GFP_NOFS); ++ if (unlikely(!hfsn)) ++ goto out; ++ ++ err = 0; ++ group = fsnotify_alloc_group(&au_hfsn_ops); ++ if (IS_ERR(group)) { ++ err = PTR_ERR(group); ++ pr_err("fsnotify_alloc_group() failed, %d\n", err); ++ goto out_hfsn; ++ } ++ ++ group->private = hfsn; ++ hfsn->hfsn_group = group; ++ br->br_hfsn = hfsn; ++ goto out; /* success */ ++ ++out_hfsn: ++ kfree(hfsn); ++out: ++ return err; ++} ++ ++static int au_hfsn_reset_br(unsigned int udba, struct au_branch *br, int perm) ++{ ++ int err; ++ ++ err = 0; ++ if (!br->br_hfsn) ++ err = au_hfsn_init_br(br, perm); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_hfsn_fin(void) ++{ ++ AuDbg("au_hfsn_ifree %lld\n", (long long)atomic64_read(&au_hfsn_ifree)); ++ wait_event(au_hfsn_wq, !atomic64_read(&au_hfsn_ifree)); ++} ++ ++const struct au_hnotify_op au_hnotify_op = { ++ .ctl = au_hfsn_ctl, ++ .alloc = au_hfsn_alloc, ++ .free = au_hfsn_free, ++ ++ .fin = au_hfsn_fin, ++ ++ .reset_br = au_hfsn_reset_br, ++ .fin_br = au_hfsn_fin_br, ++ .init_br = au_hfsn_init_br ++}; +diff --git a/fs/aufs/hfsplus.c b/fs/aufs/hfsplus.c +new file mode 100644 +index 0000000..8a54c82 +--- /dev/null ++++ b/fs/aufs/hfsplus.c +@@ -0,0 +1,56 @@ ++/* ++ * Copyright (C) 2010-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * special support for filesystems which aqucires an inode mutex ++ * at final closing a file, eg, hfsplus. ++ * ++ * This trick is very simple and stupid, just to open the file before really ++ * neceeary open to tell hfsplus that this is not the final closing. ++ * The caller should call au_h_open_pre() after acquiring the inode mutex, ++ * and au_h_open_post() after releasing it. ++ */ ++ ++#include "aufs.h" ++ ++struct file *au_h_open_pre(struct dentry *dentry, aufs_bindex_t bindex, ++ int force_wr) ++{ ++ struct file *h_file; ++ struct dentry *h_dentry; ++ ++ h_dentry = au_h_dptr(dentry, bindex); ++ AuDebugOn(!h_dentry); ++ AuDebugOn(!h_dentry->d_inode); ++ ++ h_file = NULL; ++ if (au_test_hfsplus(h_dentry->d_sb) ++ && S_ISREG(h_dentry->d_inode->i_mode)) ++ h_file = au_h_open(dentry, bindex, ++ O_RDONLY | O_NOATIME | O_LARGEFILE, ++ /*file*/NULL, force_wr); ++ return h_file; ++} ++ ++void au_h_open_post(struct dentry *dentry, aufs_bindex_t bindex, ++ struct file *h_file) ++{ ++ if (h_file) { ++ fput(h_file); ++ au_sbr_put(dentry->d_sb, bindex); ++ } ++} +diff --git a/fs/aufs/hnotify.c b/fs/aufs/hnotify.c +new file mode 100644 +index 0000000..1801420 +--- /dev/null ++++ b/fs/aufs/hnotify.c +@@ -0,0 +1,714 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * abstraction to notify the direct changes on lower directories ++ */ ++ ++#include "aufs.h" ++ ++int au_hn_alloc(struct au_hinode *hinode, struct inode *inode) ++{ ++ int err; ++ struct au_hnotify *hn; ++ ++ err = -ENOMEM; ++ hn = au_cache_alloc_hnotify(); ++ if (hn) { ++ hn->hn_aufs_inode = inode; ++ hinode->hi_notify = hn; ++ err = au_hnotify_op.alloc(hinode); ++ AuTraceErr(err); ++ if (unlikely(err)) { ++ hinode->hi_notify = NULL; ++ au_cache_free_hnotify(hn); ++ /* ++ * The upper dir was removed by udba, but the same named ++ * dir left. In this case, aufs assignes a new inode ++ * number and set the monitor again. ++ * For the lower dir, the old monitnor is still left. ++ */ ++ if (err == -EEXIST) ++ err = 0; ++ } ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++void au_hn_free(struct au_hinode *hinode) ++{ ++ struct au_hnotify *hn; ++ ++ hn = hinode->hi_notify; ++ if (hn) { ++ hinode->hi_notify = NULL; ++ if (au_hnotify_op.free(hinode, hn)) ++ au_cache_free_hnotify(hn); ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_hn_ctl(struct au_hinode *hinode, int do_set) ++{ ++ if (hinode->hi_notify) ++ au_hnotify_op.ctl(hinode, do_set); ++} ++ ++void au_hn_reset(struct inode *inode, unsigned int flags) ++{ ++ aufs_bindex_t bindex, bend; ++ struct inode *hi; ++ struct dentry *iwhdentry; ++ ++ bend = au_ibend(inode); ++ for (bindex = au_ibstart(inode); bindex <= bend; bindex++) { ++ hi = au_h_iptr(inode, bindex); ++ if (!hi) ++ continue; ++ ++ /* mutex_lock_nested(&hi->i_mutex, AuLsc_I_CHILD); */ ++ iwhdentry = au_hi_wh(inode, bindex); ++ if (iwhdentry) ++ dget(iwhdentry); ++ au_igrab(hi); ++ au_set_h_iptr(inode, bindex, NULL, 0); ++ au_set_h_iptr(inode, bindex, au_igrab(hi), ++ flags & ~AuHi_XINO); ++ iput(hi); ++ dput(iwhdentry); ++ /* mutex_unlock(&hi->i_mutex); */ ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int hn_xino(struct inode *inode, struct inode *h_inode) ++{ ++ int err; ++ aufs_bindex_t bindex, bend, bfound, bstart; ++ struct inode *h_i; ++ ++ err = 0; ++ if (unlikely(inode->i_ino == AUFS_ROOT_INO)) { ++ pr_warn("branch root dir was changed\n"); ++ goto out; ++ } ++ ++ bfound = -1; ++ bend = au_ibend(inode); ++ bstart = au_ibstart(inode); ++#if 0 /* reserved for future use */ ++ if (bindex == bend) { ++ /* keep this ino in rename case */ ++ goto out; ++ } ++#endif ++ for (bindex = bstart; bindex <= bend; bindex++) ++ if (au_h_iptr(inode, bindex) == h_inode) { ++ bfound = bindex; ++ break; ++ } ++ if (bfound < 0) ++ goto out; ++ ++ for (bindex = bstart; bindex <= bend; bindex++) { ++ h_i = au_h_iptr(inode, bindex); ++ if (!h_i) ++ continue; ++ ++ err = au_xino_write(inode->i_sb, bindex, h_i->i_ino, /*ino*/0); ++ /* ignore this error */ ++ /* bad action? */ ++ } ++ ++ /* children inode number will be broken */ ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int hn_gen_tree(struct dentry *dentry) ++{ ++ int err, i, j, ndentry; ++ struct au_dcsub_pages dpages; ++ struct au_dpage *dpage; ++ struct dentry **dentries; ++ ++ err = au_dpages_init(&dpages, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ err = au_dcsub_pages(&dpages, dentry, NULL, NULL); ++ if (unlikely(err)) ++ goto out_dpages; ++ ++ for (i = 0; i < dpages.ndpage; i++) { ++ dpage = dpages.dpages + i; ++ dentries = dpage->dentries; ++ ndentry = dpage->ndentry; ++ for (j = 0; j < ndentry; j++) { ++ struct dentry *d; ++ ++ d = dentries[j]; ++ if (IS_ROOT(d)) ++ continue; ++ ++ au_digen_dec(d); ++ if (d->d_inode) ++ /* todo: reset children xino? ++ cached children only? */ ++ au_iigen_dec(d->d_inode); ++ } ++ } ++ ++out_dpages: ++ au_dpages_free(&dpages); ++ ++#if 0 ++ /* discard children */ ++ dentry_unhash(dentry); ++ dput(dentry); ++#endif ++out: ++ return err; ++} ++ ++/* ++ * return 0 if processed. ++ */ ++static int hn_gen_by_inode(char *name, unsigned int nlen, struct inode *inode, ++ const unsigned int isdir) ++{ ++ int err; ++ struct dentry *d; ++ struct qstr *dname; ++ ++ err = 1; ++ if (unlikely(inode->i_ino == AUFS_ROOT_INO)) { ++ pr_warn("branch root dir was changed\n"); ++ err = 0; ++ goto out; ++ } ++ ++ if (!isdir) { ++ AuDebugOn(!name); ++ au_iigen_dec(inode); ++ spin_lock(&inode->i_lock); ++ hlist_for_each_entry(d, &inode->i_dentry, d_u.d_alias) { ++ spin_lock(&d->d_lock); ++ dname = &d->d_name; ++ if (dname->len != nlen ++ && memcmp(dname->name, name, nlen)) { ++ spin_unlock(&d->d_lock); ++ continue; ++ } ++ err = 0; ++ au_digen_dec(d); ++ spin_unlock(&d->d_lock); ++ break; ++ } ++ spin_unlock(&inode->i_lock); ++ } else { ++ au_fset_si(au_sbi(inode->i_sb), FAILED_REFRESH_DIR); ++ d = d_find_any_alias(inode); ++ if (!d) { ++ au_iigen_dec(inode); ++ goto out; ++ } ++ ++ spin_lock(&d->d_lock); ++ dname = &d->d_name; ++ if (dname->len == nlen && !memcmp(dname->name, name, nlen)) { ++ spin_unlock(&d->d_lock); ++ err = hn_gen_tree(d); ++ spin_lock(&d->d_lock); ++ } ++ spin_unlock(&d->d_lock); ++ dput(d); ++ } ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int hn_gen_by_name(struct dentry *dentry, const unsigned int isdir) ++{ ++ int err; ++ struct inode *inode; ++ ++ inode = dentry->d_inode; ++ if (IS_ROOT(dentry) ++ /* || (inode && inode->i_ino == AUFS_ROOT_INO) */ ++ ) { ++ pr_warn("branch root dir was changed\n"); ++ return 0; ++ } ++ ++ err = 0; ++ if (!isdir) { ++ au_digen_dec(dentry); ++ if (inode) ++ au_iigen_dec(inode); ++ } else { ++ au_fset_si(au_sbi(dentry->d_sb), FAILED_REFRESH_DIR); ++ if (inode) ++ err = hn_gen_tree(dentry); ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* hnotify job flags */ ++#define AuHnJob_XINO0 1 ++#define AuHnJob_GEN (1 << 1) ++#define AuHnJob_DIRENT (1 << 2) ++#define AuHnJob_ISDIR (1 << 3) ++#define AuHnJob_TRYXINO0 (1 << 4) ++#define AuHnJob_MNTPNT (1 << 5) ++#define au_ftest_hnjob(flags, name) ((flags) & AuHnJob_##name) ++#define au_fset_hnjob(flags, name) \ ++ do { (flags) |= AuHnJob_##name; } while (0) ++#define au_fclr_hnjob(flags, name) \ ++ do { (flags) &= ~AuHnJob_##name; } while (0) ++ ++enum { ++ AuHn_CHILD, ++ AuHn_PARENT, ++ AuHnLast ++}; ++ ++struct au_hnotify_args { ++ struct inode *h_dir, *dir, *h_child_inode; ++ u32 mask; ++ unsigned int flags[AuHnLast]; ++ unsigned int h_child_nlen; ++ char h_child_name[]; ++}; ++ ++struct hn_job_args { ++ unsigned int flags; ++ struct inode *inode, *h_inode, *dir, *h_dir; ++ struct dentry *dentry; ++ char *h_name; ++ int h_nlen; ++}; ++ ++static int hn_job(struct hn_job_args *a) ++{ ++ const unsigned int isdir = au_ftest_hnjob(a->flags, ISDIR); ++ int e; ++ ++ /* reset xino */ ++ if (au_ftest_hnjob(a->flags, XINO0) && a->inode) ++ hn_xino(a->inode, a->h_inode); /* ignore this error */ ++ ++ if (au_ftest_hnjob(a->flags, TRYXINO0) ++ && a->inode ++ && a->h_inode) { ++ mutex_lock_nested(&a->h_inode->i_mutex, AuLsc_I_CHILD); ++ if (!a->h_inode->i_nlink ++ && !(a->h_inode->i_state & I_LINKABLE)) ++ hn_xino(a->inode, a->h_inode); /* ignore this error */ ++ mutex_unlock(&a->h_inode->i_mutex); ++ } ++ ++ /* make the generation obsolete */ ++ if (au_ftest_hnjob(a->flags, GEN)) { ++ e = -1; ++ if (a->inode) ++ e = hn_gen_by_inode(a->h_name, a->h_nlen, a->inode, ++ isdir); ++ if (e && a->dentry) ++ hn_gen_by_name(a->dentry, isdir); ++ /* ignore this error */ ++ } ++ ++ /* make dir entries obsolete */ ++ if (au_ftest_hnjob(a->flags, DIRENT) && a->inode) { ++ struct au_vdir *vdir; ++ ++ vdir = au_ivdir(a->inode); ++ if (vdir) ++ vdir->vd_jiffy = 0; ++ /* IMustLock(a->inode); */ ++ /* a->inode->i_version++; */ ++ } ++ ++ /* can do nothing but warn */ ++ if (au_ftest_hnjob(a->flags, MNTPNT) ++ && a->dentry ++ && d_mountpoint(a->dentry)) ++ pr_warn("mount-point %pd is removed or renamed\n", a->dentry); ++ ++ return 0; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct dentry *lookup_wlock_by_name(char *name, unsigned int nlen, ++ struct inode *dir) ++{ ++ struct dentry *dentry, *d, *parent; ++ struct qstr *dname; ++ ++ parent = d_find_any_alias(dir); ++ if (!parent) ++ return NULL; ++ ++ dentry = NULL; ++ spin_lock(&parent->d_lock); ++ list_for_each_entry(d, &parent->d_subdirs, d_child) { ++ /* AuDbg("%pd\n", d); */ ++ spin_lock_nested(&d->d_lock, DENTRY_D_LOCK_NESTED); ++ dname = &d->d_name; ++ if (dname->len != nlen || memcmp(dname->name, name, nlen)) ++ goto cont_unlock; ++ if (au_di(d)) ++ au_digen_dec(d); ++ else ++ goto cont_unlock; ++ if (au_dcount(d) > 0) { ++ dentry = dget_dlock(d); ++ spin_unlock(&d->d_lock); ++ break; ++ } ++ ++cont_unlock: ++ spin_unlock(&d->d_lock); ++ } ++ spin_unlock(&parent->d_lock); ++ dput(parent); ++ ++ if (dentry) ++ di_write_lock_child(dentry); ++ ++ return dentry; ++} ++ ++static struct inode *lookup_wlock_by_ino(struct super_block *sb, ++ aufs_bindex_t bindex, ino_t h_ino) ++{ ++ struct inode *inode; ++ ino_t ino; ++ int err; ++ ++ inode = NULL; ++ err = au_xino_read(sb, bindex, h_ino, &ino); ++ if (!err && ino) ++ inode = ilookup(sb, ino); ++ if (!inode) ++ goto out; ++ ++ if (unlikely(inode->i_ino == AUFS_ROOT_INO)) { ++ pr_warn("wrong root branch\n"); ++ iput(inode); ++ inode = NULL; ++ goto out; ++ } ++ ++ ii_write_lock_child(inode); ++ ++out: ++ return inode; ++} ++ ++static void au_hn_bh(void *_args) ++{ ++ struct au_hnotify_args *a = _args; ++ struct super_block *sb; ++ aufs_bindex_t bindex, bend, bfound; ++ unsigned char xino, try_iput; ++ int err; ++ struct inode *inode; ++ ino_t h_ino; ++ struct hn_job_args args; ++ struct dentry *dentry; ++ struct au_sbinfo *sbinfo; ++ ++ AuDebugOn(!_args); ++ AuDebugOn(!a->h_dir); ++ AuDebugOn(!a->dir); ++ AuDebugOn(!a->mask); ++ AuDbg("mask 0x%x, i%lu, hi%lu, hci%lu\n", ++ a->mask, a->dir->i_ino, a->h_dir->i_ino, ++ a->h_child_inode ? a->h_child_inode->i_ino : 0); ++ ++ inode = NULL; ++ dentry = NULL; ++ /* ++ * do not lock a->dir->i_mutex here ++ * because of d_revalidate() may cause a deadlock. ++ */ ++ sb = a->dir->i_sb; ++ AuDebugOn(!sb); ++ sbinfo = au_sbi(sb); ++ AuDebugOn(!sbinfo); ++ si_write_lock(sb, AuLock_NOPLMW); ++ ++ ii_read_lock_parent(a->dir); ++ bfound = -1; ++ bend = au_ibend(a->dir); ++ for (bindex = au_ibstart(a->dir); bindex <= bend; bindex++) ++ if (au_h_iptr(a->dir, bindex) == a->h_dir) { ++ bfound = bindex; ++ break; ++ } ++ ii_read_unlock(a->dir); ++ if (unlikely(bfound < 0)) ++ goto out; ++ ++ xino = !!au_opt_test(au_mntflags(sb), XINO); ++ h_ino = 0; ++ if (a->h_child_inode) ++ h_ino = a->h_child_inode->i_ino; ++ ++ if (a->h_child_nlen ++ && (au_ftest_hnjob(a->flags[AuHn_CHILD], GEN) ++ || au_ftest_hnjob(a->flags[AuHn_CHILD], MNTPNT))) ++ dentry = lookup_wlock_by_name(a->h_child_name, a->h_child_nlen, ++ a->dir); ++ try_iput = 0; ++ if (dentry) ++ inode = dentry->d_inode; ++ if (xino && !inode && h_ino ++ && (au_ftest_hnjob(a->flags[AuHn_CHILD], XINO0) ++ || au_ftest_hnjob(a->flags[AuHn_CHILD], TRYXINO0) ++ || au_ftest_hnjob(a->flags[AuHn_CHILD], GEN))) { ++ inode = lookup_wlock_by_ino(sb, bfound, h_ino); ++ try_iput = 1; ++ } ++ ++ args.flags = a->flags[AuHn_CHILD]; ++ args.dentry = dentry; ++ args.inode = inode; ++ args.h_inode = a->h_child_inode; ++ args.dir = a->dir; ++ args.h_dir = a->h_dir; ++ args.h_name = a->h_child_name; ++ args.h_nlen = a->h_child_nlen; ++ err = hn_job(&args); ++ if (dentry) { ++ if (au_di(dentry)) ++ di_write_unlock(dentry); ++ dput(dentry); ++ } ++ if (inode && try_iput) { ++ ii_write_unlock(inode); ++ iput(inode); ++ } ++ ++ ii_write_lock_parent(a->dir); ++ args.flags = a->flags[AuHn_PARENT]; ++ args.dentry = NULL; ++ args.inode = a->dir; ++ args.h_inode = a->h_dir; ++ args.dir = NULL; ++ args.h_dir = NULL; ++ args.h_name = NULL; ++ args.h_nlen = 0; ++ err = hn_job(&args); ++ ii_write_unlock(a->dir); ++ ++out: ++ iput(a->h_child_inode); ++ iput(a->h_dir); ++ iput(a->dir); ++ si_write_unlock(sb); ++ au_nwt_done(&sbinfo->si_nowait); ++ kfree(a); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_hnotify(struct inode *h_dir, struct au_hnotify *hnotify, u32 mask, ++ struct qstr *h_child_qstr, struct inode *h_child_inode) ++{ ++ int err, len; ++ unsigned int flags[AuHnLast], f; ++ unsigned char isdir, isroot, wh; ++ struct inode *dir; ++ struct au_hnotify_args *args; ++ char *p, *h_child_name; ++ ++ err = 0; ++ AuDebugOn(!hnotify || !hnotify->hn_aufs_inode); ++ dir = igrab(hnotify->hn_aufs_inode); ++ if (!dir) ++ goto out; ++ ++ isroot = (dir->i_ino == AUFS_ROOT_INO); ++ wh = 0; ++ h_child_name = (void *)h_child_qstr->name; ++ len = h_child_qstr->len; ++ if (h_child_name) { ++ if (len > AUFS_WH_PFX_LEN ++ && !memcmp(h_child_name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) { ++ h_child_name += AUFS_WH_PFX_LEN; ++ len -= AUFS_WH_PFX_LEN; ++ wh = 1; ++ } ++ } ++ ++ isdir = 0; ++ if (h_child_inode) ++ isdir = !!S_ISDIR(h_child_inode->i_mode); ++ flags[AuHn_PARENT] = AuHnJob_ISDIR; ++ flags[AuHn_CHILD] = 0; ++ if (isdir) ++ flags[AuHn_CHILD] = AuHnJob_ISDIR; ++ au_fset_hnjob(flags[AuHn_PARENT], DIRENT); ++ au_fset_hnjob(flags[AuHn_CHILD], GEN); ++ switch (mask & FS_EVENTS_POSS_ON_CHILD) { ++ case FS_MOVED_FROM: ++ case FS_MOVED_TO: ++ au_fset_hnjob(flags[AuHn_CHILD], XINO0); ++ au_fset_hnjob(flags[AuHn_CHILD], MNTPNT); ++ /*FALLTHROUGH*/ ++ case FS_CREATE: ++ AuDebugOn(!h_child_name); ++ break; ++ ++ case FS_DELETE: ++ /* ++ * aufs never be able to get this child inode. ++ * revalidation should be in d_revalidate() ++ * by checking i_nlink, i_generation or d_unhashed(). ++ */ ++ AuDebugOn(!h_child_name); ++ au_fset_hnjob(flags[AuHn_CHILD], TRYXINO0); ++ au_fset_hnjob(flags[AuHn_CHILD], MNTPNT); ++ break; ++ ++ default: ++ AuDebugOn(1); ++ } ++ ++ if (wh) ++ h_child_inode = NULL; ++ ++ err = -ENOMEM; ++ /* iput() and kfree() will be called in au_hnotify() */ ++ args = kmalloc(sizeof(*args) + len + 1, GFP_NOFS); ++ if (unlikely(!args)) { ++ AuErr1("no memory\n"); ++ iput(dir); ++ goto out; ++ } ++ args->flags[AuHn_PARENT] = flags[AuHn_PARENT]; ++ args->flags[AuHn_CHILD] = flags[AuHn_CHILD]; ++ args->mask = mask; ++ args->dir = dir; ++ args->h_dir = igrab(h_dir); ++ if (h_child_inode) ++ h_child_inode = igrab(h_child_inode); /* can be NULL */ ++ args->h_child_inode = h_child_inode; ++ args->h_child_nlen = len; ++ if (len) { ++ p = (void *)args; ++ p += sizeof(*args); ++ memcpy(p, h_child_name, len); ++ p[len] = 0; ++ } ++ ++ /* NFS fires the event for silly-renamed one from kworker */ ++ f = 0; ++ if (!dir->i_nlink ++ || (au_test_nfs(h_dir->i_sb) && (mask & FS_DELETE))) ++ f = AuWkq_NEST; ++ err = au_wkq_nowait(au_hn_bh, args, dir->i_sb, f); ++ if (unlikely(err)) { ++ pr_err("wkq %d\n", err); ++ iput(args->h_child_inode); ++ iput(args->h_dir); ++ iput(args->dir); ++ kfree(args); ++ } ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_hnotify_reset_br(unsigned int udba, struct au_branch *br, int perm) ++{ ++ int err; ++ ++ AuDebugOn(!(udba & AuOptMask_UDBA)); ++ ++ err = 0; ++ if (au_hnotify_op.reset_br) ++ err = au_hnotify_op.reset_br(udba, br, perm); ++ ++ return err; ++} ++ ++int au_hnotify_init_br(struct au_branch *br, int perm) ++{ ++ int err; ++ ++ err = 0; ++ if (au_hnotify_op.init_br) ++ err = au_hnotify_op.init_br(br, perm); ++ ++ return err; ++} ++ ++void au_hnotify_fin_br(struct au_branch *br) ++{ ++ if (au_hnotify_op.fin_br) ++ au_hnotify_op.fin_br(br); ++} ++ ++static void au_hn_destroy_cache(void) ++{ ++ kmem_cache_destroy(au_cachep[AuCache_HNOTIFY]); ++ au_cachep[AuCache_HNOTIFY] = NULL; ++} ++ ++int __init au_hnotify_init(void) ++{ ++ int err; ++ ++ err = -ENOMEM; ++ au_cachep[AuCache_HNOTIFY] = AuCache(au_hnotify); ++ if (au_cachep[AuCache_HNOTIFY]) { ++ err = 0; ++ if (au_hnotify_op.init) ++ err = au_hnotify_op.init(); ++ if (unlikely(err)) ++ au_hn_destroy_cache(); ++ } ++ AuTraceErr(err); ++ return err; ++} ++ ++void au_hnotify_fin(void) ++{ ++ if (au_hnotify_op.fin) ++ au_hnotify_op.fin(); ++ /* cf. au_cache_fin() */ ++ if (au_cachep[AuCache_HNOTIFY]) ++ au_hn_destroy_cache(); ++} +diff --git a/fs/aufs/i_op.c b/fs/aufs/i_op.c +new file mode 100644 +index 0000000..02dc95a +--- /dev/null ++++ b/fs/aufs/i_op.c +@@ -0,0 +1,1460 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * inode operations (except add/del/rename) ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include "aufs.h" ++ ++static int h_permission(struct inode *h_inode, int mask, ++ struct vfsmount *h_mnt, int brperm) ++{ ++ int err; ++ const unsigned char write_mask = !!(mask & (MAY_WRITE | MAY_APPEND)); ++ ++ err = -EACCES; ++ if ((write_mask && IS_IMMUTABLE(h_inode)) ++ || ((mask & MAY_EXEC) ++ && S_ISREG(h_inode->i_mode) ++ && ((h_mnt->mnt_flags & MNT_NOEXEC) ++ || !(h_inode->i_mode & S_IXUGO)))) ++ goto out; ++ ++ /* ++ * - skip the lower fs test in the case of write to ro branch. ++ * - nfs dir permission write check is optimized, but a policy for ++ * link/rename requires a real check. ++ * - nfs always sets MS_POSIXACL regardless its mount option 'noacl.' ++ * in this case, generic_permission() returns -EOPNOTSUPP. ++ */ ++ if ((write_mask && !au_br_writable(brperm)) ++ || (au_test_nfs(h_inode->i_sb) && S_ISDIR(h_inode->i_mode) ++ && write_mask && !(mask & MAY_READ)) ++ || !h_inode->i_op->permission) { ++ /* AuLabel(generic_permission); */ ++ /* AuDbg("get_acl %pf\n", h_inode->i_op->get_acl); */ ++ err = generic_permission(h_inode, mask); ++ if (err == -EOPNOTSUPP && au_test_nfs_noacl(h_inode)) ++ err = h_inode->i_op->permission(h_inode, mask); ++ AuTraceErr(err); ++ } else { ++ /* AuLabel(h_inode->permission); */ ++ err = h_inode->i_op->permission(h_inode, mask); ++ AuTraceErr(err); ++ } ++ ++ if (!err) ++ err = devcgroup_inode_permission(h_inode, mask); ++ if (!err) ++ err = security_inode_permission(h_inode, mask); ++ ++#if 0 ++ if (!err) { ++ /* todo: do we need to call ima_path_check()? */ ++ struct path h_path = { ++ .dentry = ++ .mnt = h_mnt ++ }; ++ err = ima_path_check(&h_path, ++ mask & (MAY_READ | MAY_WRITE | MAY_EXEC), ++ IMA_COUNT_LEAVE); ++ } ++#endif ++ ++out: ++ return err; ++} ++ ++static int aufs_permission(struct inode *inode, int mask) ++{ ++ int err; ++ aufs_bindex_t bindex, bend; ++ const unsigned char isdir = !!S_ISDIR(inode->i_mode), ++ write_mask = !!(mask & (MAY_WRITE | MAY_APPEND)); ++ struct inode *h_inode; ++ struct super_block *sb; ++ struct au_branch *br; ++ ++ /* todo: support rcu-walk? */ ++ if (mask & MAY_NOT_BLOCK) ++ return -ECHILD; ++ ++ sb = inode->i_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ ii_read_lock_child(inode); ++#if 0 ++ err = au_iigen_test(inode, au_sigen(sb)); ++ if (unlikely(err)) ++ goto out; ++#endif ++ ++ if (!isdir ++ || write_mask ++ || au_opt_test(au_mntflags(sb), DIRPERM1)) { ++ err = au_busy_or_stale(); ++ h_inode = au_h_iptr(inode, au_ibstart(inode)); ++ if (unlikely(!h_inode ++ || (h_inode->i_mode & S_IFMT) ++ != (inode->i_mode & S_IFMT))) ++ goto out; ++ ++ err = 0; ++ bindex = au_ibstart(inode); ++ br = au_sbr(sb, bindex); ++ err = h_permission(h_inode, mask, au_br_mnt(br), br->br_perm); ++ if (write_mask ++ && !err ++ && !special_file(h_inode->i_mode)) { ++ /* test whether the upper writable branch exists */ ++ err = -EROFS; ++ for (; bindex >= 0; bindex--) ++ if (!au_br_rdonly(au_sbr(sb, bindex))) { ++ err = 0; ++ break; ++ } ++ } ++ goto out; ++ } ++ ++ /* non-write to dir */ ++ err = 0; ++ bend = au_ibend(inode); ++ for (bindex = au_ibstart(inode); !err && bindex <= bend; bindex++) { ++ h_inode = au_h_iptr(inode, bindex); ++ if (h_inode) { ++ err = au_busy_or_stale(); ++ if (unlikely(!S_ISDIR(h_inode->i_mode))) ++ break; ++ ++ br = au_sbr(sb, bindex); ++ err = h_permission(h_inode, mask, au_br_mnt(br), ++ br->br_perm); ++ } ++ } ++ ++out: ++ ii_read_unlock(inode); ++ si_read_unlock(sb); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct dentry *aufs_lookup(struct inode *dir, struct dentry *dentry, ++ unsigned int flags) ++{ ++ struct dentry *ret, *parent; ++ struct inode *inode; ++ struct super_block *sb; ++ int err, npositive; ++ ++ IMustLock(dir); ++ ++ /* todo: support rcu-walk? */ ++ ret = ERR_PTR(-ECHILD); ++ if (flags & LOOKUP_RCU) ++ goto out; ++ ++ ret = ERR_PTR(-ENAMETOOLONG); ++ if (unlikely(dentry->d_name.len > AUFS_MAX_NAMELEN)) ++ goto out; ++ ++ sb = dir->i_sb; ++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ ret = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out; ++ ++ err = au_di_init(dentry); ++ ret = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out_si; ++ ++ inode = NULL; ++ npositive = 0; /* suppress a warning */ ++ parent = dentry->d_parent; /* dir inode is locked */ ++ di_read_lock_parent(parent, AuLock_IR); ++ err = au_alive_dir(parent); ++ if (!err) ++ err = au_digen_test(parent, au_sigen(sb)); ++ if (!err) { ++ npositive = au_lkup_dentry(dentry, au_dbstart(parent), ++ /*type*/0); ++ err = npositive; ++ } ++ di_read_unlock(parent, AuLock_IR); ++ ret = ERR_PTR(err); ++ if (unlikely(err < 0)) ++ goto out_unlock; ++ ++ if (npositive) { ++ inode = au_new_inode(dentry, /*must_new*/0); ++ if (IS_ERR(inode)) { ++ ret = (void *)inode; ++ inode = NULL; ++ goto out_unlock; ++ } ++ } ++ ++ if (inode) ++ atomic_inc(&inode->i_count); ++ ret = d_splice_alias(inode, dentry); ++ if (IS_ERR(ret) ++ && PTR_ERR(ret) == -EIO ++ && inode ++ && S_ISDIR(inode->i_mode)) { ++ atomic_inc(&inode->i_count); ++ ret = d_materialise_unique(dentry, inode); ++ if (!IS_ERR(ret)) ++ ii_write_unlock(inode); ++ } ++#if 0 ++ if (unlikely(d_need_lookup(dentry))) { ++ spin_lock(&dentry->d_lock); ++ dentry->d_flags &= ~DCACHE_NEED_LOOKUP; ++ spin_unlock(&dentry->d_lock); ++ } else ++#endif ++ if (inode) { ++ if (!IS_ERR(ret)) ++ iput(inode); ++ else { ++ ii_write_unlock(inode); ++ iput(inode); ++ inode = NULL; ++ } ++ } ++ ++out_unlock: ++ di_write_unlock(dentry); ++ if (inode) { ++ /* verbose coding for lock class name */ ++ if (unlikely(S_ISLNK(inode->i_mode))) ++ au_rw_class(&au_di(dentry)->di_rwsem, ++ au_lc_key + AuLcSymlink_DIINFO); ++ else if (unlikely(S_ISDIR(inode->i_mode))) ++ au_rw_class(&au_di(dentry)->di_rwsem, ++ au_lc_key + AuLcDir_DIINFO); ++ else /* likely */ ++ au_rw_class(&au_di(dentry)->di_rwsem, ++ au_lc_key + AuLcNonDir_DIINFO); ++ } ++out_si: ++ si_read_unlock(sb); ++out: ++ return ret; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct aopen_node { ++ struct hlist_node hlist; ++ struct file *file, *h_file; ++}; ++ ++static int au_do_aopen(struct inode *inode, struct file *file) ++{ ++ struct au_sphlhead *aopen; ++ struct aopen_node *node; ++ struct au_do_open_args args = { ++ .no_lock = 1, ++ .open = au_do_open_nondir ++ }; ++ ++ aopen = &au_sbi(inode->i_sb)->si_aopen; ++ spin_lock(&aopen->spin); ++ hlist_for_each_entry(node, &aopen->head, hlist) ++ if (node->file == file) { ++ args.h_file = node->h_file; ++ break; ++ } ++ spin_unlock(&aopen->spin); ++ /* AuDebugOn(!args.h_file); */ ++ ++ return au_do_open(file, &args); ++} ++ ++static int aufs_atomic_open(struct inode *dir, struct dentry *dentry, ++ struct file *file, unsigned int open_flag, ++ umode_t create_mode, int *opened) ++{ ++ int err, h_opened = *opened; ++ struct dentry *parent; ++ struct dentry *d; ++ struct au_sphlhead *aopen; ++ struct vfsub_aopen_args args = { ++ .open_flag = open_flag, ++ .create_mode = create_mode, ++ .opened = &h_opened ++ }; ++ struct aopen_node aopen_node = { ++ .file = file ++ }; ++ ++ IMustLock(dir); ++ AuDbg("open_flag 0x%x\n", open_flag); ++ AuDbgDentry(dentry); ++ ++ err = 0; ++ if (!au_di(dentry)) { ++ d = aufs_lookup(dir, dentry, /*flags*/0); ++ if (IS_ERR(d)) { ++ err = PTR_ERR(d); ++ goto out; ++ } else if (d) { ++ /* ++ * obsoleted dentry found. ++ * another error will be returned later. ++ */ ++ d_drop(d); ++ dput(d); ++ AuDbgDentry(d); ++ } ++ AuDbgDentry(dentry); ++ } ++ ++ if (d_is_positive(dentry) ++ || d_unhashed(dentry) ++ || d_unlinked(dentry) ++ || !(open_flag & O_CREAT)) ++ goto out_no_open; ++ ++ err = aufs_read_lock(dentry, AuLock_DW | AuLock_FLUSH | AuLock_GEN); ++ if (unlikely(err)) ++ goto out; ++ ++ parent = dentry->d_parent; /* dir is locked */ ++ di_write_lock_parent(parent); ++ err = au_lkup_dentry(dentry, /*bstart*/0, /*type*/0); ++ if (unlikely(err)) ++ goto out_unlock; ++ ++ AuDbgDentry(dentry); ++ if (d_is_positive(dentry)) ++ goto out_unlock; ++ ++ args.file = get_empty_filp(); ++ err = PTR_ERR(args.file); ++ if (IS_ERR(args.file)) ++ goto out_unlock; ++ ++ args.file->f_flags = file->f_flags; ++ err = au_aopen_or_create(dir, dentry, &args); ++ AuTraceErr(err); ++ AuDbgFile(args.file); ++ if (unlikely(err < 0)) { ++ if (h_opened & FILE_OPENED) ++ fput(args.file); ++ else ++ put_filp(args.file); ++ goto out_unlock; ++ } ++ ++ /* some filesystems don't set FILE_CREATED while succeeded? */ ++ *opened |= FILE_CREATED; ++ if (h_opened & FILE_OPENED) ++ aopen_node.h_file = args.file; ++ else { ++ put_filp(args.file); ++ args.file = NULL; ++ } ++ aopen = &au_sbi(dir->i_sb)->si_aopen; ++ au_sphl_add(&aopen_node.hlist, aopen); ++ err = finish_open(file, dentry, au_do_aopen, opened); ++ au_sphl_del(&aopen_node.hlist, aopen); ++ AuTraceErr(err); ++ AuDbgFile(file); ++ if (aopen_node.h_file) ++ fput(aopen_node.h_file); ++ ++out_unlock: ++ di_write_unlock(parent); ++ aufs_read_unlock(dentry, AuLock_DW); ++ AuDbgDentry(dentry); ++ if (unlikely(err)) ++ goto out; ++out_no_open: ++ if (!err && !(*opened & FILE_CREATED)) { ++ AuLabel(out_no_open); ++ dget(dentry); ++ err = finish_no_open(file, dentry); ++ } ++out: ++ AuDbg("%pd%s%s\n", dentry, ++ (*opened & FILE_CREATED) ? " created" : "", ++ (*opened & FILE_OPENED) ? " opened" : ""); ++ AuTraceErr(err); ++ return err; ++} ++ ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_wr_dir_cpup(struct dentry *dentry, struct dentry *parent, ++ const unsigned char add_entry, aufs_bindex_t bcpup, ++ aufs_bindex_t bstart) ++{ ++ int err; ++ struct dentry *h_parent; ++ struct inode *h_dir; ++ ++ if (add_entry) ++ IMustLock(parent->d_inode); ++ else ++ di_write_lock_parent(parent); ++ ++ err = 0; ++ if (!au_h_dptr(parent, bcpup)) { ++ if (bstart > bcpup) ++ err = au_cpup_dirs(dentry, bcpup); ++ else if (bstart < bcpup) ++ err = au_cpdown_dirs(dentry, bcpup); ++ else ++ BUG(); ++ } ++ if (!err && add_entry && !au_ftest_wrdir(add_entry, TMPFILE)) { ++ h_parent = au_h_dptr(parent, bcpup); ++ h_dir = h_parent->d_inode; ++ mutex_lock_nested(&h_dir->i_mutex, AuLsc_I_PARENT); ++ err = au_lkup_neg(dentry, bcpup, /*wh*/0); ++ /* todo: no unlock here */ ++ mutex_unlock(&h_dir->i_mutex); ++ ++ AuDbg("bcpup %d\n", bcpup); ++ if (!err) { ++ if (!dentry->d_inode) ++ au_set_h_dptr(dentry, bstart, NULL); ++ au_update_dbrange(dentry, /*do_put_zero*/0); ++ } ++ } ++ ++ if (!add_entry) ++ di_write_unlock(parent); ++ if (!err) ++ err = bcpup; /* success */ ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ++ * decide the branch and the parent dir where we will create a new entry. ++ * returns new bindex or an error. ++ * copyup the parent dir if needed. ++ */ ++int au_wr_dir(struct dentry *dentry, struct dentry *src_dentry, ++ struct au_wr_dir_args *args) ++{ ++ int err; ++ unsigned int flags; ++ aufs_bindex_t bcpup, bstart, src_bstart; ++ const unsigned char add_entry ++ = au_ftest_wrdir(args->flags, ADD_ENTRY) ++ | au_ftest_wrdir(args->flags, TMPFILE); ++ struct super_block *sb; ++ struct dentry *parent; ++ struct au_sbinfo *sbinfo; ++ ++ sb = dentry->d_sb; ++ sbinfo = au_sbi(sb); ++ parent = dget_parent(dentry); ++ bstart = au_dbstart(dentry); ++ bcpup = bstart; ++ if (args->force_btgt < 0) { ++ if (src_dentry) { ++ src_bstart = au_dbstart(src_dentry); ++ if (src_bstart < bstart) ++ bcpup = src_bstart; ++ } else if (add_entry) { ++ flags = 0; ++ if (au_ftest_wrdir(args->flags, ISDIR)) ++ au_fset_wbr(flags, DIR); ++ err = AuWbrCreate(sbinfo, dentry, flags); ++ bcpup = err; ++ } ++ ++ if (bcpup < 0 || au_test_ro(sb, bcpup, dentry->d_inode)) { ++ if (add_entry) ++ err = AuWbrCopyup(sbinfo, dentry); ++ else { ++ if (!IS_ROOT(dentry)) { ++ di_read_lock_parent(parent, !AuLock_IR); ++ err = AuWbrCopyup(sbinfo, dentry); ++ di_read_unlock(parent, !AuLock_IR); ++ } else ++ err = AuWbrCopyup(sbinfo, dentry); ++ } ++ bcpup = err; ++ if (unlikely(err < 0)) ++ goto out; ++ } ++ } else { ++ bcpup = args->force_btgt; ++ AuDebugOn(au_test_ro(sb, bcpup, dentry->d_inode)); ++ } ++ ++ AuDbg("bstart %d, bcpup %d\n", bstart, bcpup); ++ err = bcpup; ++ if (bcpup == bstart) ++ goto out; /* success */ ++ ++ /* copyup the new parent into the branch we process */ ++ err = au_wr_dir_cpup(dentry, parent, add_entry, bcpup, bstart); ++ if (err >= 0) { ++ if (!dentry->d_inode) { ++ au_set_h_dptr(dentry, bstart, NULL); ++ au_set_dbstart(dentry, bcpup); ++ au_set_dbend(dentry, bcpup); ++ } ++ AuDebugOn(add_entry ++ && !au_ftest_wrdir(args->flags, TMPFILE) ++ && !au_h_dptr(dentry, bcpup)); ++ } ++ ++out: ++ dput(parent); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_pin_hdir_unlock(struct au_pin *p) ++{ ++ if (p->hdir) ++ au_hn_imtx_unlock(p->hdir); ++} ++ ++int au_pin_hdir_lock(struct au_pin *p) ++{ ++ int err; ++ ++ err = 0; ++ if (!p->hdir) ++ goto out; ++ ++ /* even if an error happens later, keep this lock */ ++ au_hn_imtx_lock_nested(p->hdir, p->lsc_hi); ++ ++ err = -EBUSY; ++ if (unlikely(p->hdir->hi_inode != p->h_parent->d_inode)) ++ goto out; ++ ++ err = 0; ++ if (p->h_dentry) ++ err = au_h_verify(p->h_dentry, p->udba, p->hdir->hi_inode, ++ p->h_parent, p->br); ++ ++out: ++ return err; ++} ++ ++int au_pin_hdir_relock(struct au_pin *p) ++{ ++ int err, i; ++ struct inode *h_i; ++ struct dentry *h_d[] = { ++ p->h_dentry, ++ p->h_parent ++ }; ++ ++ err = au_pin_hdir_lock(p); ++ if (unlikely(err)) ++ goto out; ++ ++ for (i = 0; !err && i < sizeof(h_d)/sizeof(*h_d); i++) { ++ if (!h_d[i]) ++ continue; ++ h_i = h_d[i]->d_inode; ++ if (h_i) ++ err = !h_i->i_nlink; ++ } ++ ++out: ++ return err; ++} ++ ++void au_pin_hdir_set_owner(struct au_pin *p, struct task_struct *task) ++{ ++#if defined(CONFIG_DEBUG_MUTEXES) || defined(CONFIG_SMP) ++ p->hdir->hi_inode->i_mutex.owner = task; ++#endif ++} ++ ++void au_pin_hdir_acquire_nest(struct au_pin *p) ++{ ++ if (p->hdir) { ++ mutex_acquire_nest(&p->hdir->hi_inode->i_mutex.dep_map, ++ p->lsc_hi, 0, NULL, _RET_IP_); ++ au_pin_hdir_set_owner(p, current); ++ } ++} ++ ++void au_pin_hdir_release(struct au_pin *p) ++{ ++ if (p->hdir) { ++ au_pin_hdir_set_owner(p, p->task); ++ mutex_release(&p->hdir->hi_inode->i_mutex.dep_map, 1, _RET_IP_); ++ } ++} ++ ++struct dentry *au_pinned_h_parent(struct au_pin *pin) ++{ ++ if (pin && pin->parent) ++ return au_h_dptr(pin->parent, pin->bindex); ++ return NULL; ++} ++ ++void au_unpin(struct au_pin *p) ++{ ++ if (p->hdir) ++ au_pin_hdir_unlock(p); ++ if (p->h_mnt && au_ftest_pin(p->flags, MNT_WRITE)) ++ vfsub_mnt_drop_write(p->h_mnt); ++ if (!p->hdir) ++ return; ++ ++ if (!au_ftest_pin(p->flags, DI_LOCKED)) ++ di_read_unlock(p->parent, AuLock_IR); ++ iput(p->hdir->hi_inode); ++ dput(p->parent); ++ p->parent = NULL; ++ p->hdir = NULL; ++ p->h_mnt = NULL; ++ /* do not clear p->task */ ++} ++ ++int au_do_pin(struct au_pin *p) ++{ ++ int err; ++ struct super_block *sb; ++ struct inode *h_dir; ++ ++ err = 0; ++ sb = p->dentry->d_sb; ++ p->br = au_sbr(sb, p->bindex); ++ if (IS_ROOT(p->dentry)) { ++ if (au_ftest_pin(p->flags, MNT_WRITE)) { ++ p->h_mnt = au_br_mnt(p->br); ++ err = vfsub_mnt_want_write(p->h_mnt); ++ if (unlikely(err)) { ++ au_fclr_pin(p->flags, MNT_WRITE); ++ goto out_err; ++ } ++ } ++ goto out; ++ } ++ ++ p->h_dentry = NULL; ++ if (p->bindex <= au_dbend(p->dentry)) ++ p->h_dentry = au_h_dptr(p->dentry, p->bindex); ++ ++ p->parent = dget_parent(p->dentry); ++ if (!au_ftest_pin(p->flags, DI_LOCKED)) ++ di_read_lock(p->parent, AuLock_IR, p->lsc_di); ++ ++ h_dir = NULL; ++ p->h_parent = au_h_dptr(p->parent, p->bindex); ++ p->hdir = au_hi(p->parent->d_inode, p->bindex); ++ if (p->hdir) ++ h_dir = p->hdir->hi_inode; ++ ++ /* ++ * udba case, or ++ * if DI_LOCKED is not set, then p->parent may be different ++ * and h_parent can be NULL. ++ */ ++ if (unlikely(!p->hdir || !h_dir || !p->h_parent)) { ++ err = -EBUSY; ++ if (!au_ftest_pin(p->flags, DI_LOCKED)) ++ di_read_unlock(p->parent, AuLock_IR); ++ dput(p->parent); ++ p->parent = NULL; ++ goto out_err; ++ } ++ ++ if (au_ftest_pin(p->flags, MNT_WRITE)) { ++ p->h_mnt = au_br_mnt(p->br); ++ err = vfsub_mnt_want_write(p->h_mnt); ++ if (unlikely(err)) { ++ au_fclr_pin(p->flags, MNT_WRITE); ++ if (!au_ftest_pin(p->flags, DI_LOCKED)) ++ di_read_unlock(p->parent, AuLock_IR); ++ dput(p->parent); ++ p->parent = NULL; ++ goto out_err; ++ } ++ } ++ ++ au_igrab(h_dir); ++ err = au_pin_hdir_lock(p); ++ if (!err) ++ goto out; /* success */ ++ ++ au_unpin(p); ++ ++out_err: ++ pr_err("err %d\n", err); ++ err = au_busy_or_stale(); ++out: ++ return err; ++} ++ ++void au_pin_init(struct au_pin *p, struct dentry *dentry, ++ aufs_bindex_t bindex, int lsc_di, int lsc_hi, ++ unsigned int udba, unsigned char flags) ++{ ++ p->dentry = dentry; ++ p->udba = udba; ++ p->lsc_di = lsc_di; ++ p->lsc_hi = lsc_hi; ++ p->flags = flags; ++ p->bindex = bindex; ++ ++ p->parent = NULL; ++ p->hdir = NULL; ++ p->h_mnt = NULL; ++ ++ p->h_dentry = NULL; ++ p->h_parent = NULL; ++ p->br = NULL; ++ p->task = current; ++} ++ ++int au_pin(struct au_pin *pin, struct dentry *dentry, aufs_bindex_t bindex, ++ unsigned int udba, unsigned char flags) ++{ ++ au_pin_init(pin, dentry, bindex, AuLsc_DI_PARENT, AuLsc_I_PARENT2, ++ udba, flags); ++ return au_do_pin(pin); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * ->setattr() and ->getattr() are called in various cases. ++ * chmod, stat: dentry is revalidated. ++ * fchmod, fstat: file and dentry are not revalidated, additionally they may be ++ * unhashed. ++ * for ->setattr(), ia->ia_file is passed from ftruncate only. ++ */ ++/* todo: consolidate with do_refresh() and simple_reval_dpath() */ ++int au_reval_for_attr(struct dentry *dentry, unsigned int sigen) ++{ ++ int err; ++ struct inode *inode; ++ struct dentry *parent; ++ ++ err = 0; ++ inode = dentry->d_inode; ++ if (au_digen_test(dentry, sigen)) { ++ parent = dget_parent(dentry); ++ di_read_lock_parent(parent, AuLock_IR); ++ err = au_refresh_dentry(dentry, parent); ++ di_read_unlock(parent, AuLock_IR); ++ dput(parent); ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_pin_and_icpup(struct dentry *dentry, struct iattr *ia, ++ struct au_icpup_args *a) ++{ ++ int err; ++ loff_t sz; ++ aufs_bindex_t bstart, ibstart; ++ struct dentry *hi_wh, *parent; ++ struct inode *inode; ++ struct au_wr_dir_args wr_dir_args = { ++ .force_btgt = -1, ++ .flags = 0 ++ }; ++ ++ if (d_is_dir(dentry)) ++ au_fset_wrdir(wr_dir_args.flags, ISDIR); ++ /* plink or hi_wh() case */ ++ bstart = au_dbstart(dentry); ++ inode = dentry->d_inode; ++ ibstart = au_ibstart(inode); ++ if (bstart != ibstart && !au_test_ro(inode->i_sb, ibstart, inode)) ++ wr_dir_args.force_btgt = ibstart; ++ err = au_wr_dir(dentry, /*src_dentry*/NULL, &wr_dir_args); ++ if (unlikely(err < 0)) ++ goto out; ++ a->btgt = err; ++ if (err != bstart) ++ au_fset_icpup(a->flags, DID_CPUP); ++ ++ err = 0; ++ a->pin_flags = AuPin_MNT_WRITE; ++ parent = NULL; ++ if (!IS_ROOT(dentry)) { ++ au_fset_pin(a->pin_flags, DI_LOCKED); ++ parent = dget_parent(dentry); ++ di_write_lock_parent(parent); ++ } ++ ++ err = au_pin(&a->pin, dentry, a->btgt, a->udba, a->pin_flags); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ a->h_path.dentry = au_h_dptr(dentry, bstart); ++ a->h_inode = a->h_path.dentry->d_inode; ++ sz = -1; ++ if (ia && (ia->ia_valid & ATTR_SIZE)) { ++ mutex_lock_nested(&a->h_inode->i_mutex, AuLsc_I_CHILD); ++ if (ia->ia_size < i_size_read(a->h_inode)) ++ sz = ia->ia_size; ++ mutex_unlock(&a->h_inode->i_mutex); ++ } ++ ++ hi_wh = NULL; ++ if (au_ftest_icpup(a->flags, DID_CPUP) && d_unlinked(dentry)) { ++ hi_wh = au_hi_wh(inode, a->btgt); ++ if (!hi_wh) { ++ struct au_cp_generic cpg = { ++ .dentry = dentry, ++ .bdst = a->btgt, ++ .bsrc = -1, ++ .len = sz, ++ .pin = &a->pin ++ }; ++ err = au_sio_cpup_wh(&cpg, /*file*/NULL); ++ if (unlikely(err)) ++ goto out_unlock; ++ hi_wh = au_hi_wh(inode, a->btgt); ++ /* todo: revalidate hi_wh? */ ++ } ++ } ++ ++ if (parent) { ++ au_pin_set_parent_lflag(&a->pin, /*lflag*/0); ++ di_downgrade_lock(parent, AuLock_IR); ++ dput(parent); ++ parent = NULL; ++ } ++ if (!au_ftest_icpup(a->flags, DID_CPUP)) ++ goto out; /* success */ ++ ++ if (!d_unhashed(dentry)) { ++ struct au_cp_generic cpg = { ++ .dentry = dentry, ++ .bdst = a->btgt, ++ .bsrc = bstart, ++ .len = sz, ++ .pin = &a->pin, ++ .flags = AuCpup_DTIME | AuCpup_HOPEN ++ }; ++ err = au_sio_cpup_simple(&cpg); ++ if (!err) ++ a->h_path.dentry = au_h_dptr(dentry, a->btgt); ++ } else if (!hi_wh) ++ a->h_path.dentry = au_h_dptr(dentry, a->btgt); ++ else ++ a->h_path.dentry = hi_wh; /* do not dget here */ ++ ++out_unlock: ++ a->h_inode = a->h_path.dentry->d_inode; ++ if (!err) ++ goto out; /* success */ ++ au_unpin(&a->pin); ++out_parent: ++ if (parent) { ++ di_write_unlock(parent); ++ dput(parent); ++ } ++out: ++ if (!err) ++ mutex_lock_nested(&a->h_inode->i_mutex, AuLsc_I_CHILD); ++ return err; ++} ++ ++static int aufs_setattr(struct dentry *dentry, struct iattr *ia) ++{ ++ int err; ++ struct inode *inode, *delegated; ++ struct super_block *sb; ++ struct file *file; ++ struct au_icpup_args *a; ++ ++ inode = dentry->d_inode; ++ IMustLock(inode); ++ ++ err = -ENOMEM; ++ a = kzalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ if (ia->ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID)) ++ ia->ia_valid &= ~ATTR_MODE; ++ ++ file = NULL; ++ sb = dentry->d_sb; ++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (unlikely(err)) ++ goto out_kfree; ++ ++ if (ia->ia_valid & ATTR_FILE) { ++ /* currently ftruncate(2) only */ ++ AuDebugOn(!S_ISREG(inode->i_mode)); ++ file = ia->ia_file; ++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1); ++ if (unlikely(err)) ++ goto out_si; ++ ia->ia_file = au_hf_top(file); ++ a->udba = AuOpt_UDBA_NONE; ++ } else { ++ /* fchmod() doesn't pass ia_file */ ++ a->udba = au_opt_udba(sb); ++ di_write_lock_child(dentry); ++ /* no d_unlinked(), to set UDBA_NONE for root */ ++ if (d_unhashed(dentry)) ++ a->udba = AuOpt_UDBA_NONE; ++ if (a->udba != AuOpt_UDBA_NONE) { ++ AuDebugOn(IS_ROOT(dentry)); ++ err = au_reval_for_attr(dentry, au_sigen(sb)); ++ if (unlikely(err)) ++ goto out_dentry; ++ } ++ } ++ ++ err = au_pin_and_icpup(dentry, ia, a); ++ if (unlikely(err < 0)) ++ goto out_dentry; ++ if (au_ftest_icpup(a->flags, DID_CPUP)) { ++ ia->ia_file = NULL; ++ ia->ia_valid &= ~ATTR_FILE; ++ } ++ ++ a->h_path.mnt = au_sbr_mnt(sb, a->btgt); ++ if ((ia->ia_valid & (ATTR_MODE | ATTR_CTIME)) ++ == (ATTR_MODE | ATTR_CTIME)) { ++ err = security_path_chmod(&a->h_path, ia->ia_mode); ++ if (unlikely(err)) ++ goto out_unlock; ++ } else if ((ia->ia_valid & (ATTR_UID | ATTR_GID)) ++ && (ia->ia_valid & ATTR_CTIME)) { ++ err = security_path_chown(&a->h_path, ia->ia_uid, ia->ia_gid); ++ if (unlikely(err)) ++ goto out_unlock; ++ } ++ ++ if (ia->ia_valid & ATTR_SIZE) { ++ struct file *f; ++ ++ if (ia->ia_size < i_size_read(inode)) ++ /* unmap only */ ++ truncate_setsize(inode, ia->ia_size); ++ ++ f = NULL; ++ if (ia->ia_valid & ATTR_FILE) ++ f = ia->ia_file; ++ mutex_unlock(&a->h_inode->i_mutex); ++ err = vfsub_trunc(&a->h_path, ia->ia_size, ia->ia_valid, f); ++ mutex_lock_nested(&a->h_inode->i_mutex, AuLsc_I_CHILD); ++ } else { ++ delegated = NULL; ++ while (1) { ++ err = vfsub_notify_change(&a->h_path, ia, &delegated); ++ if (delegated) { ++ err = break_deleg_wait(&delegated); ++ if (!err) ++ continue; ++ } ++ break; ++ } ++ } ++ /* ++ * regardless aufs 'acl' option setting. ++ * why don't all acl-aware fs call this func from their ->setattr()? ++ */ ++ if (!err && (ia->ia_valid & ATTR_MODE)) ++ err = vfsub_acl_chmod(a->h_inode, ia->ia_mode); ++ if (!err) ++ au_cpup_attr_changeable(inode); ++ ++out_unlock: ++ mutex_unlock(&a->h_inode->i_mutex); ++ au_unpin(&a->pin); ++ if (unlikely(err)) ++ au_update_dbstart(dentry); ++out_dentry: ++ di_write_unlock(dentry); ++ if (file) { ++ fi_write_unlock(file); ++ ia->ia_file = file; ++ ia->ia_valid |= ATTR_FILE; ++ } ++out_si: ++ si_read_unlock(sb); ++out_kfree: ++ kfree(a); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++#if IS_ENABLED(CONFIG_AUFS_XATTR) || IS_ENABLED(CONFIG_FS_POSIX_ACL) ++static int au_h_path_to_set_attr(struct dentry *dentry, ++ struct au_icpup_args *a, struct path *h_path) ++{ ++ int err; ++ struct super_block *sb; ++ ++ sb = dentry->d_sb; ++ a->udba = au_opt_udba(sb); ++ /* no d_unlinked(), to set UDBA_NONE for root */ ++ if (d_unhashed(dentry)) ++ a->udba = AuOpt_UDBA_NONE; ++ if (a->udba != AuOpt_UDBA_NONE) { ++ AuDebugOn(IS_ROOT(dentry)); ++ err = au_reval_for_attr(dentry, au_sigen(sb)); ++ if (unlikely(err)) ++ goto out; ++ } ++ err = au_pin_and_icpup(dentry, /*ia*/NULL, a); ++ if (unlikely(err < 0)) ++ goto out; ++ ++ h_path->dentry = a->h_path.dentry; ++ h_path->mnt = au_sbr_mnt(sb, a->btgt); ++ ++out: ++ return err; ++} ++ ++ssize_t au_srxattr(struct dentry *dentry, struct au_srxattr *arg) ++{ ++ int err; ++ struct path h_path; ++ struct super_block *sb; ++ struct au_icpup_args *a; ++ struct inode *inode, *h_inode; ++ ++ inode = dentry->d_inode; ++ IMustLock(inode); ++ ++ err = -ENOMEM; ++ a = kzalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ sb = dentry->d_sb; ++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (unlikely(err)) ++ goto out_kfree; ++ ++ h_path.dentry = NULL; /* silence gcc */ ++ di_write_lock_child(dentry); ++ err = au_h_path_to_set_attr(dentry, a, &h_path); ++ if (unlikely(err)) ++ goto out_di; ++ ++ mutex_unlock(&a->h_inode->i_mutex); ++ switch (arg->type) { ++ case AU_XATTR_SET: ++ err = vfsub_setxattr(h_path.dentry, ++ arg->u.set.name, arg->u.set.value, ++ arg->u.set.size, arg->u.set.flags); ++ break; ++ case AU_XATTR_REMOVE: ++ err = vfsub_removexattr(h_path.dentry, arg->u.remove.name); ++ break; ++ case AU_ACL_SET: ++ err = -EOPNOTSUPP; ++ h_inode = h_path.dentry->d_inode; ++ if (h_inode->i_op->set_acl) ++ err = h_inode->i_op->set_acl(h_inode, ++ arg->u.acl_set.acl, ++ arg->u.acl_set.type); ++ break; ++ } ++ if (!err) ++ au_cpup_attr_timesizes(inode); ++ ++ au_unpin(&a->pin); ++ if (unlikely(err)) ++ au_update_dbstart(dentry); ++ ++out_di: ++ di_write_unlock(dentry); ++ si_read_unlock(sb); ++out_kfree: ++ kfree(a); ++out: ++ AuTraceErr(err); ++ return err; ++} ++#endif ++ ++static void au_refresh_iattr(struct inode *inode, struct kstat *st, ++ unsigned int nlink) ++{ ++ unsigned int n; ++ ++ inode->i_mode = st->mode; ++ /* don't i_[ug]id_write() here */ ++ inode->i_uid = st->uid; ++ inode->i_gid = st->gid; ++ inode->i_atime = st->atime; ++ inode->i_mtime = st->mtime; ++ inode->i_ctime = st->ctime; ++ ++ au_cpup_attr_nlink(inode, /*force*/0); ++ if (S_ISDIR(inode->i_mode)) { ++ n = inode->i_nlink; ++ n -= nlink; ++ n += st->nlink; ++ smp_mb(); /* for i_nlink */ ++ /* 0 can happen */ ++ set_nlink(inode, n); ++ } ++ ++ spin_lock(&inode->i_lock); ++ inode->i_blocks = st->blocks; ++ i_size_write(inode, st->size); ++ spin_unlock(&inode->i_lock); ++} ++ ++/* ++ * common routine for aufs_getattr() and aufs_getxattr(). ++ * returns zero or negative (an error). ++ * @dentry will be read-locked in success. ++ */ ++int au_h_path_getattr(struct dentry *dentry, int force, struct path *h_path) ++{ ++ int err; ++ unsigned int mnt_flags, sigen; ++ unsigned char udba_none; ++ aufs_bindex_t bindex; ++ struct super_block *sb, *h_sb; ++ struct inode *inode; ++ ++ h_path->mnt = NULL; ++ h_path->dentry = NULL; ++ ++ err = 0; ++ sb = dentry->d_sb; ++ mnt_flags = au_mntflags(sb); ++ udba_none = !!au_opt_test(mnt_flags, UDBA_NONE); ++ ++ /* support fstat(2) */ ++ if (!d_unlinked(dentry) && !udba_none) { ++ sigen = au_sigen(sb); ++ err = au_digen_test(dentry, sigen); ++ if (!err) { ++ di_read_lock_child(dentry, AuLock_IR); ++ err = au_dbrange_test(dentry); ++ if (unlikely(err)) { ++ di_read_unlock(dentry, AuLock_IR); ++ goto out; ++ } ++ } else { ++ AuDebugOn(IS_ROOT(dentry)); ++ di_write_lock_child(dentry); ++ err = au_dbrange_test(dentry); ++ if (!err) ++ err = au_reval_for_attr(dentry, sigen); ++ if (!err) ++ di_downgrade_lock(dentry, AuLock_IR); ++ else { ++ di_write_unlock(dentry); ++ goto out; ++ } ++ } ++ } else ++ di_read_lock_child(dentry, AuLock_IR); ++ ++ inode = dentry->d_inode; ++ bindex = au_ibstart(inode); ++ h_path->mnt = au_sbr_mnt(sb, bindex); ++ h_sb = h_path->mnt->mnt_sb; ++ if (!force ++ && !au_test_fs_bad_iattr(h_sb) ++ && udba_none) ++ goto out; /* success */ ++ ++ if (au_dbstart(dentry) == bindex) ++ h_path->dentry = au_h_dptr(dentry, bindex); ++ else if (au_opt_test(mnt_flags, PLINK) && au_plink_test(inode)) { ++ h_path->dentry = au_plink_lkup(inode, bindex); ++ if (IS_ERR(h_path->dentry)) ++ /* pretending success */ ++ h_path->dentry = NULL; ++ else ++ dput(h_path->dentry); ++ } ++ ++out: ++ return err; ++} ++ ++static int aufs_getattr(struct vfsmount *mnt __maybe_unused, ++ struct dentry *dentry, struct kstat *st) ++{ ++ int err; ++ unsigned char positive; ++ struct path h_path; ++ struct inode *inode; ++ struct super_block *sb; ++ ++ inode = dentry->d_inode; ++ sb = dentry->d_sb; ++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (unlikely(err)) ++ goto out; ++ err = au_h_path_getattr(dentry, /*force*/0, &h_path); ++ if (unlikely(err)) ++ goto out_si; ++ if (unlikely(!h_path.dentry)) ++ /* illegally overlapped or something */ ++ goto out_fill; /* pretending success */ ++ ++ positive = !!h_path.dentry->d_inode; ++ if (positive) ++ err = vfs_getattr(&h_path, st); ++ if (!err) { ++ if (positive) ++ au_refresh_iattr(inode, st, ++ h_path.dentry->d_inode->i_nlink); ++ goto out_fill; /* success */ ++ } ++ AuTraceErr(err); ++ goto out_di; ++ ++out_fill: ++ generic_fillattr(inode, st); ++out_di: ++ di_read_unlock(dentry, AuLock_IR); ++out_si: ++ si_read_unlock(sb); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int h_readlink(struct dentry *dentry, int bindex, char __user *buf, ++ int bufsiz) ++{ ++ int err; ++ struct super_block *sb; ++ struct dentry *h_dentry; ++ ++ err = -EINVAL; ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (unlikely(!h_dentry->d_inode->i_op->readlink)) ++ goto out; ++ ++ err = security_inode_readlink(h_dentry); ++ if (unlikely(err)) ++ goto out; ++ ++ sb = dentry->d_sb; ++ if (!au_test_ro(sb, bindex, dentry->d_inode)) { ++ vfsub_touch_atime(au_sbr_mnt(sb, bindex), h_dentry); ++ fsstack_copy_attr_atime(dentry->d_inode, h_dentry->d_inode); ++ } ++ err = h_dentry->d_inode->i_op->readlink(h_dentry, buf, bufsiz); ++ ++out: ++ return err; ++} ++ ++static int aufs_readlink(struct dentry *dentry, char __user *buf, int bufsiz) ++{ ++ int err; ++ ++ err = aufs_read_lock(dentry, AuLock_IR | AuLock_GEN); ++ if (unlikely(err)) ++ goto out; ++ err = au_d_hashed_positive(dentry); ++ if (!err) ++ err = h_readlink(dentry, au_dbstart(dentry), buf, bufsiz); ++ aufs_read_unlock(dentry, AuLock_IR); ++ ++out: ++ return err; ++} ++ ++static void *aufs_follow_link(struct dentry *dentry, struct nameidata *nd) ++{ ++ int err; ++ mm_segment_t old_fs; ++ union { ++ char *k; ++ char __user *u; ++ } buf; ++ ++ err = -ENOMEM; ++ buf.k = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!buf.k)) ++ goto out; ++ ++ err = aufs_read_lock(dentry, AuLock_IR | AuLock_GEN); ++ if (unlikely(err)) ++ goto out_name; ++ ++ err = au_d_hashed_positive(dentry); ++ if (!err) { ++ old_fs = get_fs(); ++ set_fs(KERNEL_DS); ++ err = h_readlink(dentry, au_dbstart(dentry), buf.u, PATH_MAX); ++ set_fs(old_fs); ++ } ++ aufs_read_unlock(dentry, AuLock_IR); ++ ++ if (err >= 0) { ++ buf.k[err] = 0; ++ /* will be freed by put_link */ ++ nd_set_link(nd, buf.k); ++ return NULL; /* success */ ++ } ++ ++out_name: ++ free_page((unsigned long)buf.k); ++out: ++ AuTraceErr(err); ++ return ERR_PTR(err); ++} ++ ++static void aufs_put_link(struct dentry *dentry __maybe_unused, ++ struct nameidata *nd, void *cookie __maybe_unused) ++{ ++ char *p; ++ ++ p = nd_get_link(nd); ++ if (!IS_ERR_OR_NULL(p)) ++ free_page((unsigned long)p); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int aufs_update_time(struct inode *inode, struct timespec *ts, int flags) ++{ ++ int err; ++ struct super_block *sb; ++ struct inode *h_inode; ++ ++ sb = inode->i_sb; ++ /* mmap_sem might be acquired already, cf. aufs_mmap() */ ++ lockdep_off(); ++ si_read_lock(sb, AuLock_FLUSH); ++ ii_write_lock_child(inode); ++ lockdep_on(); ++ h_inode = au_h_iptr(inode, au_ibstart(inode)); ++ err = vfsub_update_time(h_inode, ts, flags); ++ lockdep_off(); ++ if (!err) ++ au_cpup_attr_timesizes(inode); ++ ii_write_unlock(inode); ++ si_read_unlock(sb); ++ lockdep_on(); ++ ++ if (!err && (flags & S_VERSION)) ++ inode_inc_iversion(inode); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* no getattr version will be set by module.c:aufs_init() */ ++struct inode_operations aufs_iop_nogetattr[AuIop_Last], ++ aufs_iop[] = { ++ [AuIop_SYMLINK] = { ++ .permission = aufs_permission, ++#ifdef CONFIG_FS_POSIX_ACL ++ .get_acl = aufs_get_acl, ++ .set_acl = aufs_set_acl, /* unsupport for symlink? */ ++#endif ++ ++ .setattr = aufs_setattr, ++ .getattr = aufs_getattr, ++ ++#ifdef CONFIG_AUFS_XATTR ++ .setxattr = aufs_setxattr, ++ .getxattr = aufs_getxattr, ++ .listxattr = aufs_listxattr, ++ .removexattr = aufs_removexattr, ++#endif ++ ++ .readlink = aufs_readlink, ++ .follow_link = aufs_follow_link, ++ .put_link = aufs_put_link, ++ ++ /* .update_time = aufs_update_time */ ++ }, ++ [AuIop_DIR] = { ++ .create = aufs_create, ++ .lookup = aufs_lookup, ++ .link = aufs_link, ++ .unlink = aufs_unlink, ++ .symlink = aufs_symlink, ++ .mkdir = aufs_mkdir, ++ .rmdir = aufs_rmdir, ++ .mknod = aufs_mknod, ++ .rename = aufs_rename, ++ ++ .permission = aufs_permission, ++#ifdef CONFIG_FS_POSIX_ACL ++ .get_acl = aufs_get_acl, ++ .set_acl = aufs_set_acl, ++#endif ++ ++ .setattr = aufs_setattr, ++ .getattr = aufs_getattr, ++ ++#ifdef CONFIG_AUFS_XATTR ++ .setxattr = aufs_setxattr, ++ .getxattr = aufs_getxattr, ++ .listxattr = aufs_listxattr, ++ .removexattr = aufs_removexattr, ++#endif ++ ++ .update_time = aufs_update_time, ++ .atomic_open = aufs_atomic_open, ++ .tmpfile = aufs_tmpfile ++ }, ++ [AuIop_OTHER] = { ++ .permission = aufs_permission, ++#ifdef CONFIG_FS_POSIX_ACL ++ .get_acl = aufs_get_acl, ++ .set_acl = aufs_set_acl, ++#endif ++ ++ .setattr = aufs_setattr, ++ .getattr = aufs_getattr, ++ ++#ifdef CONFIG_AUFS_XATTR ++ .setxattr = aufs_setxattr, ++ .getxattr = aufs_getxattr, ++ .listxattr = aufs_listxattr, ++ .removexattr = aufs_removexattr, ++#endif ++ ++ .update_time = aufs_update_time ++ } ++}; +diff --git a/fs/aufs/i_op_add.c b/fs/aufs/i_op_add.c +new file mode 100644 +index 0000000..9e4f65c +--- /dev/null ++++ b/fs/aufs/i_op_add.c +@@ -0,0 +1,930 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * inode operations (add entry) ++ */ ++ ++#include "aufs.h" ++ ++/* ++ * final procedure of adding a new entry, except link(2). ++ * remove whiteout, instantiate, copyup the parent dir's times and size ++ * and update version. ++ * if it failed, re-create the removed whiteout. ++ */ ++static int epilog(struct inode *dir, aufs_bindex_t bindex, ++ struct dentry *wh_dentry, struct dentry *dentry) ++{ ++ int err, rerr; ++ aufs_bindex_t bwh; ++ struct path h_path; ++ struct super_block *sb; ++ struct inode *inode, *h_dir; ++ struct dentry *wh; ++ ++ bwh = -1; ++ sb = dir->i_sb; ++ if (wh_dentry) { ++ h_dir = wh_dentry->d_parent->d_inode; /* dir inode is locked */ ++ IMustLock(h_dir); ++ AuDebugOn(au_h_iptr(dir, bindex) != h_dir); ++ bwh = au_dbwh(dentry); ++ h_path.dentry = wh_dentry; ++ h_path.mnt = au_sbr_mnt(sb, bindex); ++ err = au_wh_unlink_dentry(au_h_iptr(dir, bindex), &h_path, ++ dentry); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++ inode = au_new_inode(dentry, /*must_new*/1); ++ if (!IS_ERR(inode)) { ++ d_instantiate(dentry, inode); ++ dir = dentry->d_parent->d_inode; /* dir inode is locked */ ++ IMustLock(dir); ++ au_dir_ts(dir, bindex); ++ dir->i_version++; ++ au_fhsm_wrote(sb, bindex, /*force*/0); ++ return 0; /* success */ ++ } ++ ++ err = PTR_ERR(inode); ++ if (!wh_dentry) ++ goto out; ++ ++ /* revert */ ++ /* dir inode is locked */ ++ wh = au_wh_create(dentry, bwh, wh_dentry->d_parent); ++ rerr = PTR_ERR(wh); ++ if (IS_ERR(wh)) { ++ AuIOErr("%pd reverting whiteout failed(%d, %d)\n", ++ dentry, err, rerr); ++ err = -EIO; ++ } else ++ dput(wh); ++ ++out: ++ return err; ++} ++ ++static int au_d_may_add(struct dentry *dentry) ++{ ++ int err; ++ ++ err = 0; ++ if (unlikely(d_unhashed(dentry))) ++ err = -ENOENT; ++ if (unlikely(dentry->d_inode)) ++ err = -EEXIST; ++ return err; ++} ++ ++/* ++ * simple tests for the adding inode operations. ++ * following the checks in vfs, plus the parent-child relationship. ++ */ ++int au_may_add(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_parent, int isdir) ++{ ++ int err; ++ umode_t h_mode; ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ ++ err = -ENAMETOOLONG; ++ if (unlikely(dentry->d_name.len > AUFS_MAX_NAMELEN)) ++ goto out; ++ ++ h_dentry = au_h_dptr(dentry, bindex); ++ h_inode = h_dentry->d_inode; ++ if (!dentry->d_inode) { ++ err = -EEXIST; ++ if (unlikely(h_inode)) ++ goto out; ++ } else { ++ /* rename(2) case */ ++ err = -EIO; ++ if (unlikely(!h_inode || !h_inode->i_nlink)) ++ goto out; ++ ++ h_mode = h_inode->i_mode; ++ if (!isdir) { ++ err = -EISDIR; ++ if (unlikely(S_ISDIR(h_mode))) ++ goto out; ++ } else if (unlikely(!S_ISDIR(h_mode))) { ++ err = -ENOTDIR; ++ goto out; ++ } ++ } ++ ++ err = 0; ++ /* expected parent dir is locked */ ++ if (unlikely(h_parent != h_dentry->d_parent)) ++ err = -EIO; ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ++ * initial procedure of adding a new entry. ++ * prepare writable branch and the parent dir, lock it, ++ * and lookup whiteout for the new entry. ++ */ ++static struct dentry* ++lock_hdir_lkup_wh(struct dentry *dentry, struct au_dtime *dt, ++ struct dentry *src_dentry, struct au_pin *pin, ++ struct au_wr_dir_args *wr_dir_args) ++{ ++ struct dentry *wh_dentry, *h_parent; ++ struct super_block *sb; ++ struct au_branch *br; ++ int err; ++ unsigned int udba; ++ aufs_bindex_t bcpup; ++ ++ AuDbg("%pd\n", dentry); ++ ++ err = au_wr_dir(dentry, src_dentry, wr_dir_args); ++ bcpup = err; ++ wh_dentry = ERR_PTR(err); ++ if (unlikely(err < 0)) ++ goto out; ++ ++ sb = dentry->d_sb; ++ udba = au_opt_udba(sb); ++ err = au_pin(pin, dentry, bcpup, udba, ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ wh_dentry = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out; ++ ++ h_parent = au_pinned_h_parent(pin); ++ if (udba != AuOpt_UDBA_NONE ++ && au_dbstart(dentry) == bcpup) ++ err = au_may_add(dentry, bcpup, h_parent, ++ au_ftest_wrdir(wr_dir_args->flags, ISDIR)); ++ else if (unlikely(dentry->d_name.len > AUFS_MAX_NAMELEN)) ++ err = -ENAMETOOLONG; ++ wh_dentry = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out_unpin; ++ ++ br = au_sbr(sb, bcpup); ++ if (dt) { ++ struct path tmp = { ++ .dentry = h_parent, ++ .mnt = au_br_mnt(br) ++ }; ++ au_dtime_store(dt, au_pinned_parent(pin), &tmp); ++ } ++ ++ wh_dentry = NULL; ++ if (bcpup != au_dbwh(dentry)) ++ goto out; /* success */ ++ ++ /* ++ * ENAMETOOLONG here means that if we allowed create such name, then it ++ * would not be able to removed in the future. So we don't allow such ++ * name here and we don't handle ENAMETOOLONG differently here. ++ */ ++ wh_dentry = au_wh_lkup(h_parent, &dentry->d_name, br); ++ ++out_unpin: ++ if (IS_ERR(wh_dentry)) ++ au_unpin(pin); ++out: ++ return wh_dentry; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++enum { Mknod, Symlink, Creat }; ++struct simple_arg { ++ int type; ++ union { ++ struct { ++ umode_t mode; ++ bool want_excl; ++ bool try_aopen; ++ struct vfsub_aopen_args *aopen; ++ } c; ++ struct { ++ const char *symname; ++ } s; ++ struct { ++ umode_t mode; ++ dev_t dev; ++ } m; ++ } u; ++}; ++ ++static int add_simple(struct inode *dir, struct dentry *dentry, ++ struct simple_arg *arg) ++{ ++ int err, rerr; ++ aufs_bindex_t bstart; ++ unsigned char created; ++ const unsigned char try_aopen ++ = (arg->type == Creat && arg->u.c.try_aopen); ++ struct dentry *wh_dentry, *parent; ++ struct inode *h_dir; ++ struct super_block *sb; ++ struct au_branch *br; ++ /* to reuduce stack size */ ++ struct { ++ struct au_dtime dt; ++ struct au_pin pin; ++ struct path h_path; ++ struct au_wr_dir_args wr_dir_args; ++ } *a; ++ ++ AuDbg("%pd\n", dentry); ++ IMustLock(dir); ++ ++ err = -ENOMEM; ++ a = kmalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ a->wr_dir_args.force_btgt = -1; ++ a->wr_dir_args.flags = AuWrDir_ADD_ENTRY; ++ ++ parent = dentry->d_parent; /* dir inode is locked */ ++ if (!try_aopen) { ++ err = aufs_read_lock(dentry, AuLock_DW | AuLock_GEN); ++ if (unlikely(err)) ++ goto out_free; ++ } ++ err = au_d_may_add(dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ if (!try_aopen) ++ di_write_lock_parent(parent); ++ wh_dentry = lock_hdir_lkup_wh(dentry, &a->dt, /*src_dentry*/NULL, ++ &a->pin, &a->wr_dir_args); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out_parent; ++ ++ bstart = au_dbstart(dentry); ++ sb = dentry->d_sb; ++ br = au_sbr(sb, bstart); ++ a->h_path.dentry = au_h_dptr(dentry, bstart); ++ a->h_path.mnt = au_br_mnt(br); ++ h_dir = au_pinned_h_dir(&a->pin); ++ switch (arg->type) { ++ case Creat: ++ err = 0; ++ if (!try_aopen || !h_dir->i_op->atomic_open) ++ err = vfsub_create(h_dir, &a->h_path, arg->u.c.mode, ++ arg->u.c.want_excl); ++ else ++ err = vfsub_atomic_open(h_dir, a->h_path.dentry, ++ arg->u.c.aopen, br); ++ break; ++ case Symlink: ++ err = vfsub_symlink(h_dir, &a->h_path, arg->u.s.symname); ++ break; ++ case Mknod: ++ err = vfsub_mknod(h_dir, &a->h_path, arg->u.m.mode, ++ arg->u.m.dev); ++ break; ++ default: ++ BUG(); ++ } ++ created = !err; ++ if (!err) ++ err = epilog(dir, bstart, wh_dentry, dentry); ++ ++ /* revert */ ++ if (unlikely(created && err && a->h_path.dentry->d_inode)) { ++ /* no delegation since it is just created */ ++ rerr = vfsub_unlink(h_dir, &a->h_path, /*delegated*/NULL, ++ /*force*/0); ++ if (rerr) { ++ AuIOErr("%pd revert failure(%d, %d)\n", ++ dentry, err, rerr); ++ err = -EIO; ++ } ++ au_dtime_revert(&a->dt); ++ } ++ ++ if (!err && try_aopen && !h_dir->i_op->atomic_open) ++ *arg->u.c.aopen->opened |= FILE_CREATED; ++ ++ au_unpin(&a->pin); ++ dput(wh_dentry); ++ ++out_parent: ++ if (!try_aopen) ++ di_write_unlock(parent); ++out_unlock: ++ if (unlikely(err)) { ++ au_update_dbstart(dentry); ++ d_drop(dentry); ++ } ++ if (!try_aopen) ++ aufs_read_unlock(dentry, AuLock_DW); ++out_free: ++ kfree(a); ++out: ++ return err; ++} ++ ++int aufs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, ++ dev_t dev) ++{ ++ struct simple_arg arg = { ++ .type = Mknod, ++ .u.m = { ++ .mode = mode, ++ .dev = dev ++ } ++ }; ++ return add_simple(dir, dentry, &arg); ++} ++ ++int aufs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) ++{ ++ struct simple_arg arg = { ++ .type = Symlink, ++ .u.s.symname = symname ++ }; ++ return add_simple(dir, dentry, &arg); ++} ++ ++int aufs_create(struct inode *dir, struct dentry *dentry, umode_t mode, ++ bool want_excl) ++{ ++ struct simple_arg arg = { ++ .type = Creat, ++ .u.c = { ++ .mode = mode, ++ .want_excl = want_excl ++ } ++ }; ++ return add_simple(dir, dentry, &arg); ++} ++ ++int au_aopen_or_create(struct inode *dir, struct dentry *dentry, ++ struct vfsub_aopen_args *aopen_args) ++{ ++ struct simple_arg arg = { ++ .type = Creat, ++ .u.c = { ++ .mode = aopen_args->create_mode, ++ .want_excl = aopen_args->open_flag & O_EXCL, ++ .try_aopen = true, ++ .aopen = aopen_args ++ } ++ }; ++ return add_simple(dir, dentry, &arg); ++} ++ ++int aufs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ struct super_block *sb; ++ struct dentry *parent, *h_parent, *h_dentry; ++ struct inode *h_dir, *inode; ++ struct vfsmount *h_mnt; ++ struct au_wr_dir_args wr_dir_args = { ++ .force_btgt = -1, ++ .flags = AuWrDir_TMPFILE ++ }; ++ ++ /* copy-up may happen */ ++ mutex_lock(&dir->i_mutex); ++ ++ sb = dir->i_sb; ++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (unlikely(err)) ++ goto out; ++ ++ err = au_di_init(dentry); ++ if (unlikely(err)) ++ goto out_si; ++ ++ err = -EBUSY; ++ parent = d_find_any_alias(dir); ++ AuDebugOn(!parent); ++ di_write_lock_parent(parent); ++ if (unlikely(parent->d_inode != dir)) ++ goto out_parent; ++ ++ err = au_digen_test(parent, au_sigen(sb)); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ bindex = au_dbstart(parent); ++ au_set_dbstart(dentry, bindex); ++ au_set_dbend(dentry, bindex); ++ err = au_wr_dir(dentry, /*src_dentry*/NULL, &wr_dir_args); ++ bindex = err; ++ if (unlikely(err < 0)) ++ goto out_parent; ++ ++ err = -EOPNOTSUPP; ++ h_dir = au_h_iptr(dir, bindex); ++ if (unlikely(!h_dir->i_op->tmpfile)) ++ goto out_parent; ++ ++ h_mnt = au_sbr_mnt(sb, bindex); ++ err = vfsub_mnt_want_write(h_mnt); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ h_parent = au_h_dptr(parent, bindex); ++ err = inode_permission(h_parent->d_inode, MAY_WRITE | MAY_EXEC); ++ if (unlikely(err)) ++ goto out_mnt; ++ ++ err = -ENOMEM; ++ h_dentry = d_alloc(h_parent, &dentry->d_name); ++ if (unlikely(!h_dentry)) ++ goto out_mnt; ++ ++ err = h_dir->i_op->tmpfile(h_dir, h_dentry, mode); ++ if (unlikely(err)) ++ goto out_dentry; ++ ++ au_set_dbstart(dentry, bindex); ++ au_set_dbend(dentry, bindex); ++ au_set_h_dptr(dentry, bindex, dget(h_dentry)); ++ inode = au_new_inode(dentry, /*must_new*/1); ++ if (IS_ERR(inode)) { ++ err = PTR_ERR(inode); ++ au_set_h_dptr(dentry, bindex, NULL); ++ au_set_dbstart(dentry, -1); ++ au_set_dbend(dentry, -1); ++ } else { ++ if (!inode->i_nlink) ++ set_nlink(inode, 1); ++ d_tmpfile(dentry, inode); ++ au_di(dentry)->di_tmpfile = 1; ++ ++ /* update without i_mutex */ ++ if (au_ibstart(dir) == au_dbstart(dentry)) ++ au_cpup_attr_timesizes(dir); ++ } ++ ++out_dentry: ++ dput(h_dentry); ++out_mnt: ++ vfsub_mnt_drop_write(h_mnt); ++out_parent: ++ di_write_unlock(parent); ++ dput(parent); ++ di_write_unlock(dentry); ++ if (!err) ++#if 0 ++ /* verbose coding for lock class name */ ++ au_rw_class(&au_di(dentry)->di_rwsem, ++ au_lc_key + AuLcNonDir_DIINFO); ++#else ++ ; ++#endif ++ else { ++ au_di_fin(dentry); ++ dentry->d_fsdata = NULL; ++ } ++out_si: ++ si_read_unlock(sb); ++out: ++ mutex_unlock(&dir->i_mutex); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_link_args { ++ aufs_bindex_t bdst, bsrc; ++ struct au_pin pin; ++ struct path h_path; ++ struct dentry *src_parent, *parent; ++}; ++ ++static int au_cpup_before_link(struct dentry *src_dentry, ++ struct au_link_args *a) ++{ ++ int err; ++ struct dentry *h_src_dentry; ++ struct au_cp_generic cpg = { ++ .dentry = src_dentry, ++ .bdst = a->bdst, ++ .bsrc = a->bsrc, ++ .len = -1, ++ .pin = &a->pin, ++ .flags = AuCpup_DTIME | AuCpup_HOPEN /* | AuCpup_KEEPLINO */ ++ }; ++ ++ di_read_lock_parent(a->src_parent, AuLock_IR); ++ err = au_test_and_cpup_dirs(src_dentry, a->bdst); ++ if (unlikely(err)) ++ goto out; ++ ++ h_src_dentry = au_h_dptr(src_dentry, a->bsrc); ++ err = au_pin(&a->pin, src_dentry, a->bdst, ++ au_opt_udba(src_dentry->d_sb), ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (unlikely(err)) ++ goto out; ++ ++ err = au_sio_cpup_simple(&cpg); ++ au_unpin(&a->pin); ++ ++out: ++ di_read_unlock(a->src_parent, AuLock_IR); ++ return err; ++} ++ ++static int au_cpup_or_link(struct dentry *src_dentry, struct dentry *dentry, ++ struct au_link_args *a) ++{ ++ int err; ++ unsigned char plink; ++ aufs_bindex_t bend; ++ struct dentry *h_src_dentry; ++ struct inode *h_inode, *inode, *delegated; ++ struct super_block *sb; ++ struct file *h_file; ++ ++ plink = 0; ++ h_inode = NULL; ++ sb = src_dentry->d_sb; ++ inode = src_dentry->d_inode; ++ if (au_ibstart(inode) <= a->bdst) ++ h_inode = au_h_iptr(inode, a->bdst); ++ if (!h_inode || !h_inode->i_nlink) { ++ /* copyup src_dentry as the name of dentry. */ ++ bend = au_dbend(dentry); ++ if (bend < a->bsrc) ++ au_set_dbend(dentry, a->bsrc); ++ au_set_h_dptr(dentry, a->bsrc, ++ dget(au_h_dptr(src_dentry, a->bsrc))); ++ dget(a->h_path.dentry); ++ au_set_h_dptr(dentry, a->bdst, NULL); ++ AuDbg("temporary d_inode...\n"); ++ spin_lock(&dentry->d_lock); ++ dentry->d_inode = src_dentry->d_inode; /* tmp */ ++ spin_unlock(&dentry->d_lock); ++ h_file = au_h_open_pre(dentry, a->bsrc, /*force_wr*/0); ++ if (IS_ERR(h_file)) ++ err = PTR_ERR(h_file); ++ else { ++ struct au_cp_generic cpg = { ++ .dentry = dentry, ++ .bdst = a->bdst, ++ .bsrc = -1, ++ .len = -1, ++ .pin = &a->pin, ++ .flags = AuCpup_KEEPLINO ++ }; ++ err = au_sio_cpup_simple(&cpg); ++ au_h_open_post(dentry, a->bsrc, h_file); ++ if (!err) { ++ dput(a->h_path.dentry); ++ a->h_path.dentry = au_h_dptr(dentry, a->bdst); ++ } else ++ au_set_h_dptr(dentry, a->bdst, ++ a->h_path.dentry); ++ } ++ spin_lock(&dentry->d_lock); ++ dentry->d_inode = NULL; /* restore */ ++ spin_unlock(&dentry->d_lock); ++ AuDbg("temporary d_inode...done\n"); ++ au_set_h_dptr(dentry, a->bsrc, NULL); ++ au_set_dbend(dentry, bend); ++ } else { ++ /* the inode of src_dentry already exists on a.bdst branch */ ++ h_src_dentry = d_find_alias(h_inode); ++ if (!h_src_dentry && au_plink_test(inode)) { ++ plink = 1; ++ h_src_dentry = au_plink_lkup(inode, a->bdst); ++ err = PTR_ERR(h_src_dentry); ++ if (IS_ERR(h_src_dentry)) ++ goto out; ++ ++ if (unlikely(!h_src_dentry->d_inode)) { ++ dput(h_src_dentry); ++ h_src_dentry = NULL; ++ } ++ ++ } ++ if (h_src_dentry) { ++ delegated = NULL; ++ err = vfsub_link(h_src_dentry, au_pinned_h_dir(&a->pin), ++ &a->h_path, &delegated); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal link\n"); ++ iput(delegated); ++ } ++ dput(h_src_dentry); ++ } else { ++ AuIOErr("no dentry found for hi%lu on b%d\n", ++ h_inode->i_ino, a->bdst); ++ err = -EIO; ++ } ++ } ++ ++ if (!err && !plink) ++ au_plink_append(inode, a->bdst, a->h_path.dentry); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int aufs_link(struct dentry *src_dentry, struct inode *dir, ++ struct dentry *dentry) ++{ ++ int err, rerr; ++ struct au_dtime dt; ++ struct au_link_args *a; ++ struct dentry *wh_dentry, *h_src_dentry; ++ struct inode *inode, *delegated; ++ struct super_block *sb; ++ struct au_wr_dir_args wr_dir_args = { ++ /* .force_btgt = -1, */ ++ .flags = AuWrDir_ADD_ENTRY ++ }; ++ ++ IMustLock(dir); ++ inode = src_dentry->d_inode; ++ IMustLock(inode); ++ ++ err = -ENOMEM; ++ a = kzalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ a->parent = dentry->d_parent; /* dir inode is locked */ ++ err = aufs_read_and_write_lock2(dentry, src_dentry, ++ AuLock_NOPLM | AuLock_GEN); ++ if (unlikely(err)) ++ goto out_kfree; ++ err = au_d_linkable(src_dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ err = au_d_may_add(dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ ++ a->src_parent = dget_parent(src_dentry); ++ wr_dir_args.force_btgt = au_ibstart(inode); ++ ++ di_write_lock_parent(a->parent); ++ wr_dir_args.force_btgt = au_wbr(dentry, wr_dir_args.force_btgt); ++ wh_dentry = lock_hdir_lkup_wh(dentry, &dt, src_dentry, &a->pin, ++ &wr_dir_args); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out_parent; ++ ++ err = 0; ++ sb = dentry->d_sb; ++ a->bdst = au_dbstart(dentry); ++ a->h_path.dentry = au_h_dptr(dentry, a->bdst); ++ a->h_path.mnt = au_sbr_mnt(sb, a->bdst); ++ a->bsrc = au_ibstart(inode); ++ h_src_dentry = au_h_d_alias(src_dentry, a->bsrc); ++ if (!h_src_dentry && au_di(src_dentry)->di_tmpfile) ++ h_src_dentry = dget(au_hi_wh(inode, a->bsrc)); ++ if (!h_src_dentry) { ++ a->bsrc = au_dbstart(src_dentry); ++ h_src_dentry = au_h_d_alias(src_dentry, a->bsrc); ++ AuDebugOn(!h_src_dentry); ++ } else if (IS_ERR(h_src_dentry)) { ++ err = PTR_ERR(h_src_dentry); ++ goto out_parent; ++ } ++ ++ if (au_opt_test(au_mntflags(sb), PLINK)) { ++ if (a->bdst < a->bsrc ++ /* && h_src_dentry->d_sb != a->h_path.dentry->d_sb */) ++ err = au_cpup_or_link(src_dentry, dentry, a); ++ else { ++ delegated = NULL; ++ err = vfsub_link(h_src_dentry, au_pinned_h_dir(&a->pin), ++ &a->h_path, &delegated); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal link\n"); ++ iput(delegated); ++ } ++ } ++ dput(h_src_dentry); ++ } else { ++ /* ++ * copyup src_dentry to the branch we process, ++ * and then link(2) to it. ++ */ ++ dput(h_src_dentry); ++ if (a->bdst < a->bsrc ++ /* && h_src_dentry->d_sb != a->h_path.dentry->d_sb */) { ++ au_unpin(&a->pin); ++ di_write_unlock(a->parent); ++ err = au_cpup_before_link(src_dentry, a); ++ di_write_lock_parent(a->parent); ++ if (!err) ++ err = au_pin(&a->pin, dentry, a->bdst, ++ au_opt_udba(sb), ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (unlikely(err)) ++ goto out_wh; ++ } ++ if (!err) { ++ h_src_dentry = au_h_dptr(src_dentry, a->bdst); ++ err = -ENOENT; ++ if (h_src_dentry && h_src_dentry->d_inode) { ++ delegated = NULL; ++ err = vfsub_link(h_src_dentry, ++ au_pinned_h_dir(&a->pin), ++ &a->h_path, &delegated); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry" ++ " for NFSv4 delegation" ++ " for an internal link\n"); ++ iput(delegated); ++ } ++ } ++ } ++ } ++ if (unlikely(err)) ++ goto out_unpin; ++ ++ if (wh_dentry) { ++ a->h_path.dentry = wh_dentry; ++ err = au_wh_unlink_dentry(au_pinned_h_dir(&a->pin), &a->h_path, ++ dentry); ++ if (unlikely(err)) ++ goto out_revert; ++ } ++ ++ au_dir_ts(dir, a->bdst); ++ dir->i_version++; ++ inc_nlink(inode); ++ inode->i_ctime = dir->i_ctime; ++ d_instantiate(dentry, au_igrab(inode)); ++ if (d_unhashed(a->h_path.dentry)) ++ /* some filesystem calls d_drop() */ ++ d_drop(dentry); ++ /* some filesystems consume an inode even hardlink */ ++ au_fhsm_wrote(sb, a->bdst, /*force*/0); ++ goto out_unpin; /* success */ ++ ++out_revert: ++ /* no delegation since it is just created */ ++ rerr = vfsub_unlink(au_pinned_h_dir(&a->pin), &a->h_path, ++ /*delegated*/NULL, /*force*/0); ++ if (unlikely(rerr)) { ++ AuIOErr("%pd reverting failed(%d, %d)\n", dentry, err, rerr); ++ err = -EIO; ++ } ++ au_dtime_revert(&dt); ++out_unpin: ++ au_unpin(&a->pin); ++out_wh: ++ dput(wh_dentry); ++out_parent: ++ di_write_unlock(a->parent); ++ dput(a->src_parent); ++out_unlock: ++ if (unlikely(err)) { ++ au_update_dbstart(dentry); ++ d_drop(dentry); ++ } ++ aufs_read_and_write_unlock2(dentry, src_dentry); ++out_kfree: ++ kfree(a); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int aufs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) ++{ ++ int err, rerr; ++ aufs_bindex_t bindex; ++ unsigned char diropq; ++ struct path h_path; ++ struct dentry *wh_dentry, *parent, *opq_dentry; ++ struct mutex *h_mtx; ++ struct super_block *sb; ++ struct { ++ struct au_pin pin; ++ struct au_dtime dt; ++ } *a; /* reduce the stack usage */ ++ struct au_wr_dir_args wr_dir_args = { ++ .force_btgt = -1, ++ .flags = AuWrDir_ADD_ENTRY | AuWrDir_ISDIR ++ }; ++ ++ IMustLock(dir); ++ ++ err = -ENOMEM; ++ a = kmalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ err = aufs_read_lock(dentry, AuLock_DW | AuLock_GEN); ++ if (unlikely(err)) ++ goto out_free; ++ err = au_d_may_add(dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ ++ parent = dentry->d_parent; /* dir inode is locked */ ++ di_write_lock_parent(parent); ++ wh_dentry = lock_hdir_lkup_wh(dentry, &a->dt, /*src_dentry*/NULL, ++ &a->pin, &wr_dir_args); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out_parent; ++ ++ sb = dentry->d_sb; ++ bindex = au_dbstart(dentry); ++ h_path.dentry = au_h_dptr(dentry, bindex); ++ h_path.mnt = au_sbr_mnt(sb, bindex); ++ err = vfsub_mkdir(au_pinned_h_dir(&a->pin), &h_path, mode); ++ if (unlikely(err)) ++ goto out_unpin; ++ ++ /* make the dir opaque */ ++ diropq = 0; ++ h_mtx = &h_path.dentry->d_inode->i_mutex; ++ if (wh_dentry ++ || au_opt_test(au_mntflags(sb), ALWAYS_DIROPQ)) { ++ mutex_lock_nested(h_mtx, AuLsc_I_CHILD); ++ opq_dentry = au_diropq_create(dentry, bindex); ++ mutex_unlock(h_mtx); ++ err = PTR_ERR(opq_dentry); ++ if (IS_ERR(opq_dentry)) ++ goto out_dir; ++ dput(opq_dentry); ++ diropq = 1; ++ } ++ ++ err = epilog(dir, bindex, wh_dentry, dentry); ++ if (!err) { ++ inc_nlink(dir); ++ goto out_unpin; /* success */ ++ } ++ ++ /* revert */ ++ if (diropq) { ++ AuLabel(revert opq); ++ mutex_lock_nested(h_mtx, AuLsc_I_CHILD); ++ rerr = au_diropq_remove(dentry, bindex); ++ mutex_unlock(h_mtx); ++ if (rerr) { ++ AuIOErr("%pd reverting diropq failed(%d, %d)\n", ++ dentry, err, rerr); ++ err = -EIO; ++ } ++ } ++ ++out_dir: ++ AuLabel(revert dir); ++ rerr = vfsub_rmdir(au_pinned_h_dir(&a->pin), &h_path); ++ if (rerr) { ++ AuIOErr("%pd reverting dir failed(%d, %d)\n", ++ dentry, err, rerr); ++ err = -EIO; ++ } ++ au_dtime_revert(&a->dt); ++out_unpin: ++ au_unpin(&a->pin); ++ dput(wh_dentry); ++out_parent: ++ di_write_unlock(parent); ++out_unlock: ++ if (unlikely(err)) { ++ au_update_dbstart(dentry); ++ d_drop(dentry); ++ } ++ aufs_read_unlock(dentry, AuLock_DW); ++out_free: ++ kfree(a); ++out: ++ return err; ++} +diff --git a/fs/aufs/i_op_del.c b/fs/aufs/i_op_del.c +new file mode 100644 +index 0000000..b4dd686 +--- /dev/null ++++ b/fs/aufs/i_op_del.c +@@ -0,0 +1,506 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * inode operations (del entry) ++ */ ++ ++#include "aufs.h" ++ ++/* ++ * decide if a new whiteout for @dentry is necessary or not. ++ * when it is necessary, prepare the parent dir for the upper branch whose ++ * branch index is @bcpup for creation. the actual creation of the whiteout will ++ * be done by caller. ++ * return value: ++ * 0: wh is unnecessary ++ * plus: wh is necessary ++ * minus: error ++ */ ++int au_wr_dir_need_wh(struct dentry *dentry, int isdir, aufs_bindex_t *bcpup) ++{ ++ int need_wh, err; ++ aufs_bindex_t bstart; ++ struct super_block *sb; ++ ++ sb = dentry->d_sb; ++ bstart = au_dbstart(dentry); ++ if (*bcpup < 0) { ++ *bcpup = bstart; ++ if (au_test_ro(sb, bstart, dentry->d_inode)) { ++ err = AuWbrCopyup(au_sbi(sb), dentry); ++ *bcpup = err; ++ if (unlikely(err < 0)) ++ goto out; ++ } ++ } else ++ AuDebugOn(bstart < *bcpup ++ || au_test_ro(sb, *bcpup, dentry->d_inode)); ++ AuDbg("bcpup %d, bstart %d\n", *bcpup, bstart); ++ ++ if (*bcpup != bstart) { ++ err = au_cpup_dirs(dentry, *bcpup); ++ if (unlikely(err)) ++ goto out; ++ need_wh = 1; ++ } else { ++ struct au_dinfo *dinfo, *tmp; ++ ++ need_wh = -ENOMEM; ++ dinfo = au_di(dentry); ++ tmp = au_di_alloc(sb, AuLsc_DI_TMP); ++ if (tmp) { ++ au_di_cp(tmp, dinfo); ++ au_di_swap(tmp, dinfo); ++ /* returns the number of positive dentries */ ++ need_wh = au_lkup_dentry(dentry, bstart + 1, /*type*/0); ++ au_di_swap(tmp, dinfo); ++ au_rw_write_unlock(&tmp->di_rwsem); ++ au_di_free(tmp); ++ } ++ } ++ AuDbg("need_wh %d\n", need_wh); ++ err = need_wh; ++ ++out: ++ return err; ++} ++ ++/* ++ * simple tests for the del-entry operations. ++ * following the checks in vfs, plus the parent-child relationship. ++ */ ++int au_may_del(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_parent, int isdir) ++{ ++ int err; ++ umode_t h_mode; ++ struct dentry *h_dentry, *h_latest; ++ struct inode *h_inode; ++ ++ h_dentry = au_h_dptr(dentry, bindex); ++ h_inode = h_dentry->d_inode; ++ if (dentry->d_inode) { ++ err = -ENOENT; ++ if (unlikely(!h_inode || !h_inode->i_nlink)) ++ goto out; ++ ++ h_mode = h_inode->i_mode; ++ if (!isdir) { ++ err = -EISDIR; ++ if (unlikely(S_ISDIR(h_mode))) ++ goto out; ++ } else if (unlikely(!S_ISDIR(h_mode))) { ++ err = -ENOTDIR; ++ goto out; ++ } ++ } else { ++ /* rename(2) case */ ++ err = -EIO; ++ if (unlikely(h_inode)) ++ goto out; ++ } ++ ++ err = -ENOENT; ++ /* expected parent dir is locked */ ++ if (unlikely(h_parent != h_dentry->d_parent)) ++ goto out; ++ err = 0; ++ ++ /* ++ * rmdir a dir may break the consistency on some filesystem. ++ * let's try heavy test. ++ */ ++ err = -EACCES; ++ if (unlikely(!au_opt_test(au_mntflags(dentry->d_sb), DIRPERM1) ++ && au_test_h_perm(h_parent->d_inode, ++ MAY_EXEC | MAY_WRITE))) ++ goto out; ++ ++ h_latest = au_sio_lkup_one(&dentry->d_name, h_parent); ++ err = -EIO; ++ if (IS_ERR(h_latest)) ++ goto out; ++ if (h_latest == h_dentry) ++ err = 0; ++ dput(h_latest); ++ ++out: ++ return err; ++} ++ ++/* ++ * decide the branch where we operate for @dentry. the branch index will be set ++ * @rbcpup. after diciding it, 'pin' it and store the timestamps of the parent ++ * dir for reverting. ++ * when a new whiteout is necessary, create it. ++ */ ++static struct dentry* ++lock_hdir_create_wh(struct dentry *dentry, int isdir, aufs_bindex_t *rbcpup, ++ struct au_dtime *dt, struct au_pin *pin) ++{ ++ struct dentry *wh_dentry; ++ struct super_block *sb; ++ struct path h_path; ++ int err, need_wh; ++ unsigned int udba; ++ aufs_bindex_t bcpup; ++ ++ need_wh = au_wr_dir_need_wh(dentry, isdir, rbcpup); ++ wh_dentry = ERR_PTR(need_wh); ++ if (unlikely(need_wh < 0)) ++ goto out; ++ ++ sb = dentry->d_sb; ++ udba = au_opt_udba(sb); ++ bcpup = *rbcpup; ++ err = au_pin(pin, dentry, bcpup, udba, ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ wh_dentry = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out; ++ ++ h_path.dentry = au_pinned_h_parent(pin); ++ if (udba != AuOpt_UDBA_NONE ++ && au_dbstart(dentry) == bcpup) { ++ err = au_may_del(dentry, bcpup, h_path.dentry, isdir); ++ wh_dentry = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out_unpin; ++ } ++ ++ h_path.mnt = au_sbr_mnt(sb, bcpup); ++ au_dtime_store(dt, au_pinned_parent(pin), &h_path); ++ wh_dentry = NULL; ++ if (!need_wh) ++ goto out; /* success, no need to create whiteout */ ++ ++ wh_dentry = au_wh_create(dentry, bcpup, h_path.dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out_unpin; ++ ++ /* returns with the parent is locked and wh_dentry is dget-ed */ ++ goto out; /* success */ ++ ++out_unpin: ++ au_unpin(pin); ++out: ++ return wh_dentry; ++} ++ ++/* ++ * when removing a dir, rename it to a unique temporary whiteout-ed name first ++ * in order to be revertible and save time for removing many child whiteouts ++ * under the dir. ++ * returns 1 when there are too many child whiteout and caller should remove ++ * them asynchronously. returns 0 when the number of children is enough small to ++ * remove now or the branch fs is a remote fs. ++ * otherwise return an error. ++ */ ++static int renwh_and_rmdir(struct dentry *dentry, aufs_bindex_t bindex, ++ struct au_nhash *whlist, struct inode *dir) ++{ ++ int rmdir_later, err, dirwh; ++ struct dentry *h_dentry; ++ struct super_block *sb; ++ ++ sb = dentry->d_sb; ++ SiMustAnyLock(sb); ++ h_dentry = au_h_dptr(dentry, bindex); ++ err = au_whtmp_ren(h_dentry, au_sbr(sb, bindex)); ++ if (unlikely(err)) ++ goto out; ++ ++ /* stop monitoring */ ++ au_hn_free(au_hi(dentry->d_inode, bindex)); ++ ++ if (!au_test_fs_remote(h_dentry->d_sb)) { ++ dirwh = au_sbi(sb)->si_dirwh; ++ rmdir_later = (dirwh <= 1); ++ if (!rmdir_later) ++ rmdir_later = au_nhash_test_longer_wh(whlist, bindex, ++ dirwh); ++ if (rmdir_later) ++ return rmdir_later; ++ } ++ ++ err = au_whtmp_rmdir(dir, bindex, h_dentry, whlist); ++ if (unlikely(err)) { ++ AuIOErr("rmdir %pd, b%d failed, %d. ignored\n", ++ h_dentry, bindex, err); ++ err = 0; ++ } ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ++ * final procedure for deleting a entry. ++ * maintain dentry and iattr. ++ */ ++static void epilog(struct inode *dir, struct dentry *dentry, ++ aufs_bindex_t bindex) ++{ ++ struct inode *inode; ++ ++ inode = dentry->d_inode; ++ d_drop(dentry); ++ inode->i_ctime = dir->i_ctime; ++ ++ au_dir_ts(dir, bindex); ++ dir->i_version++; ++} ++ ++/* ++ * when an error happened, remove the created whiteout and revert everything. ++ */ ++static int do_revert(int err, struct inode *dir, aufs_bindex_t bindex, ++ aufs_bindex_t bwh, struct dentry *wh_dentry, ++ struct dentry *dentry, struct au_dtime *dt) ++{ ++ int rerr; ++ struct path h_path = { ++ .dentry = wh_dentry, ++ .mnt = au_sbr_mnt(dir->i_sb, bindex) ++ }; ++ ++ rerr = au_wh_unlink_dentry(au_h_iptr(dir, bindex), &h_path, dentry); ++ if (!rerr) { ++ au_set_dbwh(dentry, bwh); ++ au_dtime_revert(dt); ++ return 0; ++ } ++ ++ AuIOErr("%pd reverting whiteout failed(%d, %d)\n", dentry, err, rerr); ++ return -EIO; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int aufs_unlink(struct inode *dir, struct dentry *dentry) ++{ ++ int err; ++ aufs_bindex_t bwh, bindex, bstart; ++ struct inode *inode, *h_dir, *delegated; ++ struct dentry *parent, *wh_dentry; ++ /* to reuduce stack size */ ++ struct { ++ struct au_dtime dt; ++ struct au_pin pin; ++ struct path h_path; ++ } *a; ++ ++ IMustLock(dir); ++ ++ err = -ENOMEM; ++ a = kmalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ err = aufs_read_lock(dentry, AuLock_DW | AuLock_GEN); ++ if (unlikely(err)) ++ goto out_free; ++ err = au_d_hashed_positive(dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ inode = dentry->d_inode; ++ IMustLock(inode); ++ err = -EISDIR; ++ if (unlikely(d_is_dir(dentry))) ++ goto out_unlock; /* possible? */ ++ ++ bstart = au_dbstart(dentry); ++ bwh = au_dbwh(dentry); ++ bindex = -1; ++ parent = dentry->d_parent; /* dir inode is locked */ ++ di_write_lock_parent(parent); ++ wh_dentry = lock_hdir_create_wh(dentry, /*isdir*/0, &bindex, &a->dt, ++ &a->pin); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out_parent; ++ ++ a->h_path.mnt = au_sbr_mnt(dentry->d_sb, bstart); ++ a->h_path.dentry = au_h_dptr(dentry, bstart); ++ dget(a->h_path.dentry); ++ if (bindex == bstart) { ++ h_dir = au_pinned_h_dir(&a->pin); ++ delegated = NULL; ++ err = vfsub_unlink(h_dir, &a->h_path, &delegated, /*force*/0); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ } else { ++ /* dir inode is locked */ ++ h_dir = wh_dentry->d_parent->d_inode; ++ IMustLock(h_dir); ++ err = 0; ++ } ++ ++ if (!err) { ++ vfsub_drop_nlink(inode); ++ epilog(dir, dentry, bindex); ++ ++ /* update target timestamps */ ++ if (bindex == bstart) { ++ vfsub_update_h_iattr(&a->h_path, /*did*/NULL); ++ /*ignore*/ ++ inode->i_ctime = a->h_path.dentry->d_inode->i_ctime; ++ } else ++ /* todo: this timestamp may be reverted later */ ++ inode->i_ctime = h_dir->i_ctime; ++ goto out_unpin; /* success */ ++ } ++ ++ /* revert */ ++ if (wh_dentry) { ++ int rerr; ++ ++ rerr = do_revert(err, dir, bindex, bwh, wh_dentry, dentry, ++ &a->dt); ++ if (rerr) ++ err = rerr; ++ } ++ ++out_unpin: ++ au_unpin(&a->pin); ++ dput(wh_dentry); ++ dput(a->h_path.dentry); ++out_parent: ++ di_write_unlock(parent); ++out_unlock: ++ aufs_read_unlock(dentry, AuLock_DW); ++out_free: ++ kfree(a); ++out: ++ return err; ++} ++ ++int aufs_rmdir(struct inode *dir, struct dentry *dentry) ++{ ++ int err, rmdir_later; ++ aufs_bindex_t bwh, bindex, bstart; ++ struct inode *inode; ++ struct dentry *parent, *wh_dentry, *h_dentry; ++ struct au_whtmp_rmdir *args; ++ /* to reuduce stack size */ ++ struct { ++ struct au_dtime dt; ++ struct au_pin pin; ++ } *a; ++ ++ IMustLock(dir); ++ ++ err = -ENOMEM; ++ a = kmalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ err = aufs_read_lock(dentry, AuLock_DW | AuLock_FLUSH | AuLock_GEN); ++ if (unlikely(err)) ++ goto out_free; ++ err = au_alive_dir(dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ inode = dentry->d_inode; ++ IMustLock(inode); ++ err = -ENOTDIR; ++ if (unlikely(!d_is_dir(dentry))) ++ goto out_unlock; /* possible? */ ++ ++ err = -ENOMEM; ++ args = au_whtmp_rmdir_alloc(dir->i_sb, GFP_NOFS); ++ if (unlikely(!args)) ++ goto out_unlock; ++ ++ parent = dentry->d_parent; /* dir inode is locked */ ++ di_write_lock_parent(parent); ++ err = au_test_empty(dentry, &args->whlist); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ bstart = au_dbstart(dentry); ++ bwh = au_dbwh(dentry); ++ bindex = -1; ++ wh_dentry = lock_hdir_create_wh(dentry, /*isdir*/1, &bindex, &a->dt, ++ &a->pin); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out_parent; ++ ++ h_dentry = au_h_dptr(dentry, bstart); ++ dget(h_dentry); ++ rmdir_later = 0; ++ if (bindex == bstart) { ++ err = renwh_and_rmdir(dentry, bstart, &args->whlist, dir); ++ if (err > 0) { ++ rmdir_later = err; ++ err = 0; ++ } ++ } else { ++ /* stop monitoring */ ++ au_hn_free(au_hi(inode, bstart)); ++ ++ /* dir inode is locked */ ++ IMustLock(wh_dentry->d_parent->d_inode); ++ err = 0; ++ } ++ ++ if (!err) { ++ vfsub_dead_dir(inode); ++ au_set_dbdiropq(dentry, -1); ++ epilog(dir, dentry, bindex); ++ ++ if (rmdir_later) { ++ au_whtmp_kick_rmdir(dir, bstart, h_dentry, args); ++ args = NULL; ++ } ++ ++ goto out_unpin; /* success */ ++ } ++ ++ /* revert */ ++ AuLabel(revert); ++ if (wh_dentry) { ++ int rerr; ++ ++ rerr = do_revert(err, dir, bindex, bwh, wh_dentry, dentry, ++ &a->dt); ++ if (rerr) ++ err = rerr; ++ } ++ ++out_unpin: ++ au_unpin(&a->pin); ++ dput(wh_dentry); ++ dput(h_dentry); ++out_parent: ++ di_write_unlock(parent); ++ if (args) ++ au_whtmp_rmdir_free(args); ++out_unlock: ++ aufs_read_unlock(dentry, AuLock_DW); ++out_free: ++ kfree(a); ++out: ++ AuTraceErr(err); ++ return err; ++} +diff --git a/fs/aufs/i_op_ren.c b/fs/aufs/i_op_ren.c +new file mode 100644 +index 0000000..6ce2ed6 +--- /dev/null ++++ b/fs/aufs/i_op_ren.c +@@ -0,0 +1,1013 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * inode operation (rename entry) ++ * todo: this is crazy monster ++ */ ++ ++#include "aufs.h" ++ ++enum { AuSRC, AuDST, AuSrcDst }; ++enum { AuPARENT, AuCHILD, AuParentChild }; ++ ++#define AuRen_ISDIR 1 ++#define AuRen_ISSAMEDIR (1 << 1) ++#define AuRen_WHSRC (1 << 2) ++#define AuRen_WHDST (1 << 3) ++#define AuRen_MNT_WRITE (1 << 4) ++#define AuRen_DT_DSTDIR (1 << 5) ++#define AuRen_DIROPQ (1 << 6) ++#define au_ftest_ren(flags, name) ((flags) & AuRen_##name) ++#define au_fset_ren(flags, name) \ ++ do { (flags) |= AuRen_##name; } while (0) ++#define au_fclr_ren(flags, name) \ ++ do { (flags) &= ~AuRen_##name; } while (0) ++ ++struct au_ren_args { ++ struct { ++ struct dentry *dentry, *h_dentry, *parent, *h_parent, ++ *wh_dentry; ++ struct inode *dir, *inode; ++ struct au_hinode *hdir; ++ struct au_dtime dt[AuParentChild]; ++ aufs_bindex_t bstart; ++ } sd[AuSrcDst]; ++ ++#define src_dentry sd[AuSRC].dentry ++#define src_dir sd[AuSRC].dir ++#define src_inode sd[AuSRC].inode ++#define src_h_dentry sd[AuSRC].h_dentry ++#define src_parent sd[AuSRC].parent ++#define src_h_parent sd[AuSRC].h_parent ++#define src_wh_dentry sd[AuSRC].wh_dentry ++#define src_hdir sd[AuSRC].hdir ++#define src_h_dir sd[AuSRC].hdir->hi_inode ++#define src_dt sd[AuSRC].dt ++#define src_bstart sd[AuSRC].bstart ++ ++#define dst_dentry sd[AuDST].dentry ++#define dst_dir sd[AuDST].dir ++#define dst_inode sd[AuDST].inode ++#define dst_h_dentry sd[AuDST].h_dentry ++#define dst_parent sd[AuDST].parent ++#define dst_h_parent sd[AuDST].h_parent ++#define dst_wh_dentry sd[AuDST].wh_dentry ++#define dst_hdir sd[AuDST].hdir ++#define dst_h_dir sd[AuDST].hdir->hi_inode ++#define dst_dt sd[AuDST].dt ++#define dst_bstart sd[AuDST].bstart ++ ++ struct dentry *h_trap; ++ struct au_branch *br; ++ struct au_hinode *src_hinode; ++ struct path h_path; ++ struct au_nhash whlist; ++ aufs_bindex_t btgt, src_bwh, src_bdiropq; ++ ++ unsigned int flags; ++ ++ struct au_whtmp_rmdir *thargs; ++ struct dentry *h_dst; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * functions for reverting. ++ * when an error happened in a single rename systemcall, we should revert ++ * everything as if nothing happened. ++ * we don't need to revert the copied-up/down the parent dir since they are ++ * harmless. ++ */ ++ ++#define RevertFailure(fmt, ...) do { \ ++ AuIOErr("revert failure: " fmt " (%d, %d)\n", \ ++ ##__VA_ARGS__, err, rerr); \ ++ err = -EIO; \ ++} while (0) ++ ++static void au_ren_rev_diropq(int err, struct au_ren_args *a) ++{ ++ int rerr; ++ ++ au_hn_imtx_lock_nested(a->src_hinode, AuLsc_I_CHILD); ++ rerr = au_diropq_remove(a->src_dentry, a->btgt); ++ au_hn_imtx_unlock(a->src_hinode); ++ au_set_dbdiropq(a->src_dentry, a->src_bdiropq); ++ if (rerr) ++ RevertFailure("remove diropq %pd", a->src_dentry); ++} ++ ++static void au_ren_rev_rename(int err, struct au_ren_args *a) ++{ ++ int rerr; ++ struct inode *delegated; ++ ++ a->h_path.dentry = vfsub_lkup_one(&a->src_dentry->d_name, ++ a->src_h_parent); ++ rerr = PTR_ERR(a->h_path.dentry); ++ if (IS_ERR(a->h_path.dentry)) { ++ RevertFailure("lkup one %pd", a->src_dentry); ++ return; ++ } ++ ++ delegated = NULL; ++ rerr = vfsub_rename(a->dst_h_dir, ++ au_h_dptr(a->src_dentry, a->btgt), ++ a->src_h_dir, &a->h_path, &delegated); ++ if (unlikely(rerr == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal rename\n"); ++ iput(delegated); ++ } ++ d_drop(a->h_path.dentry); ++ dput(a->h_path.dentry); ++ /* au_set_h_dptr(a->src_dentry, a->btgt, NULL); */ ++ if (rerr) ++ RevertFailure("rename %pd", a->src_dentry); ++} ++ ++static void au_ren_rev_whtmp(int err, struct au_ren_args *a) ++{ ++ int rerr; ++ struct inode *delegated; ++ ++ a->h_path.dentry = vfsub_lkup_one(&a->dst_dentry->d_name, ++ a->dst_h_parent); ++ rerr = PTR_ERR(a->h_path.dentry); ++ if (IS_ERR(a->h_path.dentry)) { ++ RevertFailure("lkup one %pd", a->dst_dentry); ++ return; ++ } ++ if (a->h_path.dentry->d_inode) { ++ d_drop(a->h_path.dentry); ++ dput(a->h_path.dentry); ++ return; ++ } ++ ++ delegated = NULL; ++ rerr = vfsub_rename(a->dst_h_dir, a->h_dst, a->dst_h_dir, &a->h_path, ++ &delegated); ++ if (unlikely(rerr == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal rename\n"); ++ iput(delegated); ++ } ++ d_drop(a->h_path.dentry); ++ dput(a->h_path.dentry); ++ if (!rerr) ++ au_set_h_dptr(a->dst_dentry, a->btgt, dget(a->h_dst)); ++ else ++ RevertFailure("rename %pd", a->h_dst); ++} ++ ++static void au_ren_rev_whsrc(int err, struct au_ren_args *a) ++{ ++ int rerr; ++ ++ a->h_path.dentry = a->src_wh_dentry; ++ rerr = au_wh_unlink_dentry(a->src_h_dir, &a->h_path, a->src_dentry); ++ au_set_dbwh(a->src_dentry, a->src_bwh); ++ if (rerr) ++ RevertFailure("unlink %pd", a->src_wh_dentry); ++} ++#undef RevertFailure ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * when we have to copyup the renaming entry, do it with the rename-target name ++ * in order to minimize the cost (the later actual rename is unnecessary). ++ * otherwise rename it on the target branch. ++ */ ++static int au_ren_or_cpup(struct au_ren_args *a) ++{ ++ int err; ++ struct dentry *d; ++ struct inode *delegated; ++ ++ d = a->src_dentry; ++ if (au_dbstart(d) == a->btgt) { ++ a->h_path.dentry = a->dst_h_dentry; ++ if (au_ftest_ren(a->flags, DIROPQ) ++ && au_dbdiropq(d) == a->btgt) ++ au_fclr_ren(a->flags, DIROPQ); ++ AuDebugOn(au_dbstart(d) != a->btgt); ++ delegated = NULL; ++ err = vfsub_rename(a->src_h_dir, au_h_dptr(d, a->btgt), ++ a->dst_h_dir, &a->h_path, &delegated); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal rename\n"); ++ iput(delegated); ++ } ++ } else ++ BUG(); ++ ++ if (!err && a->h_dst) ++ /* it will be set to dinfo later */ ++ dget(a->h_dst); ++ ++ return err; ++} ++ ++/* cf. aufs_rmdir() */ ++static int au_ren_del_whtmp(struct au_ren_args *a) ++{ ++ int err; ++ struct inode *dir; ++ ++ dir = a->dst_dir; ++ SiMustAnyLock(dir->i_sb); ++ if (!au_nhash_test_longer_wh(&a->whlist, a->btgt, ++ au_sbi(dir->i_sb)->si_dirwh) ++ || au_test_fs_remote(a->h_dst->d_sb)) { ++ err = au_whtmp_rmdir(dir, a->btgt, a->h_dst, &a->whlist); ++ if (unlikely(err)) ++ pr_warn("failed removing whtmp dir %pd (%d), " ++ "ignored.\n", a->h_dst, err); ++ } else { ++ au_nhash_wh_free(&a->thargs->whlist); ++ a->thargs->whlist = a->whlist; ++ a->whlist.nh_num = 0; ++ au_whtmp_kick_rmdir(dir, a->btgt, a->h_dst, a->thargs); ++ dput(a->h_dst); ++ a->thargs = NULL; ++ } ++ ++ return 0; ++} ++ ++/* make it 'opaque' dir. */ ++static int au_ren_diropq(struct au_ren_args *a) ++{ ++ int err; ++ struct dentry *diropq; ++ ++ err = 0; ++ a->src_bdiropq = au_dbdiropq(a->src_dentry); ++ a->src_hinode = au_hi(a->src_inode, a->btgt); ++ au_hn_imtx_lock_nested(a->src_hinode, AuLsc_I_CHILD); ++ diropq = au_diropq_create(a->src_dentry, a->btgt); ++ au_hn_imtx_unlock(a->src_hinode); ++ if (IS_ERR(diropq)) ++ err = PTR_ERR(diropq); ++ else ++ dput(diropq); ++ ++ return err; ++} ++ ++static int do_rename(struct au_ren_args *a) ++{ ++ int err; ++ struct dentry *d, *h_d; ++ ++ /* prepare workqueue args for asynchronous rmdir */ ++ h_d = a->dst_h_dentry; ++ if (au_ftest_ren(a->flags, ISDIR) && h_d->d_inode) { ++ err = -ENOMEM; ++ a->thargs = au_whtmp_rmdir_alloc(a->src_dentry->d_sb, GFP_NOFS); ++ if (unlikely(!a->thargs)) ++ goto out; ++ a->h_dst = dget(h_d); ++ } ++ ++ /* create whiteout for src_dentry */ ++ if (au_ftest_ren(a->flags, WHSRC)) { ++ a->src_bwh = au_dbwh(a->src_dentry); ++ AuDebugOn(a->src_bwh >= 0); ++ a->src_wh_dentry ++ = au_wh_create(a->src_dentry, a->btgt, a->src_h_parent); ++ err = PTR_ERR(a->src_wh_dentry); ++ if (IS_ERR(a->src_wh_dentry)) ++ goto out_thargs; ++ } ++ ++ /* lookup whiteout for dentry */ ++ if (au_ftest_ren(a->flags, WHDST)) { ++ h_d = au_wh_lkup(a->dst_h_parent, &a->dst_dentry->d_name, ++ a->br); ++ err = PTR_ERR(h_d); ++ if (IS_ERR(h_d)) ++ goto out_whsrc; ++ if (!h_d->d_inode) ++ dput(h_d); ++ else ++ a->dst_wh_dentry = h_d; ++ } ++ ++ /* rename dentry to tmpwh */ ++ if (a->thargs) { ++ err = au_whtmp_ren(a->dst_h_dentry, a->br); ++ if (unlikely(err)) ++ goto out_whdst; ++ ++ d = a->dst_dentry; ++ au_set_h_dptr(d, a->btgt, NULL); ++ err = au_lkup_neg(d, a->btgt, /*wh*/0); ++ if (unlikely(err)) ++ goto out_whtmp; ++ a->dst_h_dentry = au_h_dptr(d, a->btgt); ++ } ++ ++ BUG_ON(a->dst_h_dentry->d_inode && a->src_bstart != a->btgt); ++ ++ /* rename by vfs_rename or cpup */ ++ d = a->dst_dentry; ++ if (au_ftest_ren(a->flags, ISDIR) ++ && (a->dst_wh_dentry ++ || au_dbdiropq(d) == a->btgt ++ /* hide the lower to keep xino */ ++ || a->btgt < au_dbend(d) ++ || au_opt_test(au_mntflags(d->d_sb), ALWAYS_DIROPQ))) ++ au_fset_ren(a->flags, DIROPQ); ++ err = au_ren_or_cpup(a); ++ if (unlikely(err)) ++ /* leave the copied-up one */ ++ goto out_whtmp; ++ ++ /* make dir opaque */ ++ if (au_ftest_ren(a->flags, DIROPQ)) { ++ err = au_ren_diropq(a); ++ if (unlikely(err)) ++ goto out_rename; ++ } ++ ++ /* update target timestamps */ ++ AuDebugOn(au_dbstart(a->src_dentry) != a->btgt); ++ a->h_path.dentry = au_h_dptr(a->src_dentry, a->btgt); ++ vfsub_update_h_iattr(&a->h_path, /*did*/NULL); /*ignore*/ ++ a->src_inode->i_ctime = a->h_path.dentry->d_inode->i_ctime; ++ ++ /* remove whiteout for dentry */ ++ if (a->dst_wh_dentry) { ++ a->h_path.dentry = a->dst_wh_dentry; ++ err = au_wh_unlink_dentry(a->dst_h_dir, &a->h_path, ++ a->dst_dentry); ++ if (unlikely(err)) ++ goto out_diropq; ++ } ++ ++ /* remove whtmp */ ++ if (a->thargs) ++ au_ren_del_whtmp(a); /* ignore this error */ ++ ++ au_fhsm_wrote(a->src_dentry->d_sb, a->btgt, /*force*/0); ++ err = 0; ++ goto out_success; ++ ++out_diropq: ++ if (au_ftest_ren(a->flags, DIROPQ)) ++ au_ren_rev_diropq(err, a); ++out_rename: ++ au_ren_rev_rename(err, a); ++ dput(a->h_dst); ++out_whtmp: ++ if (a->thargs) ++ au_ren_rev_whtmp(err, a); ++out_whdst: ++ dput(a->dst_wh_dentry); ++ a->dst_wh_dentry = NULL; ++out_whsrc: ++ if (a->src_wh_dentry) ++ au_ren_rev_whsrc(err, a); ++out_success: ++ dput(a->src_wh_dentry); ++ dput(a->dst_wh_dentry); ++out_thargs: ++ if (a->thargs) { ++ dput(a->h_dst); ++ au_whtmp_rmdir_free(a->thargs); ++ a->thargs = NULL; ++ } ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * test if @dentry dir can be rename destination or not. ++ * success means, it is a logically empty dir. ++ */ ++static int may_rename_dstdir(struct dentry *dentry, struct au_nhash *whlist) ++{ ++ return au_test_empty(dentry, whlist); ++} ++ ++/* ++ * test if @dentry dir can be rename source or not. ++ * if it can, return 0 and @children is filled. ++ * success means, ++ * - it is a logically empty dir. ++ * - or, it exists on writable branch and has no children including whiteouts ++ * on the lower branch. ++ */ ++static int may_rename_srcdir(struct dentry *dentry, aufs_bindex_t btgt) ++{ ++ int err; ++ unsigned int rdhash; ++ aufs_bindex_t bstart; ++ ++ bstart = au_dbstart(dentry); ++ if (bstart != btgt) { ++ struct au_nhash whlist; ++ ++ SiMustAnyLock(dentry->d_sb); ++ rdhash = au_sbi(dentry->d_sb)->si_rdhash; ++ if (!rdhash) ++ rdhash = au_rdhash_est(au_dir_size(/*file*/NULL, ++ dentry)); ++ err = au_nhash_alloc(&whlist, rdhash, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ err = au_test_empty(dentry, &whlist); ++ au_nhash_wh_free(&whlist); ++ goto out; ++ } ++ ++ if (bstart == au_dbtaildir(dentry)) ++ return 0; /* success */ ++ ++ err = au_test_empty_lower(dentry); ++ ++out: ++ if (err == -ENOTEMPTY) { ++ AuWarn1("renaming dir who has child(ren) on multiple branches," ++ " is not supported\n"); ++ err = -EXDEV; ++ } ++ return err; ++} ++ ++/* side effect: sets whlist and h_dentry */ ++static int au_ren_may_dir(struct au_ren_args *a) ++{ ++ int err; ++ unsigned int rdhash; ++ struct dentry *d; ++ ++ d = a->dst_dentry; ++ SiMustAnyLock(d->d_sb); ++ ++ err = 0; ++ if (au_ftest_ren(a->flags, ISDIR) && a->dst_inode) { ++ rdhash = au_sbi(d->d_sb)->si_rdhash; ++ if (!rdhash) ++ rdhash = au_rdhash_est(au_dir_size(/*file*/NULL, d)); ++ err = au_nhash_alloc(&a->whlist, rdhash, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ ++ au_set_dbstart(d, a->dst_bstart); ++ err = may_rename_dstdir(d, &a->whlist); ++ au_set_dbstart(d, a->btgt); ++ } ++ a->dst_h_dentry = au_h_dptr(d, au_dbstart(d)); ++ if (unlikely(err)) ++ goto out; ++ ++ d = a->src_dentry; ++ a->src_h_dentry = au_h_dptr(d, au_dbstart(d)); ++ if (au_ftest_ren(a->flags, ISDIR)) { ++ err = may_rename_srcdir(d, a->btgt); ++ if (unlikely(err)) { ++ au_nhash_wh_free(&a->whlist); ++ a->whlist.nh_num = 0; ++ } ++ } ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * simple tests for rename. ++ * following the checks in vfs, plus the parent-child relationship. ++ */ ++static int au_may_ren(struct au_ren_args *a) ++{ ++ int err, isdir; ++ struct inode *h_inode; ++ ++ if (a->src_bstart == a->btgt) { ++ err = au_may_del(a->src_dentry, a->btgt, a->src_h_parent, ++ au_ftest_ren(a->flags, ISDIR)); ++ if (unlikely(err)) ++ goto out; ++ err = -EINVAL; ++ if (unlikely(a->src_h_dentry == a->h_trap)) ++ goto out; ++ } ++ ++ err = 0; ++ if (a->dst_bstart != a->btgt) ++ goto out; ++ ++ err = -ENOTEMPTY; ++ if (unlikely(a->dst_h_dentry == a->h_trap)) ++ goto out; ++ ++ err = -EIO; ++ h_inode = a->dst_h_dentry->d_inode; ++ isdir = !!au_ftest_ren(a->flags, ISDIR); ++ if (!a->dst_dentry->d_inode) { ++ if (unlikely(h_inode)) ++ goto out; ++ err = au_may_add(a->dst_dentry, a->btgt, a->dst_h_parent, ++ isdir); ++ } else { ++ if (unlikely(!h_inode || !h_inode->i_nlink)) ++ goto out; ++ err = au_may_del(a->dst_dentry, a->btgt, a->dst_h_parent, ++ isdir); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++out: ++ if (unlikely(err == -ENOENT || err == -EEXIST)) ++ err = -EIO; ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * locking order ++ * (VFS) ++ * - src_dir and dir by lock_rename() ++ * - inode if exitsts ++ * (aufs) ++ * - lock all ++ * + src_dentry and dentry by aufs_read_and_write_lock2() which calls, ++ * + si_read_lock ++ * + di_write_lock2_child() ++ * + di_write_lock_child() ++ * + ii_write_lock_child() ++ * + di_write_lock_child2() ++ * + ii_write_lock_child2() ++ * + src_parent and parent ++ * + di_write_lock_parent() ++ * + ii_write_lock_parent() ++ * + di_write_lock_parent2() ++ * + ii_write_lock_parent2() ++ * + lower src_dir and dir by vfsub_lock_rename() ++ * + verify the every relationships between child and parent. if any ++ * of them failed, unlock all and return -EBUSY. ++ */ ++static void au_ren_unlock(struct au_ren_args *a) ++{ ++ vfsub_unlock_rename(a->src_h_parent, a->src_hdir, ++ a->dst_h_parent, a->dst_hdir); ++ if (au_ftest_ren(a->flags, MNT_WRITE)) ++ vfsub_mnt_drop_write(au_br_mnt(a->br)); ++} ++ ++static int au_ren_lock(struct au_ren_args *a) ++{ ++ int err; ++ unsigned int udba; ++ ++ err = 0; ++ a->src_h_parent = au_h_dptr(a->src_parent, a->btgt); ++ a->src_hdir = au_hi(a->src_dir, a->btgt); ++ a->dst_h_parent = au_h_dptr(a->dst_parent, a->btgt); ++ a->dst_hdir = au_hi(a->dst_dir, a->btgt); ++ ++ err = vfsub_mnt_want_write(au_br_mnt(a->br)); ++ if (unlikely(err)) ++ goto out; ++ au_fset_ren(a->flags, MNT_WRITE); ++ a->h_trap = vfsub_lock_rename(a->src_h_parent, a->src_hdir, ++ a->dst_h_parent, a->dst_hdir); ++ udba = au_opt_udba(a->src_dentry->d_sb); ++ if (unlikely(a->src_hdir->hi_inode != a->src_h_parent->d_inode ++ || a->dst_hdir->hi_inode != a->dst_h_parent->d_inode)) ++ err = au_busy_or_stale(); ++ if (!err && au_dbstart(a->src_dentry) == a->btgt) ++ err = au_h_verify(a->src_h_dentry, udba, ++ a->src_h_parent->d_inode, a->src_h_parent, ++ a->br); ++ if (!err && au_dbstart(a->dst_dentry) == a->btgt) ++ err = au_h_verify(a->dst_h_dentry, udba, ++ a->dst_h_parent->d_inode, a->dst_h_parent, ++ a->br); ++ if (!err) ++ goto out; /* success */ ++ ++ err = au_busy_or_stale(); ++ au_ren_unlock(a); ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_ren_refresh_dir(struct au_ren_args *a) ++{ ++ struct inode *dir; ++ ++ dir = a->dst_dir; ++ dir->i_version++; ++ if (au_ftest_ren(a->flags, ISDIR)) { ++ /* is this updating defined in POSIX? */ ++ au_cpup_attr_timesizes(a->src_inode); ++ au_cpup_attr_nlink(dir, /*force*/1); ++ } ++ ++ au_dir_ts(dir, a->btgt); ++ ++ if (au_ftest_ren(a->flags, ISSAMEDIR)) ++ return; ++ ++ dir = a->src_dir; ++ dir->i_version++; ++ if (au_ftest_ren(a->flags, ISDIR)) ++ au_cpup_attr_nlink(dir, /*force*/1); ++ au_dir_ts(dir, a->btgt); ++} ++ ++static void au_ren_refresh(struct au_ren_args *a) ++{ ++ aufs_bindex_t bend, bindex; ++ struct dentry *d, *h_d; ++ struct inode *i, *h_i; ++ struct super_block *sb; ++ ++ d = a->dst_dentry; ++ d_drop(d); ++ if (a->h_dst) ++ /* already dget-ed by au_ren_or_cpup() */ ++ au_set_h_dptr(d, a->btgt, a->h_dst); ++ ++ i = a->dst_inode; ++ if (i) { ++ if (!au_ftest_ren(a->flags, ISDIR)) ++ vfsub_drop_nlink(i); ++ else { ++ vfsub_dead_dir(i); ++ au_cpup_attr_timesizes(i); ++ } ++ au_update_dbrange(d, /*do_put_zero*/1); ++ } else { ++ bend = a->btgt; ++ for (bindex = au_dbstart(d); bindex < bend; bindex++) ++ au_set_h_dptr(d, bindex, NULL); ++ bend = au_dbend(d); ++ for (bindex = a->btgt + 1; bindex <= bend; bindex++) ++ au_set_h_dptr(d, bindex, NULL); ++ au_update_dbrange(d, /*do_put_zero*/0); ++ } ++ ++ d = a->src_dentry; ++ au_set_dbwh(d, -1); ++ bend = au_dbend(d); ++ for (bindex = a->btgt + 1; bindex <= bend; bindex++) { ++ h_d = au_h_dptr(d, bindex); ++ if (h_d) ++ au_set_h_dptr(d, bindex, NULL); ++ } ++ au_set_dbend(d, a->btgt); ++ ++ sb = d->d_sb; ++ i = a->src_inode; ++ if (au_opt_test(au_mntflags(sb), PLINK) && au_plink_test(i)) ++ return; /* success */ ++ ++ bend = au_ibend(i); ++ for (bindex = a->btgt + 1; bindex <= bend; bindex++) { ++ h_i = au_h_iptr(i, bindex); ++ if (h_i) { ++ au_xino_write(sb, bindex, h_i->i_ino, /*ino*/0); ++ /* ignore this error */ ++ au_set_h_iptr(i, bindex, NULL, 0); ++ } ++ } ++ au_set_ibend(i, a->btgt); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* mainly for link(2) and rename(2) */ ++int au_wbr(struct dentry *dentry, aufs_bindex_t btgt) ++{ ++ aufs_bindex_t bdiropq, bwh; ++ struct dentry *parent; ++ struct au_branch *br; ++ ++ parent = dentry->d_parent; ++ IMustLock(parent->d_inode); /* dir is locked */ ++ ++ bdiropq = au_dbdiropq(parent); ++ bwh = au_dbwh(dentry); ++ br = au_sbr(dentry->d_sb, btgt); ++ if (au_br_rdonly(br) ++ || (0 <= bdiropq && bdiropq < btgt) ++ || (0 <= bwh && bwh < btgt)) ++ btgt = -1; ++ ++ AuDbg("btgt %d\n", btgt); ++ return btgt; ++} ++ ++/* sets src_bstart, dst_bstart and btgt */ ++static int au_ren_wbr(struct au_ren_args *a) ++{ ++ int err; ++ struct au_wr_dir_args wr_dir_args = { ++ /* .force_btgt = -1, */ ++ .flags = AuWrDir_ADD_ENTRY ++ }; ++ ++ a->src_bstart = au_dbstart(a->src_dentry); ++ a->dst_bstart = au_dbstart(a->dst_dentry); ++ if (au_ftest_ren(a->flags, ISDIR)) ++ au_fset_wrdir(wr_dir_args.flags, ISDIR); ++ wr_dir_args.force_btgt = a->src_bstart; ++ if (a->dst_inode && a->dst_bstart < a->src_bstart) ++ wr_dir_args.force_btgt = a->dst_bstart; ++ wr_dir_args.force_btgt = au_wbr(a->dst_dentry, wr_dir_args.force_btgt); ++ err = au_wr_dir(a->dst_dentry, a->src_dentry, &wr_dir_args); ++ a->btgt = err; ++ ++ return err; ++} ++ ++static void au_ren_dt(struct au_ren_args *a) ++{ ++ a->h_path.dentry = a->src_h_parent; ++ au_dtime_store(a->src_dt + AuPARENT, a->src_parent, &a->h_path); ++ if (!au_ftest_ren(a->flags, ISSAMEDIR)) { ++ a->h_path.dentry = a->dst_h_parent; ++ au_dtime_store(a->dst_dt + AuPARENT, a->dst_parent, &a->h_path); ++ } ++ ++ au_fclr_ren(a->flags, DT_DSTDIR); ++ if (!au_ftest_ren(a->flags, ISDIR)) ++ return; ++ ++ a->h_path.dentry = a->src_h_dentry; ++ au_dtime_store(a->src_dt + AuCHILD, a->src_dentry, &a->h_path); ++ if (a->dst_h_dentry->d_inode) { ++ au_fset_ren(a->flags, DT_DSTDIR); ++ a->h_path.dentry = a->dst_h_dentry; ++ au_dtime_store(a->dst_dt + AuCHILD, a->dst_dentry, &a->h_path); ++ } ++} ++ ++static void au_ren_rev_dt(int err, struct au_ren_args *a) ++{ ++ struct dentry *h_d; ++ struct mutex *h_mtx; ++ ++ au_dtime_revert(a->src_dt + AuPARENT); ++ if (!au_ftest_ren(a->flags, ISSAMEDIR)) ++ au_dtime_revert(a->dst_dt + AuPARENT); ++ ++ if (au_ftest_ren(a->flags, ISDIR) && err != -EIO) { ++ h_d = a->src_dt[AuCHILD].dt_h_path.dentry; ++ h_mtx = &h_d->d_inode->i_mutex; ++ mutex_lock_nested(h_mtx, AuLsc_I_CHILD); ++ au_dtime_revert(a->src_dt + AuCHILD); ++ mutex_unlock(h_mtx); ++ ++ if (au_ftest_ren(a->flags, DT_DSTDIR)) { ++ h_d = a->dst_dt[AuCHILD].dt_h_path.dentry; ++ h_mtx = &h_d->d_inode->i_mutex; ++ mutex_lock_nested(h_mtx, AuLsc_I_CHILD); ++ au_dtime_revert(a->dst_dt + AuCHILD); ++ mutex_unlock(h_mtx); ++ } ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int aufs_rename(struct inode *_src_dir, struct dentry *_src_dentry, ++ struct inode *_dst_dir, struct dentry *_dst_dentry) ++{ ++ int err, flags; ++ /* reduce stack space */ ++ struct au_ren_args *a; ++ ++ AuDbg("%pd, %pd\n", _src_dentry, _dst_dentry); ++ IMustLock(_src_dir); ++ IMustLock(_dst_dir); ++ ++ err = -ENOMEM; ++ BUILD_BUG_ON(sizeof(*a) > PAGE_SIZE); ++ a = kzalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ a->src_dir = _src_dir; ++ a->src_dentry = _src_dentry; ++ a->src_inode = a->src_dentry->d_inode; ++ a->src_parent = a->src_dentry->d_parent; /* dir inode is locked */ ++ a->dst_dir = _dst_dir; ++ a->dst_dentry = _dst_dentry; ++ a->dst_inode = a->dst_dentry->d_inode; ++ a->dst_parent = a->dst_dentry->d_parent; /* dir inode is locked */ ++ if (a->dst_inode) { ++ IMustLock(a->dst_inode); ++ au_igrab(a->dst_inode); ++ } ++ ++ err = -ENOTDIR; ++ flags = AuLock_FLUSH | AuLock_NOPLM | AuLock_GEN; ++ if (d_is_dir(a->src_dentry)) { ++ au_fset_ren(a->flags, ISDIR); ++ if (unlikely(d_is_positive(a->dst_dentry) ++ && !d_is_dir(a->dst_dentry))) ++ goto out_free; ++ flags |= AuLock_DIRS; ++ } ++ err = aufs_read_and_write_lock2(a->dst_dentry, a->src_dentry, flags); ++ if (unlikely(err)) ++ goto out_free; ++ ++ err = au_d_hashed_positive(a->src_dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ err = -ENOENT; ++ if (a->dst_inode) { ++ /* ++ * If it is a dir, VFS unhash dst_dentry before this ++ * function. It means we cannot rely upon d_unhashed(). ++ */ ++ if (unlikely(!a->dst_inode->i_nlink)) ++ goto out_unlock; ++ if (!S_ISDIR(a->dst_inode->i_mode)) { ++ err = au_d_hashed_positive(a->dst_dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ } else if (unlikely(IS_DEADDIR(a->dst_inode))) ++ goto out_unlock; ++ } else if (unlikely(d_unhashed(a->dst_dentry))) ++ goto out_unlock; ++ ++ /* ++ * is it possible? ++ * yes, it happened (in linux-3.3-rcN) but I don't know why. ++ * there may exist a problem somewhere else. ++ */ ++ err = -EINVAL; ++ if (unlikely(a->dst_parent->d_inode == a->src_dentry->d_inode)) ++ goto out_unlock; ++ ++ au_fset_ren(a->flags, ISSAMEDIR); /* temporary */ ++ di_write_lock_parent(a->dst_parent); ++ ++ /* which branch we process */ ++ err = au_ren_wbr(a); ++ if (unlikely(err < 0)) ++ goto out_parent; ++ a->br = au_sbr(a->dst_dentry->d_sb, a->btgt); ++ a->h_path.mnt = au_br_mnt(a->br); ++ ++ /* are they available to be renamed */ ++ err = au_ren_may_dir(a); ++ if (unlikely(err)) ++ goto out_children; ++ ++ /* prepare the writable parent dir on the same branch */ ++ if (a->dst_bstart == a->btgt) { ++ au_fset_ren(a->flags, WHDST); ++ } else { ++ err = au_cpup_dirs(a->dst_dentry, a->btgt); ++ if (unlikely(err)) ++ goto out_children; ++ } ++ ++ if (a->src_dir != a->dst_dir) { ++ /* ++ * this temporary unlock is safe, ++ * because both dir->i_mutex are locked. ++ */ ++ di_write_unlock(a->dst_parent); ++ di_write_lock_parent(a->src_parent); ++ err = au_wr_dir_need_wh(a->src_dentry, ++ au_ftest_ren(a->flags, ISDIR), ++ &a->btgt); ++ di_write_unlock(a->src_parent); ++ di_write_lock2_parent(a->src_parent, a->dst_parent, /*isdir*/1); ++ au_fclr_ren(a->flags, ISSAMEDIR); ++ } else ++ err = au_wr_dir_need_wh(a->src_dentry, ++ au_ftest_ren(a->flags, ISDIR), ++ &a->btgt); ++ if (unlikely(err < 0)) ++ goto out_children; ++ if (err) ++ au_fset_ren(a->flags, WHSRC); ++ ++ /* cpup src */ ++ if (a->src_bstart != a->btgt) { ++ struct au_pin pin; ++ ++ err = au_pin(&pin, a->src_dentry, a->btgt, ++ au_opt_udba(a->src_dentry->d_sb), ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (!err) { ++ struct au_cp_generic cpg = { ++ .dentry = a->src_dentry, ++ .bdst = a->btgt, ++ .bsrc = a->src_bstart, ++ .len = -1, ++ .pin = &pin, ++ .flags = AuCpup_DTIME | AuCpup_HOPEN ++ }; ++ AuDebugOn(au_dbstart(a->src_dentry) != a->src_bstart); ++ err = au_sio_cpup_simple(&cpg); ++ au_unpin(&pin); ++ } ++ if (unlikely(err)) ++ goto out_children; ++ a->src_bstart = a->btgt; ++ a->src_h_dentry = au_h_dptr(a->src_dentry, a->btgt); ++ au_fset_ren(a->flags, WHSRC); ++ } ++ ++ /* lock them all */ ++ err = au_ren_lock(a); ++ if (unlikely(err)) ++ /* leave the copied-up one */ ++ goto out_children; ++ ++ if (!au_opt_test(au_mntflags(a->dst_dir->i_sb), UDBA_NONE)) ++ err = au_may_ren(a); ++ else if (unlikely(a->dst_dentry->d_name.len > AUFS_MAX_NAMELEN)) ++ err = -ENAMETOOLONG; ++ if (unlikely(err)) ++ goto out_hdir; ++ ++ /* store timestamps to be revertible */ ++ au_ren_dt(a); ++ ++ /* here we go */ ++ err = do_rename(a); ++ if (unlikely(err)) ++ goto out_dt; ++ ++ /* update dir attributes */ ++ au_ren_refresh_dir(a); ++ ++ /* dput/iput all lower dentries */ ++ au_ren_refresh(a); ++ ++ goto out_hdir; /* success */ ++ ++out_dt: ++ au_ren_rev_dt(err, a); ++out_hdir: ++ au_ren_unlock(a); ++out_children: ++ au_nhash_wh_free(&a->whlist); ++ if (err && a->dst_inode && a->dst_bstart != a->btgt) { ++ AuDbg("bstart %d, btgt %d\n", a->dst_bstart, a->btgt); ++ au_set_h_dptr(a->dst_dentry, a->btgt, NULL); ++ au_set_dbstart(a->dst_dentry, a->dst_bstart); ++ } ++out_parent: ++ if (!err) ++ d_move(a->src_dentry, a->dst_dentry); ++ else { ++ au_update_dbstart(a->dst_dentry); ++ if (!a->dst_inode) ++ d_drop(a->dst_dentry); ++ } ++ if (au_ftest_ren(a->flags, ISSAMEDIR)) ++ di_write_unlock(a->dst_parent); ++ else ++ di_write_unlock2(a->src_parent, a->dst_parent); ++out_unlock: ++ aufs_read_and_write_unlock2(a->dst_dentry, a->src_dentry); ++out_free: ++ iput(a->dst_inode); ++ if (a->thargs) ++ au_whtmp_rmdir_free(a->thargs); ++ kfree(a); ++out: ++ AuTraceErr(err); ++ return err; ++} +diff --git a/fs/aufs/iinfo.c b/fs/aufs/iinfo.c +new file mode 100644 +index 0000000..f889aba +--- /dev/null ++++ b/fs/aufs/iinfo.c +@@ -0,0 +1,277 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * inode private data ++ */ ++ ++#include "aufs.h" ++ ++struct inode *au_h_iptr(struct inode *inode, aufs_bindex_t bindex) ++{ ++ struct inode *h_inode; ++ ++ IiMustAnyLock(inode); ++ ++ h_inode = au_ii(inode)->ii_hinode[0 + bindex].hi_inode; ++ AuDebugOn(h_inode && atomic_read(&h_inode->i_count) <= 0); ++ return h_inode; ++} ++ ++/* todo: hard/soft set? */ ++void au_hiput(struct au_hinode *hinode) ++{ ++ au_hn_free(hinode); ++ dput(hinode->hi_whdentry); ++ iput(hinode->hi_inode); ++} ++ ++unsigned int au_hi_flags(struct inode *inode, int isdir) ++{ ++ unsigned int flags; ++ const unsigned int mnt_flags = au_mntflags(inode->i_sb); ++ ++ flags = 0; ++ if (au_opt_test(mnt_flags, XINO)) ++ au_fset_hi(flags, XINO); ++ if (isdir && au_opt_test(mnt_flags, UDBA_HNOTIFY)) ++ au_fset_hi(flags, HNOTIFY); ++ return flags; ++} ++ ++void au_set_h_iptr(struct inode *inode, aufs_bindex_t bindex, ++ struct inode *h_inode, unsigned int flags) ++{ ++ struct au_hinode *hinode; ++ struct inode *hi; ++ struct au_iinfo *iinfo = au_ii(inode); ++ ++ IiMustWriteLock(inode); ++ ++ hinode = iinfo->ii_hinode + bindex; ++ hi = hinode->hi_inode; ++ AuDebugOn(h_inode && atomic_read(&h_inode->i_count) <= 0); ++ ++ if (hi) ++ au_hiput(hinode); ++ hinode->hi_inode = h_inode; ++ if (h_inode) { ++ int err; ++ struct super_block *sb = inode->i_sb; ++ struct au_branch *br; ++ ++ AuDebugOn(inode->i_mode ++ && (h_inode->i_mode & S_IFMT) ++ != (inode->i_mode & S_IFMT)); ++ if (bindex == iinfo->ii_bstart) ++ au_cpup_igen(inode, h_inode); ++ br = au_sbr(sb, bindex); ++ hinode->hi_id = br->br_id; ++ if (au_ftest_hi(flags, XINO)) { ++ err = au_xino_write(sb, bindex, h_inode->i_ino, ++ inode->i_ino); ++ if (unlikely(err)) ++ AuIOErr1("failed au_xino_write() %d\n", err); ++ } ++ ++ if (au_ftest_hi(flags, HNOTIFY) ++ && au_br_hnotifyable(br->br_perm)) { ++ err = au_hn_alloc(hinode, inode); ++ if (unlikely(err)) ++ AuIOErr1("au_hn_alloc() %d\n", err); ++ } ++ } ++} ++ ++void au_set_hi_wh(struct inode *inode, aufs_bindex_t bindex, ++ struct dentry *h_wh) ++{ ++ struct au_hinode *hinode; ++ ++ IiMustWriteLock(inode); ++ ++ hinode = au_ii(inode)->ii_hinode + bindex; ++ AuDebugOn(hinode->hi_whdentry); ++ hinode->hi_whdentry = h_wh; ++} ++ ++void au_update_iigen(struct inode *inode, int half) ++{ ++ struct au_iinfo *iinfo; ++ struct au_iigen *iigen; ++ unsigned int sigen; ++ ++ sigen = au_sigen(inode->i_sb); ++ iinfo = au_ii(inode); ++ iigen = &iinfo->ii_generation; ++ spin_lock(&iigen->ig_spin); ++ iigen->ig_generation = sigen; ++ if (half) ++ au_ig_fset(iigen->ig_flags, HALF_REFRESHED); ++ else ++ au_ig_fclr(iigen->ig_flags, HALF_REFRESHED); ++ spin_unlock(&iigen->ig_spin); ++} ++ ++/* it may be called at remount time, too */ ++void au_update_ibrange(struct inode *inode, int do_put_zero) ++{ ++ struct au_iinfo *iinfo; ++ aufs_bindex_t bindex, bend; ++ ++ iinfo = au_ii(inode); ++ if (!iinfo) ++ return; ++ ++ IiMustWriteLock(inode); ++ ++ if (do_put_zero && iinfo->ii_bstart >= 0) { ++ for (bindex = iinfo->ii_bstart; bindex <= iinfo->ii_bend; ++ bindex++) { ++ struct inode *h_i; ++ ++ h_i = iinfo->ii_hinode[0 + bindex].hi_inode; ++ if (h_i ++ && !h_i->i_nlink ++ && !(h_i->i_state & I_LINKABLE)) ++ au_set_h_iptr(inode, bindex, NULL, 0); ++ } ++ } ++ ++ iinfo->ii_bstart = -1; ++ iinfo->ii_bend = -1; ++ bend = au_sbend(inode->i_sb); ++ for (bindex = 0; bindex <= bend; bindex++) ++ if (iinfo->ii_hinode[0 + bindex].hi_inode) { ++ iinfo->ii_bstart = bindex; ++ break; ++ } ++ if (iinfo->ii_bstart >= 0) ++ for (bindex = bend; bindex >= iinfo->ii_bstart; bindex--) ++ if (iinfo->ii_hinode[0 + bindex].hi_inode) { ++ iinfo->ii_bend = bindex; ++ break; ++ } ++ AuDebugOn(iinfo->ii_bstart > iinfo->ii_bend); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_icntnr_init_once(void *_c) ++{ ++ struct au_icntnr *c = _c; ++ struct au_iinfo *iinfo = &c->iinfo; ++ static struct lock_class_key aufs_ii; ++ ++ spin_lock_init(&iinfo->ii_generation.ig_spin); ++ au_rw_init(&iinfo->ii_rwsem); ++ au_rw_class(&iinfo->ii_rwsem, &aufs_ii); ++ inode_init_once(&c->vfs_inode); ++} ++ ++int au_iinfo_init(struct inode *inode) ++{ ++ struct au_iinfo *iinfo; ++ struct super_block *sb; ++ int nbr, i; ++ ++ sb = inode->i_sb; ++ iinfo = &(container_of(inode, struct au_icntnr, vfs_inode)->iinfo); ++ nbr = au_sbend(sb) + 1; ++ if (unlikely(nbr <= 0)) ++ nbr = 1; ++ iinfo->ii_hinode = kcalloc(nbr, sizeof(*iinfo->ii_hinode), GFP_NOFS); ++ if (iinfo->ii_hinode) { ++ au_ninodes_inc(sb); ++ for (i = 0; i < nbr; i++) ++ iinfo->ii_hinode[i].hi_id = -1; ++ ++ iinfo->ii_generation.ig_generation = au_sigen(sb); ++ iinfo->ii_bstart = -1; ++ iinfo->ii_bend = -1; ++ iinfo->ii_vdir = NULL; ++ return 0; ++ } ++ return -ENOMEM; ++} ++ ++int au_ii_realloc(struct au_iinfo *iinfo, int nbr) ++{ ++ int err, sz; ++ struct au_hinode *hip; ++ ++ AuRwMustWriteLock(&iinfo->ii_rwsem); ++ ++ err = -ENOMEM; ++ sz = sizeof(*hip) * (iinfo->ii_bend + 1); ++ if (!sz) ++ sz = sizeof(*hip); ++ hip = au_kzrealloc(iinfo->ii_hinode, sz, sizeof(*hip) * nbr, GFP_NOFS); ++ if (hip) { ++ iinfo->ii_hinode = hip; ++ err = 0; ++ } ++ ++ return err; ++} ++ ++void au_iinfo_fin(struct inode *inode) ++{ ++ struct au_iinfo *iinfo; ++ struct au_hinode *hi; ++ struct super_block *sb; ++ aufs_bindex_t bindex, bend; ++ const unsigned char unlinked = !inode->i_nlink; ++ ++ iinfo = au_ii(inode); ++ /* bad_inode case */ ++ if (!iinfo) ++ return; ++ ++ sb = inode->i_sb; ++ au_ninodes_dec(sb); ++ if (si_pid_test(sb)) ++ au_xino_delete_inode(inode, unlinked); ++ else { ++ /* ++ * it is safe to hide the dependency between sbinfo and ++ * sb->s_umount. ++ */ ++ lockdep_off(); ++ si_noflush_read_lock(sb); ++ au_xino_delete_inode(inode, unlinked); ++ si_read_unlock(sb); ++ lockdep_on(); ++ } ++ ++ if (iinfo->ii_vdir) ++ au_vdir_free(iinfo->ii_vdir); ++ ++ bindex = iinfo->ii_bstart; ++ if (bindex >= 0) { ++ hi = iinfo->ii_hinode + bindex; ++ bend = iinfo->ii_bend; ++ while (bindex++ <= bend) { ++ if (hi->hi_inode) ++ au_hiput(hi); ++ hi++; ++ } ++ } ++ kfree(iinfo->ii_hinode); ++ iinfo->ii_hinode = NULL; ++ AuRwDestroy(&iinfo->ii_rwsem); ++} +diff --git a/fs/aufs/inode.c b/fs/aufs/inode.c +new file mode 100644 +index 0000000..75ec2e5 +--- /dev/null ++++ b/fs/aufs/inode.c +@@ -0,0 +1,522 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * inode functions ++ */ ++ ++#include "aufs.h" ++ ++struct inode *au_igrab(struct inode *inode) ++{ ++ if (inode) { ++ AuDebugOn(!atomic_read(&inode->i_count)); ++ ihold(inode); ++ } ++ return inode; ++} ++ ++static void au_refresh_hinode_attr(struct inode *inode, int do_version) ++{ ++ au_cpup_attr_all(inode, /*force*/0); ++ au_update_iigen(inode, /*half*/1); ++ if (do_version) ++ inode->i_version++; ++} ++ ++static int au_ii_refresh(struct inode *inode, int *update) ++{ ++ int err, e; ++ umode_t type; ++ aufs_bindex_t bindex, new_bindex; ++ struct super_block *sb; ++ struct au_iinfo *iinfo; ++ struct au_hinode *p, *q, tmp; ++ ++ IiMustWriteLock(inode); ++ ++ *update = 0; ++ sb = inode->i_sb; ++ type = inode->i_mode & S_IFMT; ++ iinfo = au_ii(inode); ++ err = au_ii_realloc(iinfo, au_sbend(sb) + 1); ++ if (unlikely(err)) ++ goto out; ++ ++ AuDebugOn(iinfo->ii_bstart < 0); ++ p = iinfo->ii_hinode + iinfo->ii_bstart; ++ for (bindex = iinfo->ii_bstart; bindex <= iinfo->ii_bend; ++ bindex++, p++) { ++ if (!p->hi_inode) ++ continue; ++ ++ AuDebugOn(type != (p->hi_inode->i_mode & S_IFMT)); ++ new_bindex = au_br_index(sb, p->hi_id); ++ if (new_bindex == bindex) ++ continue; ++ ++ if (new_bindex < 0) { ++ *update = 1; ++ au_hiput(p); ++ p->hi_inode = NULL; ++ continue; ++ } ++ ++ if (new_bindex < iinfo->ii_bstart) ++ iinfo->ii_bstart = new_bindex; ++ if (iinfo->ii_bend < new_bindex) ++ iinfo->ii_bend = new_bindex; ++ /* swap two lower inode, and loop again */ ++ q = iinfo->ii_hinode + new_bindex; ++ tmp = *q; ++ *q = *p; ++ *p = tmp; ++ if (tmp.hi_inode) { ++ bindex--; ++ p--; ++ } ++ } ++ au_update_ibrange(inode, /*do_put_zero*/0); ++ e = au_dy_irefresh(inode); ++ if (unlikely(e && !err)) ++ err = e; ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++void au_refresh_iop(struct inode *inode, int force_getattr) ++{ ++ int type; ++ struct au_sbinfo *sbi = au_sbi(inode->i_sb); ++ const struct inode_operations *iop ++ = force_getattr ? aufs_iop : sbi->si_iop_array; ++ ++ if (inode->i_op == iop) ++ return; ++ ++ switch (inode->i_mode & S_IFMT) { ++ case S_IFDIR: ++ type = AuIop_DIR; ++ break; ++ case S_IFLNK: ++ type = AuIop_SYMLINK; ++ break; ++ default: ++ type = AuIop_OTHER; ++ break; ++ } ++ ++ inode->i_op = iop + type; ++ /* unnecessary smp_wmb() */ ++} ++ ++int au_refresh_hinode_self(struct inode *inode) ++{ ++ int err, update; ++ ++ err = au_ii_refresh(inode, &update); ++ if (!err) ++ au_refresh_hinode_attr(inode, update && S_ISDIR(inode->i_mode)); ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_refresh_hinode(struct inode *inode, struct dentry *dentry) ++{ ++ int err, e, update; ++ unsigned int flags; ++ umode_t mode; ++ aufs_bindex_t bindex, bend; ++ unsigned char isdir; ++ struct au_hinode *p; ++ struct au_iinfo *iinfo; ++ ++ err = au_ii_refresh(inode, &update); ++ if (unlikely(err)) ++ goto out; ++ ++ update = 0; ++ iinfo = au_ii(inode); ++ p = iinfo->ii_hinode + iinfo->ii_bstart; ++ mode = (inode->i_mode & S_IFMT); ++ isdir = S_ISDIR(mode); ++ flags = au_hi_flags(inode, isdir); ++ bend = au_dbend(dentry); ++ for (bindex = au_dbstart(dentry); bindex <= bend; bindex++) { ++ struct inode *h_i; ++ struct dentry *h_d; ++ ++ h_d = au_h_dptr(dentry, bindex); ++ if (!h_d || !h_d->d_inode) ++ continue; ++ ++ AuDebugOn(mode != (h_d->d_inode->i_mode & S_IFMT)); ++ if (iinfo->ii_bstart <= bindex && bindex <= iinfo->ii_bend) { ++ h_i = au_h_iptr(inode, bindex); ++ if (h_i) { ++ if (h_i == h_d->d_inode) ++ continue; ++ err = -EIO; ++ break; ++ } ++ } ++ if (bindex < iinfo->ii_bstart) ++ iinfo->ii_bstart = bindex; ++ if (iinfo->ii_bend < bindex) ++ iinfo->ii_bend = bindex; ++ au_set_h_iptr(inode, bindex, au_igrab(h_d->d_inode), flags); ++ update = 1; ++ } ++ au_update_ibrange(inode, /*do_put_zero*/0); ++ e = au_dy_irefresh(inode); ++ if (unlikely(e && !err)) ++ err = e; ++ if (!err) ++ au_refresh_hinode_attr(inode, update && isdir); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int set_inode(struct inode *inode, struct dentry *dentry) ++{ ++ int err; ++ unsigned int flags; ++ umode_t mode; ++ aufs_bindex_t bindex, bstart, btail; ++ unsigned char isdir; ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ struct au_iinfo *iinfo; ++ struct inode_operations *iop; ++ ++ IiMustWriteLock(inode); ++ ++ err = 0; ++ isdir = 0; ++ iop = au_sbi(inode->i_sb)->si_iop_array; ++ bstart = au_dbstart(dentry); ++ h_inode = au_h_dptr(dentry, bstart)->d_inode; ++ mode = h_inode->i_mode; ++ switch (mode & S_IFMT) { ++ case S_IFREG: ++ btail = au_dbtail(dentry); ++ inode->i_op = iop + AuIop_OTHER; ++ inode->i_fop = &aufs_file_fop; ++ err = au_dy_iaop(inode, bstart, h_inode); ++ if (unlikely(err)) ++ goto out; ++ break; ++ case S_IFDIR: ++ isdir = 1; ++ btail = au_dbtaildir(dentry); ++ inode->i_op = iop + AuIop_DIR; ++ inode->i_fop = &aufs_dir_fop; ++ break; ++ case S_IFLNK: ++ btail = au_dbtail(dentry); ++ inode->i_op = iop + AuIop_SYMLINK; ++ break; ++ case S_IFBLK: ++ case S_IFCHR: ++ case S_IFIFO: ++ case S_IFSOCK: ++ btail = au_dbtail(dentry); ++ inode->i_op = iop + AuIop_OTHER; ++ init_special_inode(inode, mode, h_inode->i_rdev); ++ break; ++ default: ++ AuIOErr("Unknown file type 0%o\n", mode); ++ err = -EIO; ++ goto out; ++ } ++ ++ /* do not set hnotify for whiteouted dirs (SHWH mode) */ ++ flags = au_hi_flags(inode, isdir); ++ if (au_opt_test(au_mntflags(dentry->d_sb), SHWH) ++ && au_ftest_hi(flags, HNOTIFY) ++ && dentry->d_name.len > AUFS_WH_PFX_LEN ++ && !memcmp(dentry->d_name.name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) ++ au_fclr_hi(flags, HNOTIFY); ++ iinfo = au_ii(inode); ++ iinfo->ii_bstart = bstart; ++ iinfo->ii_bend = btail; ++ for (bindex = bstart; bindex <= btail; bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (h_dentry) ++ au_set_h_iptr(inode, bindex, ++ au_igrab(h_dentry->d_inode), flags); ++ } ++ au_cpup_attr_all(inode, /*force*/1); ++ /* ++ * to force calling aufs_get_acl() every time, ++ * do not call cache_no_acl() for aufs inode. ++ */ ++ ++out: ++ return err; ++} ++ ++/* ++ * successful returns with iinfo write_locked ++ * minus: errno ++ * zero: success, matched ++ * plus: no error, but unmatched ++ */ ++static int reval_inode(struct inode *inode, struct dentry *dentry) ++{ ++ int err; ++ unsigned int gen, igflags; ++ aufs_bindex_t bindex, bend; ++ struct inode *h_inode, *h_dinode; ++ ++ /* ++ * before this function, if aufs got any iinfo lock, it must be only ++ * one, the parent dir. ++ * it can happen by UDBA and the obsoleted inode number. ++ */ ++ err = -EIO; ++ if (unlikely(inode->i_ino == parent_ino(dentry))) ++ goto out; ++ ++ err = 1; ++ ii_write_lock_new_child(inode); ++ h_dinode = au_h_dptr(dentry, au_dbstart(dentry))->d_inode; ++ bend = au_ibend(inode); ++ for (bindex = au_ibstart(inode); bindex <= bend; bindex++) { ++ h_inode = au_h_iptr(inode, bindex); ++ if (!h_inode || h_inode != h_dinode) ++ continue; ++ ++ err = 0; ++ gen = au_iigen(inode, &igflags); ++ if (gen == au_digen(dentry) ++ && !au_ig_ftest(igflags, HALF_REFRESHED)) ++ break; ++ ++ /* fully refresh inode using dentry */ ++ err = au_refresh_hinode(inode, dentry); ++ if (!err) ++ au_update_iigen(inode, /*half*/0); ++ break; ++ } ++ ++ if (unlikely(err)) ++ ii_write_unlock(inode); ++out: ++ return err; ++} ++ ++int au_ino(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ unsigned int d_type, ino_t *ino) ++{ ++ int err; ++ struct mutex *mtx; ++ ++ /* prevent hardlinked inode number from race condition */ ++ mtx = NULL; ++ if (d_type != DT_DIR) { ++ mtx = &au_sbr(sb, bindex)->br_xino.xi_nondir_mtx; ++ mutex_lock(mtx); ++ } ++ err = au_xino_read(sb, bindex, h_ino, ino); ++ if (unlikely(err)) ++ goto out; ++ ++ if (!*ino) { ++ err = -EIO; ++ *ino = au_xino_new_ino(sb); ++ if (unlikely(!*ino)) ++ goto out; ++ err = au_xino_write(sb, bindex, h_ino, *ino); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++out: ++ if (mtx) ++ mutex_unlock(mtx); ++ return err; ++} ++ ++/* successful returns with iinfo write_locked */ ++/* todo: return with unlocked? */ ++struct inode *au_new_inode(struct dentry *dentry, int must_new) ++{ ++ struct inode *inode; ++ struct dentry *h_dentry; ++ struct super_block *sb; ++ struct mutex *mtx; ++ ino_t h_ino, ino; ++ int err; ++ aufs_bindex_t bstart; ++ ++ sb = dentry->d_sb; ++ bstart = au_dbstart(dentry); ++ h_dentry = au_h_dptr(dentry, bstart); ++ h_ino = h_dentry->d_inode->i_ino; ++ ++ /* ++ * stop 'race'-ing between hardlinks under different ++ * parents. ++ */ ++ mtx = NULL; ++ if (!d_is_dir(h_dentry)) ++ mtx = &au_sbr(sb, bstart)->br_xino.xi_nondir_mtx; ++ ++new_ino: ++ if (mtx) ++ mutex_lock(mtx); ++ err = au_xino_read(sb, bstart, h_ino, &ino); ++ inode = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out; ++ ++ if (!ino) { ++ ino = au_xino_new_ino(sb); ++ if (unlikely(!ino)) { ++ inode = ERR_PTR(-EIO); ++ goto out; ++ } ++ } ++ ++ AuDbg("i%lu\n", (unsigned long)ino); ++ inode = au_iget_locked(sb, ino); ++ err = PTR_ERR(inode); ++ if (IS_ERR(inode)) ++ goto out; ++ ++ AuDbg("%lx, new %d\n", inode->i_state, !!(inode->i_state & I_NEW)); ++ if (inode->i_state & I_NEW) { ++ /* verbose coding for lock class name */ ++ if (unlikely(d_is_symlink(h_dentry))) ++ au_rw_class(&au_ii(inode)->ii_rwsem, ++ au_lc_key + AuLcSymlink_IIINFO); ++ else if (unlikely(d_is_dir(h_dentry))) ++ au_rw_class(&au_ii(inode)->ii_rwsem, ++ au_lc_key + AuLcDir_IIINFO); ++ else /* likely */ ++ au_rw_class(&au_ii(inode)->ii_rwsem, ++ au_lc_key + AuLcNonDir_IIINFO); ++ ++ ii_write_lock_new_child(inode); ++ err = set_inode(inode, dentry); ++ if (!err) { ++ unlock_new_inode(inode); ++ goto out; /* success */ ++ } ++ ++ /* ++ * iget_failed() calls iput(), but we need to call ++ * ii_write_unlock() after iget_failed(). so dirty hack for ++ * i_count. ++ */ ++ atomic_inc(&inode->i_count); ++ iget_failed(inode); ++ ii_write_unlock(inode); ++ au_xino_write(sb, bstart, h_ino, /*ino*/0); ++ /* ignore this error */ ++ goto out_iput; ++ } else if (!must_new && !IS_DEADDIR(inode) && inode->i_nlink) { ++ /* ++ * horrible race condition between lookup, readdir and copyup ++ * (or something). ++ */ ++ if (mtx) ++ mutex_unlock(mtx); ++ err = reval_inode(inode, dentry); ++ if (unlikely(err < 0)) { ++ mtx = NULL; ++ goto out_iput; ++ } ++ ++ if (!err) { ++ mtx = NULL; ++ goto out; /* success */ ++ } else if (mtx) ++ mutex_lock(mtx); ++ } ++ ++ if (unlikely(au_test_fs_unique_ino(h_dentry->d_inode))) ++ AuWarn1("Warning: Un-notified UDBA or repeatedly renamed dir," ++ " b%d, %s, %pd, hi%lu, i%lu.\n", ++ bstart, au_sbtype(h_dentry->d_sb), dentry, ++ (unsigned long)h_ino, (unsigned long)ino); ++ ino = 0; ++ err = au_xino_write(sb, bstart, h_ino, /*ino*/0); ++ if (!err) { ++ iput(inode); ++ if (mtx) ++ mutex_unlock(mtx); ++ goto new_ino; ++ } ++ ++out_iput: ++ iput(inode); ++ inode = ERR_PTR(err); ++out: ++ if (mtx) ++ mutex_unlock(mtx); ++ return inode; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_test_ro(struct super_block *sb, aufs_bindex_t bindex, ++ struct inode *inode) ++{ ++ int err; ++ struct inode *hi; ++ ++ err = au_br_rdonly(au_sbr(sb, bindex)); ++ ++ /* pseudo-link after flushed may happen out of bounds */ ++ if (!err ++ && inode ++ && au_ibstart(inode) <= bindex ++ && bindex <= au_ibend(inode)) { ++ /* ++ * permission check is unnecessary since vfsub routine ++ * will be called later ++ */ ++ hi = au_h_iptr(inode, bindex); ++ if (hi) ++ err = IS_IMMUTABLE(hi) ? -EROFS : 0; ++ } ++ ++ return err; ++} ++ ++int au_test_h_perm(struct inode *h_inode, int mask) ++{ ++ if (uid_eq(current_fsuid(), GLOBAL_ROOT_UID)) ++ return 0; ++ return inode_permission(h_inode, mask); ++} ++ ++int au_test_h_perm_sio(struct inode *h_inode, int mask) ++{ ++ if (au_test_nfs(h_inode->i_sb) ++ && (mask & MAY_WRITE) ++ && S_ISDIR(h_inode->i_mode)) ++ mask |= MAY_READ; /* force permission check */ ++ return au_test_h_perm(h_inode, mask); ++} +diff --git a/fs/aufs/inode.h b/fs/aufs/inode.h +new file mode 100644 +index 0000000..49d53a2 +--- /dev/null ++++ b/fs/aufs/inode.h +@@ -0,0 +1,686 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * inode operations ++ */ ++ ++#ifndef __AUFS_INODE_H__ ++#define __AUFS_INODE_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include "rwsem.h" ++ ++struct vfsmount; ++ ++struct au_hnotify { ++#ifdef CONFIG_AUFS_HNOTIFY ++#ifdef CONFIG_AUFS_HFSNOTIFY ++ /* never use fsnotify_add_vfsmount_mark() */ ++ struct fsnotify_mark hn_mark; ++#endif ++ struct inode *hn_aufs_inode; /* no get/put */ ++#endif ++} ____cacheline_aligned_in_smp; ++ ++struct au_hinode { ++ struct inode *hi_inode; ++ aufs_bindex_t hi_id; ++#ifdef CONFIG_AUFS_HNOTIFY ++ struct au_hnotify *hi_notify; ++#endif ++ ++ /* reference to the copied-up whiteout with get/put */ ++ struct dentry *hi_whdentry; ++}; ++ ++/* ig_flags */ ++#define AuIG_HALF_REFRESHED 1 ++#define au_ig_ftest(flags, name) ((flags) & AuIG_##name) ++#define au_ig_fset(flags, name) \ ++ do { (flags) |= AuIG_##name; } while (0) ++#define au_ig_fclr(flags, name) \ ++ do { (flags) &= ~AuIG_##name; } while (0) ++ ++struct au_iigen { ++ spinlock_t ig_spin; ++ __u32 ig_generation, ig_flags; ++}; ++ ++struct au_vdir; ++struct au_iinfo { ++ struct au_iigen ii_generation; ++ struct super_block *ii_hsb1; /* no get/put */ ++ ++ struct au_rwsem ii_rwsem; ++ aufs_bindex_t ii_bstart, ii_bend; ++ __u32 ii_higen; ++ struct au_hinode *ii_hinode; ++ struct au_vdir *ii_vdir; ++}; ++ ++struct au_icntnr { ++ struct au_iinfo iinfo; ++ struct inode vfs_inode; ++ struct hlist_node plink; ++} ____cacheline_aligned_in_smp; ++ ++/* au_pin flags */ ++#define AuPin_DI_LOCKED 1 ++#define AuPin_MNT_WRITE (1 << 1) ++#define au_ftest_pin(flags, name) ((flags) & AuPin_##name) ++#define au_fset_pin(flags, name) \ ++ do { (flags) |= AuPin_##name; } while (0) ++#define au_fclr_pin(flags, name) \ ++ do { (flags) &= ~AuPin_##name; } while (0) ++ ++struct au_pin { ++ /* input */ ++ struct dentry *dentry; ++ unsigned int udba; ++ unsigned char lsc_di, lsc_hi, flags; ++ aufs_bindex_t bindex; ++ ++ /* output */ ++ struct dentry *parent; ++ struct au_hinode *hdir; ++ struct vfsmount *h_mnt; ++ ++ /* temporary unlock/relock for copyup */ ++ struct dentry *h_dentry, *h_parent; ++ struct au_branch *br; ++ struct task_struct *task; ++}; ++ ++void au_pin_hdir_unlock(struct au_pin *p); ++int au_pin_hdir_lock(struct au_pin *p); ++int au_pin_hdir_relock(struct au_pin *p); ++void au_pin_hdir_set_owner(struct au_pin *p, struct task_struct *task); ++void au_pin_hdir_acquire_nest(struct au_pin *p); ++void au_pin_hdir_release(struct au_pin *p); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct au_iinfo *au_ii(struct inode *inode) ++{ ++ struct au_iinfo *iinfo; ++ ++ iinfo = &(container_of(inode, struct au_icntnr, vfs_inode)->iinfo); ++ if (iinfo->ii_hinode) ++ return iinfo; ++ return NULL; /* debugging bad_inode case */ ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* inode.c */ ++struct inode *au_igrab(struct inode *inode); ++void au_refresh_iop(struct inode *inode, int force_getattr); ++int au_refresh_hinode_self(struct inode *inode); ++int au_refresh_hinode(struct inode *inode, struct dentry *dentry); ++int au_ino(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ unsigned int d_type, ino_t *ino); ++struct inode *au_new_inode(struct dentry *dentry, int must_new); ++int au_test_ro(struct super_block *sb, aufs_bindex_t bindex, ++ struct inode *inode); ++int au_test_h_perm(struct inode *h_inode, int mask); ++int au_test_h_perm_sio(struct inode *h_inode, int mask); ++ ++static inline int au_wh_ino(struct super_block *sb, aufs_bindex_t bindex, ++ ino_t h_ino, unsigned int d_type, ino_t *ino) ++{ ++#ifdef CONFIG_AUFS_SHWH ++ return au_ino(sb, bindex, h_ino, d_type, ino); ++#else ++ return 0; ++#endif ++} ++ ++/* i_op.c */ ++enum { ++ AuIop_SYMLINK, ++ AuIop_DIR, ++ AuIop_OTHER, ++ AuIop_Last ++}; ++extern struct inode_operations aufs_iop[AuIop_Last], ++ aufs_iop_nogetattr[AuIop_Last]; ++ ++/* au_wr_dir flags */ ++#define AuWrDir_ADD_ENTRY 1 ++#define AuWrDir_ISDIR (1 << 1) ++#define AuWrDir_TMPFILE (1 << 2) ++#define au_ftest_wrdir(flags, name) ((flags) & AuWrDir_##name) ++#define au_fset_wrdir(flags, name) \ ++ do { (flags) |= AuWrDir_##name; } while (0) ++#define au_fclr_wrdir(flags, name) \ ++ do { (flags) &= ~AuWrDir_##name; } while (0) ++ ++struct au_wr_dir_args { ++ aufs_bindex_t force_btgt; ++ unsigned char flags; ++}; ++int au_wr_dir(struct dentry *dentry, struct dentry *src_dentry, ++ struct au_wr_dir_args *args); ++ ++struct dentry *au_pinned_h_parent(struct au_pin *pin); ++void au_pin_init(struct au_pin *pin, struct dentry *dentry, ++ aufs_bindex_t bindex, int lsc_di, int lsc_hi, ++ unsigned int udba, unsigned char flags); ++int au_pin(struct au_pin *pin, struct dentry *dentry, aufs_bindex_t bindex, ++ unsigned int udba, unsigned char flags) __must_check; ++int au_do_pin(struct au_pin *pin) __must_check; ++void au_unpin(struct au_pin *pin); ++int au_reval_for_attr(struct dentry *dentry, unsigned int sigen); ++ ++#define AuIcpup_DID_CPUP 1 ++#define au_ftest_icpup(flags, name) ((flags) & AuIcpup_##name) ++#define au_fset_icpup(flags, name) \ ++ do { (flags) |= AuIcpup_##name; } while (0) ++#define au_fclr_icpup(flags, name) \ ++ do { (flags) &= ~AuIcpup_##name; } while (0) ++ ++struct au_icpup_args { ++ unsigned char flags; ++ unsigned char pin_flags; ++ aufs_bindex_t btgt; ++ unsigned int udba; ++ struct au_pin pin; ++ struct path h_path; ++ struct inode *h_inode; ++}; ++ ++int au_pin_and_icpup(struct dentry *dentry, struct iattr *ia, ++ struct au_icpup_args *a); ++ ++int au_h_path_getattr(struct dentry *dentry, int force, struct path *h_path); ++ ++/* i_op_add.c */ ++int au_may_add(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_parent, int isdir); ++int aufs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, ++ dev_t dev); ++int aufs_symlink(struct inode *dir, struct dentry *dentry, const char *symname); ++int aufs_create(struct inode *dir, struct dentry *dentry, umode_t mode, ++ bool want_excl); ++struct vfsub_aopen_args; ++int au_aopen_or_create(struct inode *dir, struct dentry *dentry, ++ struct vfsub_aopen_args *args); ++int aufs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode); ++int aufs_link(struct dentry *src_dentry, struct inode *dir, ++ struct dentry *dentry); ++int aufs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode); ++ ++/* i_op_del.c */ ++int au_wr_dir_need_wh(struct dentry *dentry, int isdir, aufs_bindex_t *bcpup); ++int au_may_del(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_parent, int isdir); ++int aufs_unlink(struct inode *dir, struct dentry *dentry); ++int aufs_rmdir(struct inode *dir, struct dentry *dentry); ++ ++/* i_op_ren.c */ ++int au_wbr(struct dentry *dentry, aufs_bindex_t btgt); ++int aufs_rename(struct inode *src_dir, struct dentry *src_dentry, ++ struct inode *dir, struct dentry *dentry); ++ ++/* iinfo.c */ ++struct inode *au_h_iptr(struct inode *inode, aufs_bindex_t bindex); ++void au_hiput(struct au_hinode *hinode); ++void au_set_hi_wh(struct inode *inode, aufs_bindex_t bindex, ++ struct dentry *h_wh); ++unsigned int au_hi_flags(struct inode *inode, int isdir); ++ ++/* hinode flags */ ++#define AuHi_XINO 1 ++#define AuHi_HNOTIFY (1 << 1) ++#define au_ftest_hi(flags, name) ((flags) & AuHi_##name) ++#define au_fset_hi(flags, name) \ ++ do { (flags) |= AuHi_##name; } while (0) ++#define au_fclr_hi(flags, name) \ ++ do { (flags) &= ~AuHi_##name; } while (0) ++ ++#ifndef CONFIG_AUFS_HNOTIFY ++#undef AuHi_HNOTIFY ++#define AuHi_HNOTIFY 0 ++#endif ++ ++void au_set_h_iptr(struct inode *inode, aufs_bindex_t bindex, ++ struct inode *h_inode, unsigned int flags); ++ ++void au_update_iigen(struct inode *inode, int half); ++void au_update_ibrange(struct inode *inode, int do_put_zero); ++ ++void au_icntnr_init_once(void *_c); ++int au_iinfo_init(struct inode *inode); ++void au_iinfo_fin(struct inode *inode); ++int au_ii_realloc(struct au_iinfo *iinfo, int nbr); ++ ++#ifdef CONFIG_PROC_FS ++/* plink.c */ ++int au_plink_maint(struct super_block *sb, int flags); ++struct au_sbinfo; ++void au_plink_maint_leave(struct au_sbinfo *sbinfo); ++int au_plink_maint_enter(struct super_block *sb); ++#ifdef CONFIG_AUFS_DEBUG ++void au_plink_list(struct super_block *sb); ++#else ++AuStubVoid(au_plink_list, struct super_block *sb) ++#endif ++int au_plink_test(struct inode *inode); ++struct dentry *au_plink_lkup(struct inode *inode, aufs_bindex_t bindex); ++void au_plink_append(struct inode *inode, aufs_bindex_t bindex, ++ struct dentry *h_dentry); ++void au_plink_put(struct super_block *sb, int verbose); ++void au_plink_clean(struct super_block *sb, int verbose); ++void au_plink_half_refresh(struct super_block *sb, aufs_bindex_t br_id); ++#else ++AuStubInt0(au_plink_maint, struct super_block *sb, int flags); ++AuStubVoid(au_plink_maint_leave, struct au_sbinfo *sbinfo); ++AuStubInt0(au_plink_maint_enter, struct super_block *sb); ++AuStubVoid(au_plink_list, struct super_block *sb); ++AuStubInt0(au_plink_test, struct inode *inode); ++AuStub(struct dentry *, au_plink_lkup, return NULL, ++ struct inode *inode, aufs_bindex_t bindex); ++AuStubVoid(au_plink_append, struct inode *inode, aufs_bindex_t bindex, ++ struct dentry *h_dentry); ++AuStubVoid(au_plink_put, struct super_block *sb, int verbose); ++AuStubVoid(au_plink_clean, struct super_block *sb, int verbose); ++AuStubVoid(au_plink_half_refresh, struct super_block *sb, aufs_bindex_t br_id); ++#endif /* CONFIG_PROC_FS */ ++ ++#ifdef CONFIG_AUFS_XATTR ++/* xattr.c */ ++int au_cpup_xattr(struct dentry *h_dst, struct dentry *h_src, int ignore_flags, ++ unsigned int verbose); ++ssize_t aufs_listxattr(struct dentry *dentry, char *list, size_t size); ++ssize_t aufs_getxattr(struct dentry *dentry, const char *name, void *value, ++ size_t size); ++int aufs_setxattr(struct dentry *dentry, const char *name, const void *value, ++ size_t size, int flags); ++int aufs_removexattr(struct dentry *dentry, const char *name); ++ ++/* void au_xattr_init(struct super_block *sb); */ ++#else ++AuStubInt0(au_cpup_xattr, struct dentry *h_dst, struct dentry *h_src, ++ int ignore_flags, unsigned int verbose); ++/* AuStubVoid(au_xattr_init, struct super_block *sb); */ ++#endif ++ ++#ifdef CONFIG_FS_POSIX_ACL ++struct posix_acl *aufs_get_acl(struct inode *inode, int type); ++int aufs_set_acl(struct inode *inode, struct posix_acl *acl, int type); ++#endif ++ ++#if IS_ENABLED(CONFIG_AUFS_XATTR) || IS_ENABLED(CONFIG_FS_POSIX_ACL) ++enum { ++ AU_XATTR_SET, ++ AU_XATTR_REMOVE, ++ AU_ACL_SET ++}; ++ ++struct au_srxattr { ++ int type; ++ union { ++ struct { ++ const char *name; ++ const void *value; ++ size_t size; ++ int flags; ++ } set; ++ struct { ++ const char *name; ++ } remove; ++ struct { ++ struct posix_acl *acl; ++ int type; ++ } acl_set; ++ } u; ++}; ++ssize_t au_srxattr(struct dentry *dentry, struct au_srxattr *arg); ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* lock subclass for iinfo */ ++enum { ++ AuLsc_II_CHILD, /* child first */ ++ AuLsc_II_CHILD2, /* rename(2), link(2), and cpup at hnotify */ ++ AuLsc_II_CHILD3, /* copyup dirs */ ++ AuLsc_II_PARENT, /* see AuLsc_I_PARENT in vfsub.h */ ++ AuLsc_II_PARENT2, ++ AuLsc_II_PARENT3, /* copyup dirs */ ++ AuLsc_II_NEW_CHILD ++}; ++ ++/* ++ * ii_read_lock_child, ii_write_lock_child, ++ * ii_read_lock_child2, ii_write_lock_child2, ++ * ii_read_lock_child3, ii_write_lock_child3, ++ * ii_read_lock_parent, ii_write_lock_parent, ++ * ii_read_lock_parent2, ii_write_lock_parent2, ++ * ii_read_lock_parent3, ii_write_lock_parent3, ++ * ii_read_lock_new_child, ii_write_lock_new_child, ++ */ ++#define AuReadLockFunc(name, lsc) \ ++static inline void ii_read_lock_##name(struct inode *i) \ ++{ \ ++ au_rw_read_lock_nested(&au_ii(i)->ii_rwsem, AuLsc_II_##lsc); \ ++} ++ ++#define AuWriteLockFunc(name, lsc) \ ++static inline void ii_write_lock_##name(struct inode *i) \ ++{ \ ++ au_rw_write_lock_nested(&au_ii(i)->ii_rwsem, AuLsc_II_##lsc); \ ++} ++ ++#define AuRWLockFuncs(name, lsc) \ ++ AuReadLockFunc(name, lsc) \ ++ AuWriteLockFunc(name, lsc) ++ ++AuRWLockFuncs(child, CHILD); ++AuRWLockFuncs(child2, CHILD2); ++AuRWLockFuncs(child3, CHILD3); ++AuRWLockFuncs(parent, PARENT); ++AuRWLockFuncs(parent2, PARENT2); ++AuRWLockFuncs(parent3, PARENT3); ++AuRWLockFuncs(new_child, NEW_CHILD); ++ ++#undef AuReadLockFunc ++#undef AuWriteLockFunc ++#undef AuRWLockFuncs ++ ++/* ++ * ii_read_unlock, ii_write_unlock, ii_downgrade_lock ++ */ ++AuSimpleUnlockRwsemFuncs(ii, struct inode *i, &au_ii(i)->ii_rwsem); ++ ++#define IiMustNoWaiters(i) AuRwMustNoWaiters(&au_ii(i)->ii_rwsem) ++#define IiMustAnyLock(i) AuRwMustAnyLock(&au_ii(i)->ii_rwsem) ++#define IiMustWriteLock(i) AuRwMustWriteLock(&au_ii(i)->ii_rwsem) ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline void au_icntnr_init(struct au_icntnr *c) ++{ ++#ifdef CONFIG_AUFS_DEBUG ++ c->vfs_inode.i_mode = 0; ++#endif ++} ++ ++static inline unsigned int au_iigen(struct inode *inode, unsigned int *igflags) ++{ ++ unsigned int gen; ++ struct au_iinfo *iinfo; ++ struct au_iigen *iigen; ++ ++ iinfo = au_ii(inode); ++ iigen = &iinfo->ii_generation; ++ spin_lock(&iigen->ig_spin); ++ if (igflags) ++ *igflags = iigen->ig_flags; ++ gen = iigen->ig_generation; ++ spin_unlock(&iigen->ig_spin); ++ ++ return gen; ++} ++ ++/* tiny test for inode number */ ++/* tmpfs generation is too rough */ ++static inline int au_test_higen(struct inode *inode, struct inode *h_inode) ++{ ++ struct au_iinfo *iinfo; ++ ++ iinfo = au_ii(inode); ++ AuRwMustAnyLock(&iinfo->ii_rwsem); ++ return !(iinfo->ii_hsb1 == h_inode->i_sb ++ && iinfo->ii_higen == h_inode->i_generation); ++} ++ ++static inline void au_iigen_dec(struct inode *inode) ++{ ++ struct au_iinfo *iinfo; ++ struct au_iigen *iigen; ++ ++ iinfo = au_ii(inode); ++ iigen = &iinfo->ii_generation; ++ spin_lock(&iigen->ig_spin); ++ iigen->ig_generation--; ++ spin_unlock(&iigen->ig_spin); ++} ++ ++static inline int au_iigen_test(struct inode *inode, unsigned int sigen) ++{ ++ int err; ++ ++ err = 0; ++ if (unlikely(inode && au_iigen(inode, NULL) != sigen)) ++ err = -EIO; ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline aufs_bindex_t au_ii_br_id(struct inode *inode, ++ aufs_bindex_t bindex) ++{ ++ IiMustAnyLock(inode); ++ return au_ii(inode)->ii_hinode[0 + bindex].hi_id; ++} ++ ++static inline aufs_bindex_t au_ibstart(struct inode *inode) ++{ ++ IiMustAnyLock(inode); ++ return au_ii(inode)->ii_bstart; ++} ++ ++static inline aufs_bindex_t au_ibend(struct inode *inode) ++{ ++ IiMustAnyLock(inode); ++ return au_ii(inode)->ii_bend; ++} ++ ++static inline struct au_vdir *au_ivdir(struct inode *inode) ++{ ++ IiMustAnyLock(inode); ++ return au_ii(inode)->ii_vdir; ++} ++ ++static inline struct dentry *au_hi_wh(struct inode *inode, aufs_bindex_t bindex) ++{ ++ IiMustAnyLock(inode); ++ return au_ii(inode)->ii_hinode[0 + bindex].hi_whdentry; ++} ++ ++static inline void au_set_ibstart(struct inode *inode, aufs_bindex_t bindex) ++{ ++ IiMustWriteLock(inode); ++ au_ii(inode)->ii_bstart = bindex; ++} ++ ++static inline void au_set_ibend(struct inode *inode, aufs_bindex_t bindex) ++{ ++ IiMustWriteLock(inode); ++ au_ii(inode)->ii_bend = bindex; ++} ++ ++static inline void au_set_ivdir(struct inode *inode, struct au_vdir *vdir) ++{ ++ IiMustWriteLock(inode); ++ au_ii(inode)->ii_vdir = vdir; ++} ++ ++static inline struct au_hinode *au_hi(struct inode *inode, aufs_bindex_t bindex) ++{ ++ IiMustAnyLock(inode); ++ return au_ii(inode)->ii_hinode + bindex; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct dentry *au_pinned_parent(struct au_pin *pin) ++{ ++ if (pin) ++ return pin->parent; ++ return NULL; ++} ++ ++static inline struct inode *au_pinned_h_dir(struct au_pin *pin) ++{ ++ if (pin && pin->hdir) ++ return pin->hdir->hi_inode; ++ return NULL; ++} ++ ++static inline struct au_hinode *au_pinned_hdir(struct au_pin *pin) ++{ ++ if (pin) ++ return pin->hdir; ++ return NULL; ++} ++ ++static inline void au_pin_set_dentry(struct au_pin *pin, struct dentry *dentry) ++{ ++ if (pin) ++ pin->dentry = dentry; ++} ++ ++static inline void au_pin_set_parent_lflag(struct au_pin *pin, ++ unsigned char lflag) ++{ ++ if (pin) { ++ if (lflag) ++ au_fset_pin(pin->flags, DI_LOCKED); ++ else ++ au_fclr_pin(pin->flags, DI_LOCKED); ++ } ++} ++ ++#if 0 /* reserved */ ++static inline void au_pin_set_parent(struct au_pin *pin, struct dentry *parent) ++{ ++ if (pin) { ++ dput(pin->parent); ++ pin->parent = dget(parent); ++ } ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_branch; ++#ifdef CONFIG_AUFS_HNOTIFY ++struct au_hnotify_op { ++ void (*ctl)(struct au_hinode *hinode, int do_set); ++ int (*alloc)(struct au_hinode *hinode); ++ ++ /* ++ * if it returns true, the the caller should free hinode->hi_notify, ++ * otherwise ->free() frees it. ++ */ ++ int (*free)(struct au_hinode *hinode, ++ struct au_hnotify *hn) __must_check; ++ ++ void (*fin)(void); ++ int (*init)(void); ++ ++ int (*reset_br)(unsigned int udba, struct au_branch *br, int perm); ++ void (*fin_br)(struct au_branch *br); ++ int (*init_br)(struct au_branch *br, int perm); ++}; ++ ++/* hnotify.c */ ++int au_hn_alloc(struct au_hinode *hinode, struct inode *inode); ++void au_hn_free(struct au_hinode *hinode); ++void au_hn_ctl(struct au_hinode *hinode, int do_set); ++void au_hn_reset(struct inode *inode, unsigned int flags); ++int au_hnotify(struct inode *h_dir, struct au_hnotify *hnotify, u32 mask, ++ struct qstr *h_child_qstr, struct inode *h_child_inode); ++int au_hnotify_reset_br(unsigned int udba, struct au_branch *br, int perm); ++int au_hnotify_init_br(struct au_branch *br, int perm); ++void au_hnotify_fin_br(struct au_branch *br); ++int __init au_hnotify_init(void); ++void au_hnotify_fin(void); ++ ++/* hfsnotify.c */ ++extern const struct au_hnotify_op au_hnotify_op; ++ ++static inline ++void au_hn_init(struct au_hinode *hinode) ++{ ++ hinode->hi_notify = NULL; ++} ++ ++static inline struct au_hnotify *au_hn(struct au_hinode *hinode) ++{ ++ return hinode->hi_notify; ++} ++ ++#else ++AuStub(int, au_hn_alloc, return -EOPNOTSUPP, ++ struct au_hinode *hinode __maybe_unused, ++ struct inode *inode __maybe_unused) ++AuStub(struct au_hnotify *, au_hn, return NULL, struct au_hinode *hinode) ++AuStubVoid(au_hn_free, struct au_hinode *hinode __maybe_unused) ++AuStubVoid(au_hn_ctl, struct au_hinode *hinode __maybe_unused, ++ int do_set __maybe_unused) ++AuStubVoid(au_hn_reset, struct inode *inode __maybe_unused, ++ unsigned int flags __maybe_unused) ++AuStubInt0(au_hnotify_reset_br, unsigned int udba __maybe_unused, ++ struct au_branch *br __maybe_unused, ++ int perm __maybe_unused) ++AuStubInt0(au_hnotify_init_br, struct au_branch *br __maybe_unused, ++ int perm __maybe_unused) ++AuStubVoid(au_hnotify_fin_br, struct au_branch *br __maybe_unused) ++AuStubInt0(__init au_hnotify_init, void) ++AuStubVoid(au_hnotify_fin, void) ++AuStubVoid(au_hn_init, struct au_hinode *hinode __maybe_unused) ++#endif /* CONFIG_AUFS_HNOTIFY */ ++ ++static inline void au_hn_suspend(struct au_hinode *hdir) ++{ ++ au_hn_ctl(hdir, /*do_set*/0); ++} ++ ++static inline void au_hn_resume(struct au_hinode *hdir) ++{ ++ au_hn_ctl(hdir, /*do_set*/1); ++} ++ ++static inline void au_hn_imtx_lock(struct au_hinode *hdir) ++{ ++ mutex_lock(&hdir->hi_inode->i_mutex); ++ au_hn_suspend(hdir); ++} ++ ++static inline void au_hn_imtx_lock_nested(struct au_hinode *hdir, ++ unsigned int sc __maybe_unused) ++{ ++ mutex_lock_nested(&hdir->hi_inode->i_mutex, sc); ++ au_hn_suspend(hdir); ++} ++ ++static inline void au_hn_imtx_unlock(struct au_hinode *hdir) ++{ ++ au_hn_resume(hdir); ++ mutex_unlock(&hdir->hi_inode->i_mutex); ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_INODE_H__ */ +diff --git a/fs/aufs/ioctl.c b/fs/aufs/ioctl.c +new file mode 100644 +index 0000000..10e2315 +--- /dev/null ++++ b/fs/aufs/ioctl.c +@@ -0,0 +1,219 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * ioctl ++ * plink-management and readdir in userspace. ++ * assist the pathconf(3) wrapper library. ++ * move-down ++ * File-based Hierarchical Storage Management. ++ */ ++ ++#include ++#include ++#include "aufs.h" ++ ++static int au_wbr_fd(struct path *path, struct aufs_wbr_fd __user *arg) ++{ ++ int err, fd; ++ aufs_bindex_t wbi, bindex, bend; ++ struct file *h_file; ++ struct super_block *sb; ++ struct dentry *root; ++ struct au_branch *br; ++ struct aufs_wbr_fd wbrfd = { ++ .oflags = au_dir_roflags, ++ .brid = -1 ++ }; ++ const int valid = O_RDONLY | O_NONBLOCK | O_LARGEFILE | O_DIRECTORY ++ | O_NOATIME | O_CLOEXEC; ++ ++ AuDebugOn(wbrfd.oflags & ~valid); ++ ++ if (arg) { ++ err = copy_from_user(&wbrfd, arg, sizeof(wbrfd)); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ goto out; ++ } ++ ++ err = -EINVAL; ++ AuDbg("wbrfd{0%o, %d}\n", wbrfd.oflags, wbrfd.brid); ++ wbrfd.oflags |= au_dir_roflags; ++ AuDbg("0%o\n", wbrfd.oflags); ++ if (unlikely(wbrfd.oflags & ~valid)) ++ goto out; ++ } ++ ++ fd = get_unused_fd(); ++ err = fd; ++ if (unlikely(fd < 0)) ++ goto out; ++ ++ h_file = ERR_PTR(-EINVAL); ++ wbi = 0; ++ br = NULL; ++ sb = path->dentry->d_sb; ++ root = sb->s_root; ++ aufs_read_lock(root, AuLock_IR); ++ bend = au_sbend(sb); ++ if (wbrfd.brid >= 0) { ++ wbi = au_br_index(sb, wbrfd.brid); ++ if (unlikely(wbi < 0 || wbi > bend)) ++ goto out_unlock; ++ } ++ ++ h_file = ERR_PTR(-ENOENT); ++ br = au_sbr(sb, wbi); ++ if (!au_br_writable(br->br_perm)) { ++ if (arg) ++ goto out_unlock; ++ ++ bindex = wbi + 1; ++ wbi = -1; ++ for (; bindex <= bend; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (au_br_writable(br->br_perm)) { ++ wbi = bindex; ++ br = au_sbr(sb, wbi); ++ break; ++ } ++ } ++ } ++ AuDbg("wbi %d\n", wbi); ++ if (wbi >= 0) ++ h_file = au_h_open(root, wbi, wbrfd.oflags, NULL, ++ /*force_wr*/0); ++ ++out_unlock: ++ aufs_read_unlock(root, AuLock_IR); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out_fd; ++ ++ atomic_dec(&br->br_count); /* cf. au_h_open() */ ++ fd_install(fd, h_file); ++ err = fd; ++ goto out; /* success */ ++ ++out_fd: ++ put_unused_fd(fd); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++long aufs_ioctl_dir(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ long err; ++ struct dentry *dentry; ++ ++ switch (cmd) { ++ case AUFS_CTL_RDU: ++ case AUFS_CTL_RDU_INO: ++ err = au_rdu_ioctl(file, cmd, arg); ++ break; ++ ++ case AUFS_CTL_WBR_FD: ++ err = au_wbr_fd(&file->f_path, (void __user *)arg); ++ break; ++ ++ case AUFS_CTL_IBUSY: ++ err = au_ibusy_ioctl(file, arg); ++ break; ++ ++ case AUFS_CTL_BRINFO: ++ err = au_brinfo_ioctl(file, arg); ++ break; ++ ++ case AUFS_CTL_FHSM_FD: ++ dentry = file->f_dentry; ++ if (IS_ROOT(dentry)) ++ err = au_fhsm_fd(dentry->d_sb, arg); ++ else ++ err = -ENOTTY; ++ break; ++ ++ default: ++ /* do not call the lower */ ++ AuDbg("0x%x\n", cmd); ++ err = -ENOTTY; ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++long aufs_ioctl_nondir(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ long err; ++ ++ switch (cmd) { ++ case AUFS_CTL_MVDOWN: ++ err = au_mvdown(file->f_dentry, (void __user *)arg); ++ break; ++ ++ case AUFS_CTL_WBR_FD: ++ err = au_wbr_fd(&file->f_path, (void __user *)arg); ++ break; ++ ++ default: ++ /* do not call the lower */ ++ AuDbg("0x%x\n", cmd); ++ err = -ENOTTY; ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++#ifdef CONFIG_COMPAT ++long aufs_compat_ioctl_dir(struct file *file, unsigned int cmd, ++ unsigned long arg) ++{ ++ long err; ++ ++ switch (cmd) { ++ case AUFS_CTL_RDU: ++ case AUFS_CTL_RDU_INO: ++ err = au_rdu_compat_ioctl(file, cmd, arg); ++ break; ++ ++ case AUFS_CTL_IBUSY: ++ err = au_ibusy_compat_ioctl(file, arg); ++ break; ++ ++ case AUFS_CTL_BRINFO: ++ err = au_brinfo_compat_ioctl(file, arg); ++ break; ++ ++ default: ++ err = aufs_ioctl_dir(file, cmd, arg); ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++long aufs_compat_ioctl_nondir(struct file *file, unsigned int cmd, ++ unsigned long arg) ++{ ++ return aufs_ioctl_nondir(file, cmd, (unsigned long)compat_ptr(arg)); ++} ++#endif +diff --git a/fs/aufs/loop.c b/fs/aufs/loop.c +new file mode 100644 +index 0000000..1eaf59f +--- /dev/null ++++ b/fs/aufs/loop.c +@@ -0,0 +1,146 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * support for loopback block device as a branch ++ */ ++ ++#include "aufs.h" ++ ++/* added into drivers/block/loop.c */ ++static struct file *(*backing_file_func)(struct super_block *sb); ++ ++/* ++ * test if two lower dentries have overlapping branches. ++ */ ++int au_test_loopback_overlap(struct super_block *sb, struct dentry *h_adding) ++{ ++ struct super_block *h_sb; ++ struct file *backing_file; ++ ++ if (unlikely(!backing_file_func)) { ++ /* don't load "loop" module here */ ++ backing_file_func = symbol_get(loop_backing_file); ++ if (unlikely(!backing_file_func)) ++ /* "loop" module is not loaded */ ++ return 0; ++ } ++ ++ h_sb = h_adding->d_sb; ++ backing_file = backing_file_func(h_sb); ++ if (!backing_file) ++ return 0; ++ ++ h_adding = backing_file->f_dentry; ++ /* ++ * h_adding can be local NFS. ++ * in this case aufs cannot detect the loop. ++ */ ++ if (unlikely(h_adding->d_sb == sb)) ++ return 1; ++ return !!au_test_subdir(h_adding, sb->s_root); ++} ++ ++/* true if a kernel thread named 'loop[0-9].*' accesses a file */ ++int au_test_loopback_kthread(void) ++{ ++ int ret; ++ struct task_struct *tsk = current; ++ char c, comm[sizeof(tsk->comm)]; ++ ++ ret = 0; ++ if (tsk->flags & PF_KTHREAD) { ++ get_task_comm(comm, tsk); ++ c = comm[4]; ++ ret = ('0' <= c && c <= '9' ++ && !strncmp(comm, "loop", 4)); ++ } ++ ++ return ret; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define au_warn_loopback_step 16 ++static int au_warn_loopback_nelem = au_warn_loopback_step; ++static unsigned long *au_warn_loopback_array; ++ ++void au_warn_loopback(struct super_block *h_sb) ++{ ++ int i, new_nelem; ++ unsigned long *a, magic; ++ static DEFINE_SPINLOCK(spin); ++ ++ magic = h_sb->s_magic; ++ spin_lock(&spin); ++ a = au_warn_loopback_array; ++ for (i = 0; i < au_warn_loopback_nelem && *a; i++) ++ if (a[i] == magic) { ++ spin_unlock(&spin); ++ return; ++ } ++ ++ /* h_sb is new to us, print it */ ++ if (i < au_warn_loopback_nelem) { ++ a[i] = magic; ++ goto pr; ++ } ++ ++ /* expand the array */ ++ new_nelem = au_warn_loopback_nelem + au_warn_loopback_step; ++ a = au_kzrealloc(au_warn_loopback_array, ++ au_warn_loopback_nelem * sizeof(unsigned long), ++ new_nelem * sizeof(unsigned long), GFP_ATOMIC); ++ if (a) { ++ au_warn_loopback_nelem = new_nelem; ++ au_warn_loopback_array = a; ++ a[i] = magic; ++ goto pr; ++ } ++ ++ spin_unlock(&spin); ++ AuWarn1("realloc failed, ignored\n"); ++ return; ++ ++pr: ++ spin_unlock(&spin); ++ pr_warn("you may want to try another patch for loopback file " ++ "on %s(0x%lx) branch\n", au_sbtype(h_sb), magic); ++} ++ ++int au_loopback_init(void) ++{ ++ int err; ++ struct super_block *sb __maybe_unused; ++ ++ BUILD_BUG_ON(sizeof(sb->s_magic) != sizeof(unsigned long)); ++ ++ err = 0; ++ au_warn_loopback_array = kcalloc(au_warn_loopback_step, ++ sizeof(unsigned long), GFP_NOFS); ++ if (unlikely(!au_warn_loopback_array)) ++ err = -ENOMEM; ++ ++ return err; ++} ++ ++void au_loopback_fin(void) ++{ ++ if (backing_file_func) ++ symbol_put(loop_backing_file); ++ kfree(au_warn_loopback_array); ++} +diff --git a/fs/aufs/loop.h b/fs/aufs/loop.h +new file mode 100644 +index 0000000..35f7446 +--- /dev/null ++++ b/fs/aufs/loop.h +@@ -0,0 +1,52 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * support for loopback mount as a branch ++ */ ++ ++#ifndef __AUFS_LOOP_H__ ++#define __AUFS_LOOP_H__ ++ ++#ifdef __KERNEL__ ++ ++struct dentry; ++struct super_block; ++ ++#ifdef CONFIG_AUFS_BDEV_LOOP ++/* drivers/block/loop.c */ ++struct file *loop_backing_file(struct super_block *sb); ++ ++/* loop.c */ ++int au_test_loopback_overlap(struct super_block *sb, struct dentry *h_adding); ++int au_test_loopback_kthread(void); ++void au_warn_loopback(struct super_block *h_sb); ++ ++int au_loopback_init(void); ++void au_loopback_fin(void); ++#else ++AuStubInt0(au_test_loopback_overlap, struct super_block *sb, ++ struct dentry *h_adding) ++AuStubInt0(au_test_loopback_kthread, void) ++AuStubVoid(au_warn_loopback, struct super_block *h_sb) ++ ++AuStubInt0(au_loopback_init, void) ++AuStubVoid(au_loopback_fin, void) ++#endif /* BLK_DEV_LOOP */ ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_LOOP_H__ */ +diff --git a/fs/aufs/magic.mk b/fs/aufs/magic.mk +new file mode 100644 +index 0000000..4f83bdf +--- /dev/null ++++ b/fs/aufs/magic.mk +@@ -0,0 +1,30 @@ ++ ++# defined in ${srctree}/fs/fuse/inode.c ++# tristate ++ifdef CONFIG_FUSE_FS ++ccflags-y += -DFUSE_SUPER_MAGIC=0x65735546 ++endif ++ ++# defined in ${srctree}/fs/xfs/xfs_sb.h ++# tristate ++ifdef CONFIG_XFS_FS ++ccflags-y += -DXFS_SB_MAGIC=0x58465342 ++endif ++ ++# defined in ${srctree}/fs/configfs/mount.c ++# tristate ++ifdef CONFIG_CONFIGFS_FS ++ccflags-y += -DCONFIGFS_MAGIC=0x62656570 ++endif ++ ++# defined in ${srctree}/fs/ubifs/ubifs.h ++# tristate ++ifdef CONFIG_UBIFS_FS ++ccflags-y += -DUBIFS_SUPER_MAGIC=0x24051905 ++endif ++ ++# defined in ${srctree}/fs/hfsplus/hfsplus_raw.h ++# tristate ++ifdef CONFIG_HFSPLUS_FS ++ccflags-y += -DHFSPLUS_SUPER_MAGIC=0x482b ++endif +diff --git a/fs/aufs/module.c b/fs/aufs/module.c +new file mode 100644 +index 0000000..e4e04aa +--- /dev/null ++++ b/fs/aufs/module.c +@@ -0,0 +1,222 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * module global variables and operations ++ */ ++ ++#include ++#include ++#include "aufs.h" ++ ++void *au_kzrealloc(void *p, unsigned int nused, unsigned int new_sz, gfp_t gfp) ++{ ++ if (new_sz <= nused) ++ return p; ++ ++ p = krealloc(p, new_sz, gfp); ++ if (p) ++ memset(p + nused, 0, new_sz - nused); ++ return p; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * aufs caches ++ */ ++struct kmem_cache *au_cachep[AuCache_Last]; ++static int __init au_cache_init(void) ++{ ++ au_cachep[AuCache_DINFO] = AuCacheCtor(au_dinfo, au_di_init_once); ++ if (au_cachep[AuCache_DINFO]) ++ /* SLAB_DESTROY_BY_RCU */ ++ au_cachep[AuCache_ICNTNR] = AuCacheCtor(au_icntnr, ++ au_icntnr_init_once); ++ if (au_cachep[AuCache_ICNTNR]) ++ au_cachep[AuCache_FINFO] = AuCacheCtor(au_finfo, ++ au_fi_init_once); ++ if (au_cachep[AuCache_FINFO]) ++ au_cachep[AuCache_VDIR] = AuCache(au_vdir); ++ if (au_cachep[AuCache_VDIR]) ++ au_cachep[AuCache_DEHSTR] = AuCache(au_vdir_dehstr); ++ if (au_cachep[AuCache_DEHSTR]) ++ return 0; ++ ++ return -ENOMEM; ++} ++ ++static void au_cache_fin(void) ++{ ++ int i; ++ ++ /* ++ * Make sure all delayed rcu free inodes are flushed before we ++ * destroy cache. ++ */ ++ rcu_barrier(); ++ ++ /* excluding AuCache_HNOTIFY */ ++ BUILD_BUG_ON(AuCache_HNOTIFY + 1 != AuCache_Last); ++ for (i = 0; i < AuCache_HNOTIFY; i++) ++ if (au_cachep[i]) { ++ kmem_cache_destroy(au_cachep[i]); ++ au_cachep[i] = NULL; ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_dir_roflags; ++ ++#ifdef CONFIG_AUFS_SBILIST ++/* ++ * iterate_supers_type() doesn't protect us from ++ * remounting (branch management) ++ */ ++struct au_sphlhead au_sbilist; ++#endif ++ ++struct lock_class_key au_lc_key[AuLcKey_Last]; ++ ++/* ++ * functions for module interface. ++ */ ++MODULE_LICENSE("GPL"); ++/* MODULE_LICENSE("GPL v2"); */ ++MODULE_AUTHOR("Junjiro R. Okajima "); ++MODULE_DESCRIPTION(AUFS_NAME ++ " -- Advanced multi layered unification filesystem"); ++MODULE_VERSION(AUFS_VERSION); ++MODULE_ALIAS_FS(AUFS_NAME); ++ ++/* this module parameter has no meaning when SYSFS is disabled */ ++int sysaufs_brs = 1; ++MODULE_PARM_DESC(brs, "use /fs/aufs/si_*/brN"); ++module_param_named(brs, sysaufs_brs, int, S_IRUGO); ++ ++/* this module parameter has no meaning when USER_NS is disabled */ ++bool au_userns; ++MODULE_PARM_DESC(allow_userns, "allow unprivileged to mount under userns"); ++module_param_named(allow_userns, au_userns, bool, S_IRUGO); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static char au_esc_chars[0x20 + 3]; /* 0x01-0x20, backslash, del, and NULL */ ++ ++int au_seq_path(struct seq_file *seq, struct path *path) ++{ ++ int err; ++ ++ err = seq_path(seq, path, au_esc_chars); ++ if (err > 0) ++ err = 0; ++ else if (err < 0) ++ err = -ENOMEM; ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int __init aufs_init(void) ++{ ++ int err, i; ++ char *p; ++ ++ p = au_esc_chars; ++ for (i = 1; i <= ' '; i++) ++ *p++ = i; ++ *p++ = '\\'; ++ *p++ = '\x7f'; ++ *p = 0; ++ ++ au_dir_roflags = au_file_roflags(O_DIRECTORY | O_LARGEFILE); ++ ++ memcpy(aufs_iop_nogetattr, aufs_iop, sizeof(aufs_iop)); ++ for (i = 0; i < AuIop_Last; i++) ++ aufs_iop_nogetattr[i].getattr = NULL; ++ ++ au_sbilist_init(); ++ sysaufs_brs_init(); ++ au_debug_init(); ++ au_dy_init(); ++ err = sysaufs_init(); ++ if (unlikely(err)) ++ goto out; ++ err = au_procfs_init(); ++ if (unlikely(err)) ++ goto out_sysaufs; ++ err = au_wkq_init(); ++ if (unlikely(err)) ++ goto out_procfs; ++ err = au_loopback_init(); ++ if (unlikely(err)) ++ goto out_wkq; ++ err = au_hnotify_init(); ++ if (unlikely(err)) ++ goto out_loopback; ++ err = au_sysrq_init(); ++ if (unlikely(err)) ++ goto out_hin; ++ err = au_cache_init(); ++ if (unlikely(err)) ++ goto out_sysrq; ++ ++ aufs_fs_type.fs_flags |= au_userns ? FS_USERNS_MOUNT : 0; ++ err = register_filesystem(&aufs_fs_type); ++ if (unlikely(err)) ++ goto out_cache; ++ ++ /* since we define pr_fmt, call printk directly */ ++ printk(KERN_INFO AUFS_NAME " " AUFS_VERSION "\n"); ++ goto out; /* success */ ++ ++out_cache: ++ au_cache_fin(); ++out_sysrq: ++ au_sysrq_fin(); ++out_hin: ++ au_hnotify_fin(); ++out_loopback: ++ au_loopback_fin(); ++out_wkq: ++ au_wkq_fin(); ++out_procfs: ++ au_procfs_fin(); ++out_sysaufs: ++ sysaufs_fin(); ++ au_dy_fin(); ++out: ++ return err; ++} ++ ++static void __exit aufs_exit(void) ++{ ++ unregister_filesystem(&aufs_fs_type); ++ au_cache_fin(); ++ au_sysrq_fin(); ++ au_hnotify_fin(); ++ au_loopback_fin(); ++ au_wkq_fin(); ++ au_procfs_fin(); ++ sysaufs_fin(); ++ au_dy_fin(); ++} ++ ++module_init(aufs_init); ++module_exit(aufs_exit); +diff --git a/fs/aufs/module.h b/fs/aufs/module.h +new file mode 100644 +index 0000000..90c3c8f +--- /dev/null ++++ b/fs/aufs/module.h +@@ -0,0 +1,105 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * module initialization and module-global ++ */ ++ ++#ifndef __AUFS_MODULE_H__ ++#define __AUFS_MODULE_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++ ++struct path; ++struct seq_file; ++ ++/* module parameters */ ++extern int sysaufs_brs; ++extern bool au_userns; ++ ++/* ---------------------------------------------------------------------- */ ++ ++extern int au_dir_roflags; ++ ++enum { ++ AuLcNonDir_FIINFO, ++ AuLcNonDir_DIINFO, ++ AuLcNonDir_IIINFO, ++ ++ AuLcDir_FIINFO, ++ AuLcDir_DIINFO, ++ AuLcDir_IIINFO, ++ ++ AuLcSymlink_DIINFO, ++ AuLcSymlink_IIINFO, ++ ++ AuLcKey_Last ++}; ++extern struct lock_class_key au_lc_key[AuLcKey_Last]; ++ ++void *au_kzrealloc(void *p, unsigned int nused, unsigned int new_sz, gfp_t gfp); ++int au_seq_path(struct seq_file *seq, struct path *path); ++ ++#ifdef CONFIG_PROC_FS ++/* procfs.c */ ++int __init au_procfs_init(void); ++void au_procfs_fin(void); ++#else ++AuStubInt0(au_procfs_init, void); ++AuStubVoid(au_procfs_fin, void); ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* kmem cache */ ++enum { ++ AuCache_DINFO, ++ AuCache_ICNTNR, ++ AuCache_FINFO, ++ AuCache_VDIR, ++ AuCache_DEHSTR, ++ AuCache_HNOTIFY, /* must be last */ ++ AuCache_Last ++}; ++ ++#define AuCacheFlags (SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD) ++#define AuCache(type) KMEM_CACHE(type, AuCacheFlags) ++#define AuCacheCtor(type, ctor) \ ++ kmem_cache_create(#type, sizeof(struct type), \ ++ __alignof__(struct type), AuCacheFlags, ctor) ++ ++extern struct kmem_cache *au_cachep[]; ++ ++#define AuCacheFuncs(name, index) \ ++static inline struct au_##name *au_cache_alloc_##name(void) \ ++{ return kmem_cache_alloc(au_cachep[AuCache_##index], GFP_NOFS); } \ ++static inline void au_cache_free_##name(struct au_##name *p) \ ++{ kmem_cache_free(au_cachep[AuCache_##index], p); } ++ ++AuCacheFuncs(dinfo, DINFO); ++AuCacheFuncs(icntnr, ICNTNR); ++AuCacheFuncs(finfo, FINFO); ++AuCacheFuncs(vdir, VDIR); ++AuCacheFuncs(vdir_dehstr, DEHSTR); ++#ifdef CONFIG_AUFS_HNOTIFY ++AuCacheFuncs(hnotify, HNOTIFY); ++#endif ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_MODULE_H__ */ +diff --git a/fs/aufs/mvdown.c b/fs/aufs/mvdown.c +new file mode 100644 +index 0000000..e660c8f +--- /dev/null ++++ b/fs/aufs/mvdown.c +@@ -0,0 +1,703 @@ ++/* ++ * Copyright (C) 2011-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * move-down, opposite of copy-up ++ */ ++ ++#include "aufs.h" ++ ++struct au_mvd_args { ++ struct { ++ struct super_block *h_sb; ++ struct dentry *h_parent; ++ struct au_hinode *hdir; ++ struct inode *h_dir, *h_inode; ++ struct au_pin pin; ++ } info[AUFS_MVDOWN_NARRAY]; ++ ++ struct aufs_mvdown mvdown; ++ struct dentry *dentry, *parent; ++ struct inode *inode, *dir; ++ struct super_block *sb; ++ aufs_bindex_t bopq, bwh, bfound; ++ unsigned char rename_lock; ++}; ++ ++#define mvd_errno mvdown.au_errno ++#define mvd_bsrc mvdown.stbr[AUFS_MVDOWN_UPPER].bindex ++#define mvd_src_brid mvdown.stbr[AUFS_MVDOWN_UPPER].brid ++#define mvd_bdst mvdown.stbr[AUFS_MVDOWN_LOWER].bindex ++#define mvd_dst_brid mvdown.stbr[AUFS_MVDOWN_LOWER].brid ++ ++#define mvd_h_src_sb info[AUFS_MVDOWN_UPPER].h_sb ++#define mvd_h_src_parent info[AUFS_MVDOWN_UPPER].h_parent ++#define mvd_hdir_src info[AUFS_MVDOWN_UPPER].hdir ++#define mvd_h_src_dir info[AUFS_MVDOWN_UPPER].h_dir ++#define mvd_h_src_inode info[AUFS_MVDOWN_UPPER].h_inode ++#define mvd_pin_src info[AUFS_MVDOWN_UPPER].pin ++ ++#define mvd_h_dst_sb info[AUFS_MVDOWN_LOWER].h_sb ++#define mvd_h_dst_parent info[AUFS_MVDOWN_LOWER].h_parent ++#define mvd_hdir_dst info[AUFS_MVDOWN_LOWER].hdir ++#define mvd_h_dst_dir info[AUFS_MVDOWN_LOWER].h_dir ++#define mvd_h_dst_inode info[AUFS_MVDOWN_LOWER].h_inode ++#define mvd_pin_dst info[AUFS_MVDOWN_LOWER].pin ++ ++#define AU_MVD_PR(flag, ...) do { \ ++ if (flag) \ ++ pr_err(__VA_ARGS__); \ ++ } while (0) ++ ++static int find_lower_writable(struct au_mvd_args *a) ++{ ++ struct super_block *sb; ++ aufs_bindex_t bindex, bend; ++ struct au_branch *br; ++ ++ sb = a->sb; ++ bindex = a->mvd_bsrc; ++ bend = au_sbend(sb); ++ if (a->mvdown.flags & AUFS_MVDOWN_FHSM_LOWER) ++ for (bindex++; bindex <= bend; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (au_br_fhsm(br->br_perm) ++ && (!(au_br_sb(br)->s_flags & MS_RDONLY))) ++ return bindex; ++ } ++ else if (!(a->mvdown.flags & AUFS_MVDOWN_ROLOWER)) ++ for (bindex++; bindex <= bend; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (!au_br_rdonly(br)) ++ return bindex; ++ } ++ else ++ for (bindex++; bindex <= bend; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (!(au_br_sb(br)->s_flags & MS_RDONLY)) { ++ if (au_br_rdonly(br)) ++ a->mvdown.flags ++ |= AUFS_MVDOWN_ROLOWER_R; ++ return bindex; ++ } ++ } ++ ++ return -1; ++} ++ ++/* make the parent dir on bdst */ ++static int au_do_mkdir(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ ++ err = 0; ++ a->mvd_hdir_src = au_hi(a->dir, a->mvd_bsrc); ++ a->mvd_hdir_dst = au_hi(a->dir, a->mvd_bdst); ++ a->mvd_h_src_parent = au_h_dptr(a->parent, a->mvd_bsrc); ++ a->mvd_h_dst_parent = NULL; ++ if (au_dbend(a->parent) >= a->mvd_bdst) ++ a->mvd_h_dst_parent = au_h_dptr(a->parent, a->mvd_bdst); ++ if (!a->mvd_h_dst_parent) { ++ err = au_cpdown_dirs(a->dentry, a->mvd_bdst); ++ if (unlikely(err)) { ++ AU_MVD_PR(dmsg, "cpdown_dirs failed\n"); ++ goto out; ++ } ++ a->mvd_h_dst_parent = au_h_dptr(a->parent, a->mvd_bdst); ++ } ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* lock them all */ ++static int au_do_lock(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ struct dentry *h_trap; ++ ++ a->mvd_h_src_sb = au_sbr_sb(a->sb, a->mvd_bsrc); ++ a->mvd_h_dst_sb = au_sbr_sb(a->sb, a->mvd_bdst); ++ err = au_pin(&a->mvd_pin_dst, a->dentry, a->mvd_bdst, ++ au_opt_udba(a->sb), ++ AuPin_MNT_WRITE | AuPin_DI_LOCKED); ++ AuTraceErr(err); ++ if (unlikely(err)) { ++ AU_MVD_PR(dmsg, "pin_dst failed\n"); ++ goto out; ++ } ++ ++ if (a->mvd_h_src_sb != a->mvd_h_dst_sb) { ++ a->rename_lock = 0; ++ au_pin_init(&a->mvd_pin_src, a->dentry, a->mvd_bsrc, ++ AuLsc_DI_PARENT, AuLsc_I_PARENT3, ++ au_opt_udba(a->sb), ++ AuPin_MNT_WRITE | AuPin_DI_LOCKED); ++ err = au_do_pin(&a->mvd_pin_src); ++ AuTraceErr(err); ++ a->mvd_h_src_dir = a->mvd_h_src_parent->d_inode; ++ if (unlikely(err)) { ++ AU_MVD_PR(dmsg, "pin_src failed\n"); ++ goto out_dst; ++ } ++ goto out; /* success */ ++ } ++ ++ a->rename_lock = 1; ++ au_pin_hdir_unlock(&a->mvd_pin_dst); ++ err = au_pin(&a->mvd_pin_src, a->dentry, a->mvd_bsrc, ++ au_opt_udba(a->sb), ++ AuPin_MNT_WRITE | AuPin_DI_LOCKED); ++ AuTraceErr(err); ++ a->mvd_h_src_dir = a->mvd_h_src_parent->d_inode; ++ if (unlikely(err)) { ++ AU_MVD_PR(dmsg, "pin_src failed\n"); ++ au_pin_hdir_lock(&a->mvd_pin_dst); ++ goto out_dst; ++ } ++ au_pin_hdir_unlock(&a->mvd_pin_src); ++ h_trap = vfsub_lock_rename(a->mvd_h_src_parent, a->mvd_hdir_src, ++ a->mvd_h_dst_parent, a->mvd_hdir_dst); ++ if (h_trap) { ++ err = (h_trap != a->mvd_h_src_parent); ++ if (err) ++ err = (h_trap != a->mvd_h_dst_parent); ++ } ++ BUG_ON(err); /* it should never happen */ ++ if (unlikely(a->mvd_h_src_dir != au_pinned_h_dir(&a->mvd_pin_src))) { ++ err = -EBUSY; ++ AuTraceErr(err); ++ vfsub_unlock_rename(a->mvd_h_src_parent, a->mvd_hdir_src, ++ a->mvd_h_dst_parent, a->mvd_hdir_dst); ++ au_pin_hdir_lock(&a->mvd_pin_src); ++ au_unpin(&a->mvd_pin_src); ++ au_pin_hdir_lock(&a->mvd_pin_dst); ++ goto out_dst; ++ } ++ goto out; /* success */ ++ ++out_dst: ++ au_unpin(&a->mvd_pin_dst); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static void au_do_unlock(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ if (!a->rename_lock) ++ au_unpin(&a->mvd_pin_src); ++ else { ++ vfsub_unlock_rename(a->mvd_h_src_parent, a->mvd_hdir_src, ++ a->mvd_h_dst_parent, a->mvd_hdir_dst); ++ au_pin_hdir_lock(&a->mvd_pin_src); ++ au_unpin(&a->mvd_pin_src); ++ au_pin_hdir_lock(&a->mvd_pin_dst); ++ } ++ au_unpin(&a->mvd_pin_dst); ++} ++ ++/* copy-down the file */ ++static int au_do_cpdown(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ struct au_cp_generic cpg = { ++ .dentry = a->dentry, ++ .bdst = a->mvd_bdst, ++ .bsrc = a->mvd_bsrc, ++ .len = -1, ++ .pin = &a->mvd_pin_dst, ++ .flags = AuCpup_DTIME | AuCpup_HOPEN ++ }; ++ ++ AuDbg("b%d, b%d\n", cpg.bsrc, cpg.bdst); ++ if (a->mvdown.flags & AUFS_MVDOWN_OWLOWER) ++ au_fset_cpup(cpg.flags, OVERWRITE); ++ if (a->mvdown.flags & AUFS_MVDOWN_ROLOWER) ++ au_fset_cpup(cpg.flags, RWDST); ++ err = au_sio_cpdown_simple(&cpg); ++ if (unlikely(err)) ++ AU_MVD_PR(dmsg, "cpdown failed\n"); ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ++ * unlink the whiteout on bdst if exist which may be created by UDBA while we ++ * were sleeping ++ */ ++static int au_do_unlink_wh(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ struct path h_path; ++ struct au_branch *br; ++ struct inode *delegated; ++ ++ br = au_sbr(a->sb, a->mvd_bdst); ++ h_path.dentry = au_wh_lkup(a->mvd_h_dst_parent, &a->dentry->d_name, br); ++ err = PTR_ERR(h_path.dentry); ++ if (IS_ERR(h_path.dentry)) { ++ AU_MVD_PR(dmsg, "wh_lkup failed\n"); ++ goto out; ++ } ++ ++ err = 0; ++ if (h_path.dentry->d_inode) { ++ h_path.mnt = au_br_mnt(br); ++ delegated = NULL; ++ err = vfsub_unlink(a->mvd_h_dst_parent->d_inode, &h_path, ++ &delegated, /*force*/0); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ if (unlikely(err)) ++ AU_MVD_PR(dmsg, "wh_unlink failed\n"); ++ } ++ dput(h_path.dentry); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ++ * unlink the topmost h_dentry ++ */ ++static int au_do_unlink(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ struct path h_path; ++ struct inode *delegated; ++ ++ h_path.mnt = au_sbr_mnt(a->sb, a->mvd_bsrc); ++ h_path.dentry = au_h_dptr(a->dentry, a->mvd_bsrc); ++ delegated = NULL; ++ err = vfsub_unlink(a->mvd_h_src_dir, &h_path, &delegated, /*force*/0); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ if (unlikely(err)) ++ AU_MVD_PR(dmsg, "unlink failed\n"); ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++/* Since mvdown succeeded, we ignore an error of this function */ ++static void au_do_stfs(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ struct au_branch *br; ++ ++ a->mvdown.flags |= AUFS_MVDOWN_STFS_FAILED; ++ br = au_sbr(a->sb, a->mvd_bsrc); ++ err = au_br_stfs(br, &a->mvdown.stbr[AUFS_MVDOWN_UPPER].stfs); ++ if (!err) { ++ br = au_sbr(a->sb, a->mvd_bdst); ++ a->mvdown.stbr[AUFS_MVDOWN_LOWER].brid = br->br_id; ++ err = au_br_stfs(br, &a->mvdown.stbr[AUFS_MVDOWN_LOWER].stfs); ++ } ++ if (!err) ++ a->mvdown.flags &= ~AUFS_MVDOWN_STFS_FAILED; ++ else ++ AU_MVD_PR(dmsg, "statfs failed (%d), ignored\n", err); ++} ++ ++/* ++ * copy-down the file and unlink the bsrc file. ++ * - unlink the bdst whout if exist ++ * - copy-down the file (with whtmp name and rename) ++ * - unlink the bsrc file ++ */ ++static int au_do_mvdown(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ ++ err = au_do_mkdir(dmsg, a); ++ if (!err) ++ err = au_do_lock(dmsg, a); ++ if (unlikely(err)) ++ goto out; ++ ++ /* ++ * do not revert the activities we made on bdst since they should be ++ * harmless in aufs. ++ */ ++ ++ err = au_do_cpdown(dmsg, a); ++ if (!err) ++ err = au_do_unlink_wh(dmsg, a); ++ if (!err && !(a->mvdown.flags & AUFS_MVDOWN_KUPPER)) ++ err = au_do_unlink(dmsg, a); ++ if (unlikely(err)) ++ goto out_unlock; ++ ++ AuDbg("%pd2, 0x%x, %d --> %d\n", ++ a->dentry, a->mvdown.flags, a->mvd_bsrc, a->mvd_bdst); ++ if (find_lower_writable(a) < 0) ++ a->mvdown.flags |= AUFS_MVDOWN_BOTTOM; ++ ++ if (a->mvdown.flags & AUFS_MVDOWN_STFS) ++ au_do_stfs(dmsg, a); ++ ++ /* maintain internal array */ ++ if (!(a->mvdown.flags & AUFS_MVDOWN_KUPPER)) { ++ au_set_h_dptr(a->dentry, a->mvd_bsrc, NULL); ++ au_set_dbstart(a->dentry, a->mvd_bdst); ++ au_set_h_iptr(a->inode, a->mvd_bsrc, NULL, /*flags*/0); ++ au_set_ibstart(a->inode, a->mvd_bdst); ++ } else { ++ /* hide the lower */ ++ au_set_h_dptr(a->dentry, a->mvd_bdst, NULL); ++ au_set_dbend(a->dentry, a->mvd_bsrc); ++ au_set_h_iptr(a->inode, a->mvd_bdst, NULL, /*flags*/0); ++ au_set_ibend(a->inode, a->mvd_bsrc); ++ } ++ if (au_dbend(a->dentry) < a->mvd_bdst) ++ au_set_dbend(a->dentry, a->mvd_bdst); ++ if (au_ibend(a->inode) < a->mvd_bdst) ++ au_set_ibend(a->inode, a->mvd_bdst); ++ ++out_unlock: ++ au_do_unlock(dmsg, a); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* make sure the file is idle */ ++static int au_mvd_args_busy(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err, plinked; ++ ++ err = 0; ++ plinked = !!au_opt_test(au_mntflags(a->sb), PLINK); ++ if (au_dbstart(a->dentry) == a->mvd_bsrc ++ && au_dcount(a->dentry) == 1 ++ && atomic_read(&a->inode->i_count) == 1 ++ /* && a->mvd_h_src_inode->i_nlink == 1 */ ++ && (!plinked || !au_plink_test(a->inode)) ++ && a->inode->i_nlink == 1) ++ goto out; ++ ++ err = -EBUSY; ++ AU_MVD_PR(dmsg, ++ "b%d, d{b%d, c%d?}, i{c%d?, l%u}, hi{l%u}, p{%d, %d}\n", ++ a->mvd_bsrc, au_dbstart(a->dentry), au_dcount(a->dentry), ++ atomic_read(&a->inode->i_count), a->inode->i_nlink, ++ a->mvd_h_src_inode->i_nlink, ++ plinked, plinked ? au_plink_test(a->inode) : 0); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* make sure the parent dir is fine */ ++static int au_mvd_args_parent(const unsigned char dmsg, ++ struct au_mvd_args *a) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ ++ err = 0; ++ if (unlikely(au_alive_dir(a->parent))) { ++ err = -ENOENT; ++ AU_MVD_PR(dmsg, "parent dir is dead\n"); ++ goto out; ++ } ++ ++ a->bopq = au_dbdiropq(a->parent); ++ bindex = au_wbr_nonopq(a->dentry, a->mvd_bdst); ++ AuDbg("b%d\n", bindex); ++ if (unlikely((bindex >= 0 && bindex < a->mvd_bdst) ++ || (a->bopq != -1 && a->bopq < a->mvd_bdst))) { ++ err = -EINVAL; ++ a->mvd_errno = EAU_MVDOWN_OPAQUE; ++ AU_MVD_PR(dmsg, "ancestor is opaque b%d, b%d\n", ++ a->bopq, a->mvd_bdst); ++ } ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_mvd_args_intermediate(const unsigned char dmsg, ++ struct au_mvd_args *a) ++{ ++ int err; ++ struct au_dinfo *dinfo, *tmp; ++ ++ /* lookup the next lower positive entry */ ++ err = -ENOMEM; ++ tmp = au_di_alloc(a->sb, AuLsc_DI_TMP); ++ if (unlikely(!tmp)) ++ goto out; ++ ++ a->bfound = -1; ++ a->bwh = -1; ++ dinfo = au_di(a->dentry); ++ au_di_cp(tmp, dinfo); ++ au_di_swap(tmp, dinfo); ++ ++ /* returns the number of positive dentries */ ++ err = au_lkup_dentry(a->dentry, a->mvd_bsrc + 1, /*type*/0); ++ if (!err) ++ a->bwh = au_dbwh(a->dentry); ++ else if (err > 0) ++ a->bfound = au_dbstart(a->dentry); ++ ++ au_di_swap(tmp, dinfo); ++ au_rw_write_unlock(&tmp->di_rwsem); ++ au_di_free(tmp); ++ if (unlikely(err < 0)) ++ AU_MVD_PR(dmsg, "failed look-up lower\n"); ++ ++ /* ++ * here, we have these cases. ++ * bfound == -1 ++ * no positive dentry under bsrc. there are more sub-cases. ++ * bwh < 0 ++ * there no whiteout, we can safely move-down. ++ * bwh <= bsrc ++ * impossible ++ * bsrc < bwh && bwh < bdst ++ * there is a whiteout on RO branch. cannot proceed. ++ * bwh == bdst ++ * there is a whiteout on the RW target branch. it should ++ * be removed. ++ * bdst < bwh ++ * there is a whiteout somewhere unrelated branch. ++ * -1 < bfound && bfound <= bsrc ++ * impossible. ++ * bfound < bdst ++ * found, but it is on RO branch between bsrc and bdst. cannot ++ * proceed. ++ * bfound == bdst ++ * found, replace it if AUFS_MVDOWN_FORCE is set. otherwise return ++ * error. ++ * bdst < bfound ++ * found, after we create the file on bdst, it will be hidden. ++ */ ++ ++ AuDebugOn(a->bfound == -1 ++ && a->bwh != -1 ++ && a->bwh <= a->mvd_bsrc); ++ AuDebugOn(-1 < a->bfound ++ && a->bfound <= a->mvd_bsrc); ++ ++ err = -EINVAL; ++ if (a->bfound == -1 ++ && a->mvd_bsrc < a->bwh ++ && a->bwh != -1 ++ && a->bwh < a->mvd_bdst) { ++ a->mvd_errno = EAU_MVDOWN_WHITEOUT; ++ AU_MVD_PR(dmsg, "bsrc %d, bdst %d, bfound %d, bwh %d\n", ++ a->mvd_bsrc, a->mvd_bdst, a->bfound, a->bwh); ++ goto out; ++ } else if (a->bfound != -1 && a->bfound < a->mvd_bdst) { ++ a->mvd_errno = EAU_MVDOWN_UPPER; ++ AU_MVD_PR(dmsg, "bdst %d, bfound %d\n", ++ a->mvd_bdst, a->bfound); ++ goto out; ++ } ++ ++ err = 0; /* success */ ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_mvd_args_exist(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ ++ err = 0; ++ if (!(a->mvdown.flags & AUFS_MVDOWN_OWLOWER) ++ && a->bfound == a->mvd_bdst) ++ err = -EEXIST; ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_mvd_args(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ struct au_branch *br; ++ ++ err = -EISDIR; ++ if (unlikely(S_ISDIR(a->inode->i_mode))) ++ goto out; ++ ++ err = -EINVAL; ++ if (!(a->mvdown.flags & AUFS_MVDOWN_BRID_UPPER)) ++ a->mvd_bsrc = au_ibstart(a->inode); ++ else { ++ a->mvd_bsrc = au_br_index(a->sb, a->mvd_src_brid); ++ if (unlikely(a->mvd_bsrc < 0 ++ || (a->mvd_bsrc < au_dbstart(a->dentry) ++ || au_dbend(a->dentry) < a->mvd_bsrc ++ || !au_h_dptr(a->dentry, a->mvd_bsrc)) ++ || (a->mvd_bsrc < au_ibstart(a->inode) ++ || au_ibend(a->inode) < a->mvd_bsrc ++ || !au_h_iptr(a->inode, a->mvd_bsrc)))) { ++ a->mvd_errno = EAU_MVDOWN_NOUPPER; ++ AU_MVD_PR(dmsg, "no upper\n"); ++ goto out; ++ } ++ } ++ if (unlikely(a->mvd_bsrc == au_sbend(a->sb))) { ++ a->mvd_errno = EAU_MVDOWN_BOTTOM; ++ AU_MVD_PR(dmsg, "on the bottom\n"); ++ goto out; ++ } ++ a->mvd_h_src_inode = au_h_iptr(a->inode, a->mvd_bsrc); ++ br = au_sbr(a->sb, a->mvd_bsrc); ++ err = au_br_rdonly(br); ++ if (!(a->mvdown.flags & AUFS_MVDOWN_ROUPPER)) { ++ if (unlikely(err)) ++ goto out; ++ } else if (!(vfsub_native_ro(a->mvd_h_src_inode) ++ || IS_APPEND(a->mvd_h_src_inode))) { ++ if (err) ++ a->mvdown.flags |= AUFS_MVDOWN_ROUPPER_R; ++ /* go on */ ++ } else ++ goto out; ++ ++ err = -EINVAL; ++ if (!(a->mvdown.flags & AUFS_MVDOWN_BRID_LOWER)) { ++ a->mvd_bdst = find_lower_writable(a); ++ if (unlikely(a->mvd_bdst < 0)) { ++ a->mvd_errno = EAU_MVDOWN_BOTTOM; ++ AU_MVD_PR(dmsg, "no writable lower branch\n"); ++ goto out; ++ } ++ } else { ++ a->mvd_bdst = au_br_index(a->sb, a->mvd_dst_brid); ++ if (unlikely(a->mvd_bdst < 0 ++ || au_sbend(a->sb) < a->mvd_bdst)) { ++ a->mvd_errno = EAU_MVDOWN_NOLOWERBR; ++ AU_MVD_PR(dmsg, "no lower brid\n"); ++ goto out; ++ } ++ } ++ ++ err = au_mvd_args_busy(dmsg, a); ++ if (!err) ++ err = au_mvd_args_parent(dmsg, a); ++ if (!err) ++ err = au_mvd_args_intermediate(dmsg, a); ++ if (!err) ++ err = au_mvd_args_exist(dmsg, a); ++ if (!err) ++ AuDbg("b%d, b%d\n", a->mvd_bsrc, a->mvd_bdst); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_mvdown(struct dentry *dentry, struct aufs_mvdown __user *uarg) ++{ ++ int err, e; ++ unsigned char dmsg; ++ struct au_mvd_args *args; ++ struct inode *inode; ++ ++ inode = dentry->d_inode; ++ err = -EPERM; ++ if (unlikely(!capable(CAP_SYS_ADMIN))) ++ goto out; ++ ++ err = -ENOMEM; ++ args = kmalloc(sizeof(*args), GFP_NOFS); ++ if (unlikely(!args)) ++ goto out; ++ ++ err = copy_from_user(&args->mvdown, uarg, sizeof(args->mvdown)); ++ if (!err) ++ err = !access_ok(VERIFY_WRITE, uarg, sizeof(*uarg)); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ goto out_free; ++ } ++ AuDbg("flags 0x%x\n", args->mvdown.flags); ++ args->mvdown.flags &= ~(AUFS_MVDOWN_ROLOWER_R | AUFS_MVDOWN_ROUPPER_R); ++ args->mvdown.au_errno = 0; ++ args->dentry = dentry; ++ args->inode = inode; ++ args->sb = dentry->d_sb; ++ ++ err = -ENOENT; ++ dmsg = !!(args->mvdown.flags & AUFS_MVDOWN_DMSG); ++ args->parent = dget_parent(dentry); ++ args->dir = args->parent->d_inode; ++ mutex_lock_nested(&args->dir->i_mutex, I_MUTEX_PARENT); ++ dput(args->parent); ++ if (unlikely(args->parent != dentry->d_parent)) { ++ AU_MVD_PR(dmsg, "parent dir is moved\n"); ++ goto out_dir; ++ } ++ ++ mutex_lock_nested(&inode->i_mutex, I_MUTEX_CHILD); ++ err = aufs_read_lock(dentry, AuLock_DW | AuLock_FLUSH | AuLock_NOPLMW); ++ if (unlikely(err)) ++ goto out_inode; ++ ++ di_write_lock_parent(args->parent); ++ err = au_mvd_args(dmsg, args); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ err = au_do_mvdown(dmsg, args); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ au_cpup_attr_timesizes(args->dir); ++ au_cpup_attr_timesizes(inode); ++ if (!(args->mvdown.flags & AUFS_MVDOWN_KUPPER)) ++ au_cpup_igen(inode, au_h_iptr(inode, args->mvd_bdst)); ++ /* au_digen_dec(dentry); */ ++ ++out_parent: ++ di_write_unlock(args->parent); ++ aufs_read_unlock(dentry, AuLock_DW); ++out_inode: ++ mutex_unlock(&inode->i_mutex); ++out_dir: ++ mutex_unlock(&args->dir->i_mutex); ++out_free: ++ e = copy_to_user(uarg, &args->mvdown, sizeof(args->mvdown)); ++ if (unlikely(e)) ++ err = -EFAULT; ++ kfree(args); ++out: ++ AuTraceErr(err); ++ return err; ++} +diff --git a/fs/aufs/opts.c b/fs/aufs/opts.c +new file mode 100644 +index 0000000..0363f67 +--- /dev/null ++++ b/fs/aufs/opts.c +@@ -0,0 +1,1878 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * mount options/flags ++ */ ++ ++#include ++#include /* a distribution requires */ ++#include ++#include "aufs.h" ++ ++/* ---------------------------------------------------------------------- */ ++ ++enum { ++ Opt_br, ++ Opt_add, Opt_del, Opt_mod, Opt_append, Opt_prepend, ++ Opt_idel, Opt_imod, ++ Opt_dirwh, Opt_rdcache, Opt_rdblk, Opt_rdhash, ++ Opt_rdblk_def, Opt_rdhash_def, ++ Opt_xino, Opt_noxino, ++ Opt_trunc_xino, Opt_trunc_xino_v, Opt_notrunc_xino, ++ Opt_trunc_xino_path, Opt_itrunc_xino, ++ Opt_trunc_xib, Opt_notrunc_xib, ++ Opt_shwh, Opt_noshwh, ++ Opt_plink, Opt_noplink, Opt_list_plink, ++ Opt_udba, ++ Opt_dio, Opt_nodio, ++ Opt_diropq_a, Opt_diropq_w, ++ Opt_warn_perm, Opt_nowarn_perm, ++ Opt_wbr_copyup, Opt_wbr_create, ++ Opt_fhsm_sec, ++ Opt_refrof, Opt_norefrof, ++ Opt_verbose, Opt_noverbose, ++ Opt_sum, Opt_nosum, Opt_wsum, ++ Opt_dirperm1, Opt_nodirperm1, ++ Opt_acl, Opt_noacl, ++ Opt_tail, Opt_ignore, Opt_ignore_silent, Opt_err ++}; ++ ++static match_table_t options = { ++ {Opt_br, "br=%s"}, ++ {Opt_br, "br:%s"}, ++ ++ {Opt_add, "add=%d:%s"}, ++ {Opt_add, "add:%d:%s"}, ++ {Opt_add, "ins=%d:%s"}, ++ {Opt_add, "ins:%d:%s"}, ++ {Opt_append, "append=%s"}, ++ {Opt_append, "append:%s"}, ++ {Opt_prepend, "prepend=%s"}, ++ {Opt_prepend, "prepend:%s"}, ++ ++ {Opt_del, "del=%s"}, ++ {Opt_del, "del:%s"}, ++ /* {Opt_idel, "idel:%d"}, */ ++ {Opt_mod, "mod=%s"}, ++ {Opt_mod, "mod:%s"}, ++ /* {Opt_imod, "imod:%d:%s"}, */ ++ ++ {Opt_dirwh, "dirwh=%d"}, ++ ++ {Opt_xino, "xino=%s"}, ++ {Opt_noxino, "noxino"}, ++ {Opt_trunc_xino, "trunc_xino"}, ++ {Opt_trunc_xino_v, "trunc_xino_v=%d:%d"}, ++ {Opt_notrunc_xino, "notrunc_xino"}, ++ {Opt_trunc_xino_path, "trunc_xino=%s"}, ++ {Opt_itrunc_xino, "itrunc_xino=%d"}, ++ /* {Opt_zxino, "zxino=%s"}, */ ++ {Opt_trunc_xib, "trunc_xib"}, ++ {Opt_notrunc_xib, "notrunc_xib"}, ++ ++#ifdef CONFIG_PROC_FS ++ {Opt_plink, "plink"}, ++#else ++ {Opt_ignore_silent, "plink"}, ++#endif ++ ++ {Opt_noplink, "noplink"}, ++ ++#ifdef CONFIG_AUFS_DEBUG ++ {Opt_list_plink, "list_plink"}, ++#endif ++ ++ {Opt_udba, "udba=%s"}, ++ ++ {Opt_dio, "dio"}, ++ {Opt_nodio, "nodio"}, ++ ++#ifdef CONFIG_AUFS_FHSM ++ {Opt_fhsm_sec, "fhsm_sec=%d"}, ++#else ++ {Opt_ignore_silent, "fhsm_sec=%d"}, ++#endif ++ ++ {Opt_diropq_a, "diropq=always"}, ++ {Opt_diropq_a, "diropq=a"}, ++ {Opt_diropq_w, "diropq=whiteouted"}, ++ {Opt_diropq_w, "diropq=w"}, ++ ++ {Opt_warn_perm, "warn_perm"}, ++ {Opt_nowarn_perm, "nowarn_perm"}, ++ ++ /* keep them temporary */ ++ {Opt_ignore_silent, "nodlgt"}, ++ {Opt_ignore_silent, "clean_plink"}, ++ ++#ifdef CONFIG_AUFS_SHWH ++ {Opt_shwh, "shwh"}, ++#endif ++ {Opt_noshwh, "noshwh"}, ++ ++ {Opt_dirperm1, "dirperm1"}, ++ {Opt_nodirperm1, "nodirperm1"}, ++ ++ {Opt_refrof, "refrof"}, ++ {Opt_norefrof, "norefrof"}, ++ ++ {Opt_verbose, "verbose"}, ++ {Opt_verbose, "v"}, ++ {Opt_noverbose, "noverbose"}, ++ {Opt_noverbose, "quiet"}, ++ {Opt_noverbose, "q"}, ++ {Opt_noverbose, "silent"}, ++ ++ {Opt_sum, "sum"}, ++ {Opt_nosum, "nosum"}, ++ {Opt_wsum, "wsum"}, ++ ++ {Opt_rdcache, "rdcache=%d"}, ++ {Opt_rdblk, "rdblk=%d"}, ++ {Opt_rdblk_def, "rdblk=def"}, ++ {Opt_rdhash, "rdhash=%d"}, ++ {Opt_rdhash_def, "rdhash=def"}, ++ ++ {Opt_wbr_create, "create=%s"}, ++ {Opt_wbr_create, "create_policy=%s"}, ++ {Opt_wbr_copyup, "cpup=%s"}, ++ {Opt_wbr_copyup, "copyup=%s"}, ++ {Opt_wbr_copyup, "copyup_policy=%s"}, ++ ++ /* generic VFS flag */ ++#ifdef CONFIG_FS_POSIX_ACL ++ {Opt_acl, "acl"}, ++ {Opt_noacl, "noacl"}, ++#else ++ {Opt_ignore_silent, "acl"}, ++ {Opt_ignore_silent, "noacl"}, ++#endif ++ ++ /* internal use for the scripts */ ++ {Opt_ignore_silent, "si=%s"}, ++ ++ {Opt_br, "dirs=%s"}, ++ {Opt_ignore, "debug=%d"}, ++ {Opt_ignore, "delete=whiteout"}, ++ {Opt_ignore, "delete=all"}, ++ {Opt_ignore, "imap=%s"}, ++ ++ /* temporary workaround, due to old mount(8)? */ ++ {Opt_ignore_silent, "relatime"}, ++ ++ {Opt_err, NULL} ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++static const char *au_parser_pattern(int val, match_table_t tbl) ++{ ++ struct match_token *p; ++ ++ p = tbl; ++ while (p->pattern) { ++ if (p->token == val) ++ return p->pattern; ++ p++; ++ } ++ BUG(); ++ return "??"; ++} ++ ++static const char *au_optstr(int *val, match_table_t tbl) ++{ ++ struct match_token *p; ++ int v; ++ ++ v = *val; ++ if (!v) ++ goto out; ++ p = tbl; ++ while (p->pattern) { ++ if (p->token ++ && (v & p->token) == p->token) { ++ *val &= ~p->token; ++ return p->pattern; ++ } ++ p++; ++ } ++ ++out: ++ return NULL; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static match_table_t brperm = { ++ {AuBrPerm_RO, AUFS_BRPERM_RO}, ++ {AuBrPerm_RR, AUFS_BRPERM_RR}, ++ {AuBrPerm_RW, AUFS_BRPERM_RW}, ++ {0, NULL} ++}; ++ ++static match_table_t brattr = { ++ /* general */ ++ {AuBrAttr_COO_REG, AUFS_BRATTR_COO_REG}, ++ {AuBrAttr_COO_ALL, AUFS_BRATTR_COO_ALL}, ++ /* 'unpin' attrib is meaningless since linux-3.18-rc1 */ ++ {AuBrAttr_UNPIN, AUFS_BRATTR_UNPIN}, ++#ifdef CONFIG_AUFS_FHSM ++ {AuBrAttr_FHSM, AUFS_BRATTR_FHSM}, ++#endif ++#ifdef CONFIG_AUFS_XATTR ++ {AuBrAttr_ICEX, AUFS_BRATTR_ICEX}, ++ {AuBrAttr_ICEX_SEC, AUFS_BRATTR_ICEX_SEC}, ++ {AuBrAttr_ICEX_SYS, AUFS_BRATTR_ICEX_SYS}, ++ {AuBrAttr_ICEX_TR, AUFS_BRATTR_ICEX_TR}, ++ {AuBrAttr_ICEX_USR, AUFS_BRATTR_ICEX_USR}, ++ {AuBrAttr_ICEX_OTH, AUFS_BRATTR_ICEX_OTH}, ++#endif ++ ++ /* ro/rr branch */ ++ {AuBrRAttr_WH, AUFS_BRRATTR_WH}, ++ ++ /* rw branch */ ++ {AuBrWAttr_MOO, AUFS_BRWATTR_MOO}, ++ {AuBrWAttr_NoLinkWH, AUFS_BRWATTR_NLWH}, ++ ++ {0, NULL} ++}; ++ ++static int br_attr_val(char *str, match_table_t table, substring_t args[]) ++{ ++ int attr, v; ++ char *p; ++ ++ attr = 0; ++ do { ++ p = strchr(str, '+'); ++ if (p) ++ *p = 0; ++ v = match_token(str, table, args); ++ if (v) { ++ if (v & AuBrAttr_CMOO_Mask) ++ attr &= ~AuBrAttr_CMOO_Mask; ++ attr |= v; ++ } else { ++ if (p) ++ *p = '+'; ++ pr_warn("ignored branch attribute %s\n", str); ++ break; ++ } ++ if (p) ++ str = p + 1; ++ } while (p); ++ ++ return attr; ++} ++ ++static int au_do_optstr_br_attr(au_br_perm_str_t *str, int perm) ++{ ++ int sz; ++ const char *p; ++ char *q; ++ ++ q = str->a; ++ *q = 0; ++ p = au_optstr(&perm, brattr); ++ if (p) { ++ sz = strlen(p); ++ memcpy(q, p, sz + 1); ++ q += sz; ++ } else ++ goto out; ++ ++ do { ++ p = au_optstr(&perm, brattr); ++ if (p) { ++ *q++ = '+'; ++ sz = strlen(p); ++ memcpy(q, p, sz + 1); ++ q += sz; ++ } ++ } while (p); ++ ++out: ++ return q - str->a; ++} ++ ++static int noinline_for_stack br_perm_val(char *perm) ++{ ++ int val, bad, sz; ++ char *p; ++ substring_t args[MAX_OPT_ARGS]; ++ au_br_perm_str_t attr; ++ ++ p = strchr(perm, '+'); ++ if (p) ++ *p = 0; ++ val = match_token(perm, brperm, args); ++ if (!val) { ++ if (p) ++ *p = '+'; ++ pr_warn("ignored branch permission %s\n", perm); ++ val = AuBrPerm_RO; ++ goto out; ++ } ++ if (!p) ++ goto out; ++ ++ val |= br_attr_val(p + 1, brattr, args); ++ ++ bad = 0; ++ switch (val & AuBrPerm_Mask) { ++ case AuBrPerm_RO: ++ case AuBrPerm_RR: ++ bad = val & AuBrWAttr_Mask; ++ val &= ~AuBrWAttr_Mask; ++ break; ++ case AuBrPerm_RW: ++ bad = val & AuBrRAttr_Mask; ++ val &= ~AuBrRAttr_Mask; ++ break; ++ } ++ ++ /* ++ * 'unpin' attrib becomes meaningless since linux-3.18-rc1, but aufs ++ * does not treat it as an error, just warning. ++ * this is a tiny guard for the user operation. ++ */ ++ if (val & AuBrAttr_UNPIN) { ++ bad |= AuBrAttr_UNPIN; ++ val &= ~AuBrAttr_UNPIN; ++ } ++ ++ if (unlikely(bad)) { ++ sz = au_do_optstr_br_attr(&attr, bad); ++ AuDebugOn(!sz); ++ pr_warn("ignored branch attribute %s\n", attr.a); ++ } ++ ++out: ++ return val; ++} ++ ++void au_optstr_br_perm(au_br_perm_str_t *str, int perm) ++{ ++ au_br_perm_str_t attr; ++ const char *p; ++ char *q; ++ int sz; ++ ++ q = str->a; ++ p = au_optstr(&perm, brperm); ++ AuDebugOn(!p || !*p); ++ sz = strlen(p); ++ memcpy(q, p, sz + 1); ++ q += sz; ++ ++ sz = au_do_optstr_br_attr(&attr, perm); ++ if (sz) { ++ *q++ = '+'; ++ memcpy(q, attr.a, sz + 1); ++ } ++ ++ AuDebugOn(strlen(str->a) >= sizeof(str->a)); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static match_table_t udbalevel = { ++ {AuOpt_UDBA_REVAL, "reval"}, ++ {AuOpt_UDBA_NONE, "none"}, ++#ifdef CONFIG_AUFS_HNOTIFY ++ {AuOpt_UDBA_HNOTIFY, "notify"}, /* abstraction */ ++#ifdef CONFIG_AUFS_HFSNOTIFY ++ {AuOpt_UDBA_HNOTIFY, "fsnotify"}, ++#endif ++#endif ++ {-1, NULL} ++}; ++ ++static int noinline_for_stack udba_val(char *str) ++{ ++ substring_t args[MAX_OPT_ARGS]; ++ ++ return match_token(str, udbalevel, args); ++} ++ ++const char *au_optstr_udba(int udba) ++{ ++ return au_parser_pattern(udba, udbalevel); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static match_table_t au_wbr_create_policy = { ++ {AuWbrCreate_TDP, "tdp"}, ++ {AuWbrCreate_TDP, "top-down-parent"}, ++ {AuWbrCreate_RR, "rr"}, ++ {AuWbrCreate_RR, "round-robin"}, ++ {AuWbrCreate_MFS, "mfs"}, ++ {AuWbrCreate_MFS, "most-free-space"}, ++ {AuWbrCreate_MFSV, "mfs:%d"}, ++ {AuWbrCreate_MFSV, "most-free-space:%d"}, ++ ++ {AuWbrCreate_MFSRR, "mfsrr:%d"}, ++ {AuWbrCreate_MFSRRV, "mfsrr:%d:%d"}, ++ {AuWbrCreate_PMFS, "pmfs"}, ++ {AuWbrCreate_PMFSV, "pmfs:%d"}, ++ {AuWbrCreate_PMFSRR, "pmfsrr:%d"}, ++ {AuWbrCreate_PMFSRRV, "pmfsrr:%d:%d"}, ++ ++ {-1, NULL} ++}; ++ ++/* ++ * cf. linux/lib/parser.c and cmdline.c ++ * gave up calling memparse() since it uses simple_strtoull() instead of ++ * kstrto...(). ++ */ ++static int noinline_for_stack ++au_match_ull(substring_t *s, unsigned long long *result) ++{ ++ int err; ++ unsigned int len; ++ char a[32]; ++ ++ err = -ERANGE; ++ len = s->to - s->from; ++ if (len + 1 <= sizeof(a)) { ++ memcpy(a, s->from, len); ++ a[len] = '\0'; ++ err = kstrtoull(a, 0, result); ++ } ++ return err; ++} ++ ++static int au_wbr_mfs_wmark(substring_t *arg, char *str, ++ struct au_opt_wbr_create *create) ++{ ++ int err; ++ unsigned long long ull; ++ ++ err = 0; ++ if (!au_match_ull(arg, &ull)) ++ create->mfsrr_watermark = ull; ++ else { ++ pr_err("bad integer in %s\n", str); ++ err = -EINVAL; ++ } ++ ++ return err; ++} ++ ++static int au_wbr_mfs_sec(substring_t *arg, char *str, ++ struct au_opt_wbr_create *create) ++{ ++ int n, err; ++ ++ err = 0; ++ if (!match_int(arg, &n) && 0 <= n && n <= AUFS_MFS_MAX_SEC) ++ create->mfs_second = n; ++ else { ++ pr_err("bad integer in %s\n", str); ++ err = -EINVAL; ++ } ++ ++ return err; ++} ++ ++static int noinline_for_stack ++au_wbr_create_val(char *str, struct au_opt_wbr_create *create) ++{ ++ int err, e; ++ substring_t args[MAX_OPT_ARGS]; ++ ++ err = match_token(str, au_wbr_create_policy, args); ++ create->wbr_create = err; ++ switch (err) { ++ case AuWbrCreate_MFSRRV: ++ case AuWbrCreate_PMFSRRV: ++ e = au_wbr_mfs_wmark(&args[0], str, create); ++ if (!e) ++ e = au_wbr_mfs_sec(&args[1], str, create); ++ if (unlikely(e)) ++ err = e; ++ break; ++ case AuWbrCreate_MFSRR: ++ case AuWbrCreate_PMFSRR: ++ e = au_wbr_mfs_wmark(&args[0], str, create); ++ if (unlikely(e)) { ++ err = e; ++ break; ++ } ++ /*FALLTHROUGH*/ ++ case AuWbrCreate_MFS: ++ case AuWbrCreate_PMFS: ++ create->mfs_second = AUFS_MFS_DEF_SEC; ++ break; ++ case AuWbrCreate_MFSV: ++ case AuWbrCreate_PMFSV: ++ e = au_wbr_mfs_sec(&args[0], str, create); ++ if (unlikely(e)) ++ err = e; ++ break; ++ } ++ ++ return err; ++} ++ ++const char *au_optstr_wbr_create(int wbr_create) ++{ ++ return au_parser_pattern(wbr_create, au_wbr_create_policy); ++} ++ ++static match_table_t au_wbr_copyup_policy = { ++ {AuWbrCopyup_TDP, "tdp"}, ++ {AuWbrCopyup_TDP, "top-down-parent"}, ++ {AuWbrCopyup_BUP, "bup"}, ++ {AuWbrCopyup_BUP, "bottom-up-parent"}, ++ {AuWbrCopyup_BU, "bu"}, ++ {AuWbrCopyup_BU, "bottom-up"}, ++ {-1, NULL} ++}; ++ ++static int noinline_for_stack au_wbr_copyup_val(char *str) ++{ ++ substring_t args[MAX_OPT_ARGS]; ++ ++ return match_token(str, au_wbr_copyup_policy, args); ++} ++ ++const char *au_optstr_wbr_copyup(int wbr_copyup) ++{ ++ return au_parser_pattern(wbr_copyup, au_wbr_copyup_policy); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static const int lkup_dirflags = LOOKUP_FOLLOW | LOOKUP_DIRECTORY; ++ ++static void dump_opts(struct au_opts *opts) ++{ ++#ifdef CONFIG_AUFS_DEBUG ++ /* reduce stack space */ ++ union { ++ struct au_opt_add *add; ++ struct au_opt_del *del; ++ struct au_opt_mod *mod; ++ struct au_opt_xino *xino; ++ struct au_opt_xino_itrunc *xino_itrunc; ++ struct au_opt_wbr_create *create; ++ } u; ++ struct au_opt *opt; ++ ++ opt = opts->opt; ++ while (opt->type != Opt_tail) { ++ switch (opt->type) { ++ case Opt_add: ++ u.add = &opt->add; ++ AuDbg("add {b%d, %s, 0x%x, %p}\n", ++ u.add->bindex, u.add->pathname, u.add->perm, ++ u.add->path.dentry); ++ break; ++ case Opt_del: ++ case Opt_idel: ++ u.del = &opt->del; ++ AuDbg("del {%s, %p}\n", ++ u.del->pathname, u.del->h_path.dentry); ++ break; ++ case Opt_mod: ++ case Opt_imod: ++ u.mod = &opt->mod; ++ AuDbg("mod {%s, 0x%x, %p}\n", ++ u.mod->path, u.mod->perm, u.mod->h_root); ++ break; ++ case Opt_append: ++ u.add = &opt->add; ++ AuDbg("append {b%d, %s, 0x%x, %p}\n", ++ u.add->bindex, u.add->pathname, u.add->perm, ++ u.add->path.dentry); ++ break; ++ case Opt_prepend: ++ u.add = &opt->add; ++ AuDbg("prepend {b%d, %s, 0x%x, %p}\n", ++ u.add->bindex, u.add->pathname, u.add->perm, ++ u.add->path.dentry); ++ break; ++ case Opt_dirwh: ++ AuDbg("dirwh %d\n", opt->dirwh); ++ break; ++ case Opt_rdcache: ++ AuDbg("rdcache %d\n", opt->rdcache); ++ break; ++ case Opt_rdblk: ++ AuDbg("rdblk %u\n", opt->rdblk); ++ break; ++ case Opt_rdblk_def: ++ AuDbg("rdblk_def\n"); ++ break; ++ case Opt_rdhash: ++ AuDbg("rdhash %u\n", opt->rdhash); ++ break; ++ case Opt_rdhash_def: ++ AuDbg("rdhash_def\n"); ++ break; ++ case Opt_xino: ++ u.xino = &opt->xino; ++ AuDbg("xino {%s %pD}\n", u.xino->path, u.xino->file); ++ break; ++ case Opt_trunc_xino: ++ AuLabel(trunc_xino); ++ break; ++ case Opt_notrunc_xino: ++ AuLabel(notrunc_xino); ++ break; ++ case Opt_trunc_xino_path: ++ case Opt_itrunc_xino: ++ u.xino_itrunc = &opt->xino_itrunc; ++ AuDbg("trunc_xino %d\n", u.xino_itrunc->bindex); ++ break; ++ case Opt_noxino: ++ AuLabel(noxino); ++ break; ++ case Opt_trunc_xib: ++ AuLabel(trunc_xib); ++ break; ++ case Opt_notrunc_xib: ++ AuLabel(notrunc_xib); ++ break; ++ case Opt_shwh: ++ AuLabel(shwh); ++ break; ++ case Opt_noshwh: ++ AuLabel(noshwh); ++ break; ++ case Opt_dirperm1: ++ AuLabel(dirperm1); ++ break; ++ case Opt_nodirperm1: ++ AuLabel(nodirperm1); ++ break; ++ case Opt_plink: ++ AuLabel(plink); ++ break; ++ case Opt_noplink: ++ AuLabel(noplink); ++ break; ++ case Opt_list_plink: ++ AuLabel(list_plink); ++ break; ++ case Opt_udba: ++ AuDbg("udba %d, %s\n", ++ opt->udba, au_optstr_udba(opt->udba)); ++ break; ++ case Opt_dio: ++ AuLabel(dio); ++ break; ++ case Opt_nodio: ++ AuLabel(nodio); ++ break; ++ case Opt_diropq_a: ++ AuLabel(diropq_a); ++ break; ++ case Opt_diropq_w: ++ AuLabel(diropq_w); ++ break; ++ case Opt_warn_perm: ++ AuLabel(warn_perm); ++ break; ++ case Opt_nowarn_perm: ++ AuLabel(nowarn_perm); ++ break; ++ case Opt_refrof: ++ AuLabel(refrof); ++ break; ++ case Opt_norefrof: ++ AuLabel(norefrof); ++ break; ++ case Opt_verbose: ++ AuLabel(verbose); ++ break; ++ case Opt_noverbose: ++ AuLabel(noverbose); ++ break; ++ case Opt_sum: ++ AuLabel(sum); ++ break; ++ case Opt_nosum: ++ AuLabel(nosum); ++ break; ++ case Opt_wsum: ++ AuLabel(wsum); ++ break; ++ case Opt_wbr_create: ++ u.create = &opt->wbr_create; ++ AuDbg("create %d, %s\n", u.create->wbr_create, ++ au_optstr_wbr_create(u.create->wbr_create)); ++ switch (u.create->wbr_create) { ++ case AuWbrCreate_MFSV: ++ case AuWbrCreate_PMFSV: ++ AuDbg("%d sec\n", u.create->mfs_second); ++ break; ++ case AuWbrCreate_MFSRR: ++ AuDbg("%llu watermark\n", ++ u.create->mfsrr_watermark); ++ break; ++ case AuWbrCreate_MFSRRV: ++ case AuWbrCreate_PMFSRRV: ++ AuDbg("%llu watermark, %d sec\n", ++ u.create->mfsrr_watermark, ++ u.create->mfs_second); ++ break; ++ } ++ break; ++ case Opt_wbr_copyup: ++ AuDbg("copyup %d, %s\n", opt->wbr_copyup, ++ au_optstr_wbr_copyup(opt->wbr_copyup)); ++ break; ++ case Opt_fhsm_sec: ++ AuDbg("fhsm_sec %u\n", opt->fhsm_second); ++ break; ++ case Opt_acl: ++ AuLabel(acl); ++ break; ++ case Opt_noacl: ++ AuLabel(noacl); ++ break; ++ default: ++ BUG(); ++ } ++ opt++; ++ } ++#endif ++} ++ ++void au_opts_free(struct au_opts *opts) ++{ ++ struct au_opt *opt; ++ ++ opt = opts->opt; ++ while (opt->type != Opt_tail) { ++ switch (opt->type) { ++ case Opt_add: ++ case Opt_append: ++ case Opt_prepend: ++ path_put(&opt->add.path); ++ break; ++ case Opt_del: ++ case Opt_idel: ++ path_put(&opt->del.h_path); ++ break; ++ case Opt_mod: ++ case Opt_imod: ++ dput(opt->mod.h_root); ++ break; ++ case Opt_xino: ++ fput(opt->xino.file); ++ break; ++ } ++ opt++; ++ } ++} ++ ++static int opt_add(struct au_opt *opt, char *opt_str, unsigned long sb_flags, ++ aufs_bindex_t bindex) ++{ ++ int err; ++ struct au_opt_add *add = &opt->add; ++ char *p; ++ ++ add->bindex = bindex; ++ add->perm = AuBrPerm_RO; ++ add->pathname = opt_str; ++ p = strchr(opt_str, '='); ++ if (p) { ++ *p++ = 0; ++ if (*p) ++ add->perm = br_perm_val(p); ++ } ++ ++ err = vfsub_kern_path(add->pathname, lkup_dirflags, &add->path); ++ if (!err) { ++ if (!p) { ++ add->perm = AuBrPerm_RO; ++ if (au_test_fs_rr(add->path.dentry->d_sb)) ++ add->perm = AuBrPerm_RR; ++ else if (!bindex && !(sb_flags & MS_RDONLY)) ++ add->perm = AuBrPerm_RW; ++ } ++ opt->type = Opt_add; ++ goto out; ++ } ++ pr_err("lookup failed %s (%d)\n", add->pathname, err); ++ err = -EINVAL; ++ ++out: ++ return err; ++} ++ ++static int au_opts_parse_del(struct au_opt_del *del, substring_t args[]) ++{ ++ int err; ++ ++ del->pathname = args[0].from; ++ AuDbg("del path %s\n", del->pathname); ++ ++ err = vfsub_kern_path(del->pathname, lkup_dirflags, &del->h_path); ++ if (unlikely(err)) ++ pr_err("lookup failed %s (%d)\n", del->pathname, err); ++ ++ return err; ++} ++ ++#if 0 /* reserved for future use */ ++static int au_opts_parse_idel(struct super_block *sb, aufs_bindex_t bindex, ++ struct au_opt_del *del, substring_t args[]) ++{ ++ int err; ++ struct dentry *root; ++ ++ err = -EINVAL; ++ root = sb->s_root; ++ aufs_read_lock(root, AuLock_FLUSH); ++ if (bindex < 0 || au_sbend(sb) < bindex) { ++ pr_err("out of bounds, %d\n", bindex); ++ goto out; ++ } ++ ++ err = 0; ++ del->h_path.dentry = dget(au_h_dptr(root, bindex)); ++ del->h_path.mnt = mntget(au_sbr_mnt(sb, bindex)); ++ ++out: ++ aufs_read_unlock(root, !AuLock_IR); ++ return err; ++} ++#endif ++ ++static int noinline_for_stack ++au_opts_parse_mod(struct au_opt_mod *mod, substring_t args[]) ++{ ++ int err; ++ struct path path; ++ char *p; ++ ++ err = -EINVAL; ++ mod->path = args[0].from; ++ p = strchr(mod->path, '='); ++ if (unlikely(!p)) { ++ pr_err("no permssion %s\n", args[0].from); ++ goto out; ++ } ++ ++ *p++ = 0; ++ err = vfsub_kern_path(mod->path, lkup_dirflags, &path); ++ if (unlikely(err)) { ++ pr_err("lookup failed %s (%d)\n", mod->path, err); ++ goto out; ++ } ++ ++ mod->perm = br_perm_val(p); ++ AuDbg("mod path %s, perm 0x%x, %s\n", mod->path, mod->perm, p); ++ mod->h_root = dget(path.dentry); ++ path_put(&path); ++ ++out: ++ return err; ++} ++ ++#if 0 /* reserved for future use */ ++static int au_opts_parse_imod(struct super_block *sb, aufs_bindex_t bindex, ++ struct au_opt_mod *mod, substring_t args[]) ++{ ++ int err; ++ struct dentry *root; ++ ++ err = -EINVAL; ++ root = sb->s_root; ++ aufs_read_lock(root, AuLock_FLUSH); ++ if (bindex < 0 || au_sbend(sb) < bindex) { ++ pr_err("out of bounds, %d\n", bindex); ++ goto out; ++ } ++ ++ err = 0; ++ mod->perm = br_perm_val(args[1].from); ++ AuDbg("mod path %s, perm 0x%x, %s\n", ++ mod->path, mod->perm, args[1].from); ++ mod->h_root = dget(au_h_dptr(root, bindex)); ++ ++out: ++ aufs_read_unlock(root, !AuLock_IR); ++ return err; ++} ++#endif ++ ++static int au_opts_parse_xino(struct super_block *sb, struct au_opt_xino *xino, ++ substring_t args[]) ++{ ++ int err; ++ struct file *file; ++ ++ file = au_xino_create(sb, args[0].from, /*silent*/0); ++ err = PTR_ERR(file); ++ if (IS_ERR(file)) ++ goto out; ++ ++ err = -EINVAL; ++ if (unlikely(file->f_dentry->d_sb == sb)) { ++ fput(file); ++ pr_err("%s must be outside\n", args[0].from); ++ goto out; ++ } ++ ++ err = 0; ++ xino->file = file; ++ xino->path = args[0].from; ++ ++out: ++ return err; ++} ++ ++static int noinline_for_stack ++au_opts_parse_xino_itrunc_path(struct super_block *sb, ++ struct au_opt_xino_itrunc *xino_itrunc, ++ substring_t args[]) ++{ ++ int err; ++ aufs_bindex_t bend, bindex; ++ struct path path; ++ struct dentry *root; ++ ++ err = vfsub_kern_path(args[0].from, lkup_dirflags, &path); ++ if (unlikely(err)) { ++ pr_err("lookup failed %s (%d)\n", args[0].from, err); ++ goto out; ++ } ++ ++ xino_itrunc->bindex = -1; ++ root = sb->s_root; ++ aufs_read_lock(root, AuLock_FLUSH); ++ bend = au_sbend(sb); ++ for (bindex = 0; bindex <= bend; bindex++) { ++ if (au_h_dptr(root, bindex) == path.dentry) { ++ xino_itrunc->bindex = bindex; ++ break; ++ } ++ } ++ aufs_read_unlock(root, !AuLock_IR); ++ path_put(&path); ++ ++ if (unlikely(xino_itrunc->bindex < 0)) { ++ pr_err("no such branch %s\n", args[0].from); ++ err = -EINVAL; ++ } ++ ++out: ++ return err; ++} ++ ++/* called without aufs lock */ ++int au_opts_parse(struct super_block *sb, char *str, struct au_opts *opts) ++{ ++ int err, n, token; ++ aufs_bindex_t bindex; ++ unsigned char skipped; ++ struct dentry *root; ++ struct au_opt *opt, *opt_tail; ++ char *opt_str; ++ /* reduce the stack space */ ++ union { ++ struct au_opt_xino_itrunc *xino_itrunc; ++ struct au_opt_wbr_create *create; ++ } u; ++ struct { ++ substring_t args[MAX_OPT_ARGS]; ++ } *a; ++ ++ err = -ENOMEM; ++ a = kmalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ root = sb->s_root; ++ err = 0; ++ bindex = 0; ++ opt = opts->opt; ++ opt_tail = opt + opts->max_opt - 1; ++ opt->type = Opt_tail; ++ while (!err && (opt_str = strsep(&str, ",")) && *opt_str) { ++ err = -EINVAL; ++ skipped = 0; ++ token = match_token(opt_str, options, a->args); ++ switch (token) { ++ case Opt_br: ++ err = 0; ++ while (!err && (opt_str = strsep(&a->args[0].from, ":")) ++ && *opt_str) { ++ err = opt_add(opt, opt_str, opts->sb_flags, ++ bindex++); ++ if (unlikely(!err && ++opt > opt_tail)) { ++ err = -E2BIG; ++ break; ++ } ++ opt->type = Opt_tail; ++ skipped = 1; ++ } ++ break; ++ case Opt_add: ++ if (unlikely(match_int(&a->args[0], &n))) { ++ pr_err("bad integer in %s\n", opt_str); ++ break; ++ } ++ bindex = n; ++ err = opt_add(opt, a->args[1].from, opts->sb_flags, ++ bindex); ++ if (!err) ++ opt->type = token; ++ break; ++ case Opt_append: ++ err = opt_add(opt, a->args[0].from, opts->sb_flags, ++ /*dummy bindex*/1); ++ if (!err) ++ opt->type = token; ++ break; ++ case Opt_prepend: ++ err = opt_add(opt, a->args[0].from, opts->sb_flags, ++ /*bindex*/0); ++ if (!err) ++ opt->type = token; ++ break; ++ case Opt_del: ++ err = au_opts_parse_del(&opt->del, a->args); ++ if (!err) ++ opt->type = token; ++ break; ++#if 0 /* reserved for future use */ ++ case Opt_idel: ++ del->pathname = "(indexed)"; ++ if (unlikely(match_int(&args[0], &n))) { ++ pr_err("bad integer in %s\n", opt_str); ++ break; ++ } ++ err = au_opts_parse_idel(sb, n, &opt->del, a->args); ++ if (!err) ++ opt->type = token; ++ break; ++#endif ++ case Opt_mod: ++ err = au_opts_parse_mod(&opt->mod, a->args); ++ if (!err) ++ opt->type = token; ++ break; ++#ifdef IMOD /* reserved for future use */ ++ case Opt_imod: ++ u.mod->path = "(indexed)"; ++ if (unlikely(match_int(&a->args[0], &n))) { ++ pr_err("bad integer in %s\n", opt_str); ++ break; ++ } ++ err = au_opts_parse_imod(sb, n, &opt->mod, a->args); ++ if (!err) ++ opt->type = token; ++ break; ++#endif ++ case Opt_xino: ++ err = au_opts_parse_xino(sb, &opt->xino, a->args); ++ if (!err) ++ opt->type = token; ++ break; ++ ++ case Opt_trunc_xino_path: ++ err = au_opts_parse_xino_itrunc_path ++ (sb, &opt->xino_itrunc, a->args); ++ if (!err) ++ opt->type = token; ++ break; ++ ++ case Opt_itrunc_xino: ++ u.xino_itrunc = &opt->xino_itrunc; ++ if (unlikely(match_int(&a->args[0], &n))) { ++ pr_err("bad integer in %s\n", opt_str); ++ break; ++ } ++ u.xino_itrunc->bindex = n; ++ aufs_read_lock(root, AuLock_FLUSH); ++ if (n < 0 || au_sbend(sb) < n) { ++ pr_err("out of bounds, %d\n", n); ++ aufs_read_unlock(root, !AuLock_IR); ++ break; ++ } ++ aufs_read_unlock(root, !AuLock_IR); ++ err = 0; ++ opt->type = token; ++ break; ++ ++ case Opt_dirwh: ++ if (unlikely(match_int(&a->args[0], &opt->dirwh))) ++ break; ++ err = 0; ++ opt->type = token; ++ break; ++ ++ case Opt_rdcache: ++ if (unlikely(match_int(&a->args[0], &n))) { ++ pr_err("bad integer in %s\n", opt_str); ++ break; ++ } ++ if (unlikely(n > AUFS_RDCACHE_MAX)) { ++ pr_err("rdcache must be smaller than %d\n", ++ AUFS_RDCACHE_MAX); ++ break; ++ } ++ opt->rdcache = n; ++ err = 0; ++ opt->type = token; ++ break; ++ case Opt_rdblk: ++ if (unlikely(match_int(&a->args[0], &n) ++ || n < 0 ++ || n > KMALLOC_MAX_SIZE)) { ++ pr_err("bad integer in %s\n", opt_str); ++ break; ++ } ++ if (unlikely(n && n < NAME_MAX)) { ++ pr_err("rdblk must be larger than %d\n", ++ NAME_MAX); ++ break; ++ } ++ opt->rdblk = n; ++ err = 0; ++ opt->type = token; ++ break; ++ case Opt_rdhash: ++ if (unlikely(match_int(&a->args[0], &n) ++ || n < 0 ++ || n * sizeof(struct hlist_head) ++ > KMALLOC_MAX_SIZE)) { ++ pr_err("bad integer in %s\n", opt_str); ++ break; ++ } ++ opt->rdhash = n; ++ err = 0; ++ opt->type = token; ++ break; ++ ++ case Opt_trunc_xino: ++ case Opt_notrunc_xino: ++ case Opt_noxino: ++ case Opt_trunc_xib: ++ case Opt_notrunc_xib: ++ case Opt_shwh: ++ case Opt_noshwh: ++ case Opt_dirperm1: ++ case Opt_nodirperm1: ++ case Opt_plink: ++ case Opt_noplink: ++ case Opt_list_plink: ++ case Opt_dio: ++ case Opt_nodio: ++ case Opt_diropq_a: ++ case Opt_diropq_w: ++ case Opt_warn_perm: ++ case Opt_nowarn_perm: ++ case Opt_refrof: ++ case Opt_norefrof: ++ case Opt_verbose: ++ case Opt_noverbose: ++ case Opt_sum: ++ case Opt_nosum: ++ case Opt_wsum: ++ case Opt_rdblk_def: ++ case Opt_rdhash_def: ++ case Opt_acl: ++ case Opt_noacl: ++ err = 0; ++ opt->type = token; ++ break; ++ ++ case Opt_udba: ++ opt->udba = udba_val(a->args[0].from); ++ if (opt->udba >= 0) { ++ err = 0; ++ opt->type = token; ++ } else ++ pr_err("wrong value, %s\n", opt_str); ++ break; ++ ++ case Opt_wbr_create: ++ u.create = &opt->wbr_create; ++ u.create->wbr_create ++ = au_wbr_create_val(a->args[0].from, u.create); ++ if (u.create->wbr_create >= 0) { ++ err = 0; ++ opt->type = token; ++ } else ++ pr_err("wrong value, %s\n", opt_str); ++ break; ++ case Opt_wbr_copyup: ++ opt->wbr_copyup = au_wbr_copyup_val(a->args[0].from); ++ if (opt->wbr_copyup >= 0) { ++ err = 0; ++ opt->type = token; ++ } else ++ pr_err("wrong value, %s\n", opt_str); ++ break; ++ ++ case Opt_fhsm_sec: ++ if (unlikely(match_int(&a->args[0], &n) ++ || n < 0)) { ++ pr_err("bad integer in %s\n", opt_str); ++ break; ++ } ++ if (sysaufs_brs) { ++ opt->fhsm_second = n; ++ opt->type = token; ++ } else ++ pr_warn("ignored %s\n", opt_str); ++ err = 0; ++ break; ++ ++ case Opt_ignore: ++ pr_warn("ignored %s\n", opt_str); ++ /*FALLTHROUGH*/ ++ case Opt_ignore_silent: ++ skipped = 1; ++ err = 0; ++ break; ++ case Opt_err: ++ pr_err("unknown option %s\n", opt_str); ++ break; ++ } ++ ++ if (!err && !skipped) { ++ if (unlikely(++opt > opt_tail)) { ++ err = -E2BIG; ++ opt--; ++ opt->type = Opt_tail; ++ break; ++ } ++ opt->type = Opt_tail; ++ } ++ } ++ ++ kfree(a); ++ dump_opts(opts); ++ if (unlikely(err)) ++ au_opts_free(opts); ++ ++out: ++ return err; ++} ++ ++static int au_opt_wbr_create(struct super_block *sb, ++ struct au_opt_wbr_create *create) ++{ ++ int err; ++ struct au_sbinfo *sbinfo; ++ ++ SiMustWriteLock(sb); ++ ++ err = 1; /* handled */ ++ sbinfo = au_sbi(sb); ++ if (sbinfo->si_wbr_create_ops->fin) { ++ err = sbinfo->si_wbr_create_ops->fin(sb); ++ if (!err) ++ err = 1; ++ } ++ ++ sbinfo->si_wbr_create = create->wbr_create; ++ sbinfo->si_wbr_create_ops = au_wbr_create_ops + create->wbr_create; ++ switch (create->wbr_create) { ++ case AuWbrCreate_MFSRRV: ++ case AuWbrCreate_MFSRR: ++ case AuWbrCreate_PMFSRR: ++ case AuWbrCreate_PMFSRRV: ++ sbinfo->si_wbr_mfs.mfsrr_watermark = create->mfsrr_watermark; ++ /*FALLTHROUGH*/ ++ case AuWbrCreate_MFS: ++ case AuWbrCreate_MFSV: ++ case AuWbrCreate_PMFS: ++ case AuWbrCreate_PMFSV: ++ sbinfo->si_wbr_mfs.mfs_expire ++ = msecs_to_jiffies(create->mfs_second * MSEC_PER_SEC); ++ break; ++ } ++ ++ if (sbinfo->si_wbr_create_ops->init) ++ sbinfo->si_wbr_create_ops->init(sb); /* ignore */ ++ ++ return err; ++} ++ ++/* ++ * returns, ++ * plus: processed without an error ++ * zero: unprocessed ++ */ ++static int au_opt_simple(struct super_block *sb, struct au_opt *opt, ++ struct au_opts *opts) ++{ ++ int err; ++ struct au_sbinfo *sbinfo; ++ ++ SiMustWriteLock(sb); ++ ++ err = 1; /* handled */ ++ sbinfo = au_sbi(sb); ++ switch (opt->type) { ++ case Opt_udba: ++ sbinfo->si_mntflags &= ~AuOptMask_UDBA; ++ sbinfo->si_mntflags |= opt->udba; ++ opts->given_udba |= opt->udba; ++ break; ++ ++ case Opt_plink: ++ au_opt_set(sbinfo->si_mntflags, PLINK); ++ break; ++ case Opt_noplink: ++ if (au_opt_test(sbinfo->si_mntflags, PLINK)) ++ au_plink_put(sb, /*verbose*/1); ++ au_opt_clr(sbinfo->si_mntflags, PLINK); ++ break; ++ case Opt_list_plink: ++ if (au_opt_test(sbinfo->si_mntflags, PLINK)) ++ au_plink_list(sb); ++ break; ++ ++ case Opt_dio: ++ au_opt_set(sbinfo->si_mntflags, DIO); ++ au_fset_opts(opts->flags, REFRESH_DYAOP); ++ break; ++ case Opt_nodio: ++ au_opt_clr(sbinfo->si_mntflags, DIO); ++ au_fset_opts(opts->flags, REFRESH_DYAOP); ++ break; ++ ++ case Opt_fhsm_sec: ++ au_fhsm_set(sbinfo, opt->fhsm_second); ++ break; ++ ++ case Opt_diropq_a: ++ au_opt_set(sbinfo->si_mntflags, ALWAYS_DIROPQ); ++ break; ++ case Opt_diropq_w: ++ au_opt_clr(sbinfo->si_mntflags, ALWAYS_DIROPQ); ++ break; ++ ++ case Opt_warn_perm: ++ au_opt_set(sbinfo->si_mntflags, WARN_PERM); ++ break; ++ case Opt_nowarn_perm: ++ au_opt_clr(sbinfo->si_mntflags, WARN_PERM); ++ break; ++ ++ case Opt_refrof: ++ au_opt_set(sbinfo->si_mntflags, REFROF); ++ break; ++ case Opt_norefrof: ++ au_opt_clr(sbinfo->si_mntflags, REFROF); ++ break; ++ ++ case Opt_verbose: ++ au_opt_set(sbinfo->si_mntflags, VERBOSE); ++ break; ++ case Opt_noverbose: ++ au_opt_clr(sbinfo->si_mntflags, VERBOSE); ++ break; ++ ++ case Opt_sum: ++ au_opt_set(sbinfo->si_mntflags, SUM); ++ break; ++ case Opt_wsum: ++ au_opt_clr(sbinfo->si_mntflags, SUM); ++ au_opt_set(sbinfo->si_mntflags, SUM_W); ++ case Opt_nosum: ++ au_opt_clr(sbinfo->si_mntflags, SUM); ++ au_opt_clr(sbinfo->si_mntflags, SUM_W); ++ break; ++ ++ case Opt_wbr_create: ++ err = au_opt_wbr_create(sb, &opt->wbr_create); ++ break; ++ case Opt_wbr_copyup: ++ sbinfo->si_wbr_copyup = opt->wbr_copyup; ++ sbinfo->si_wbr_copyup_ops = au_wbr_copyup_ops + opt->wbr_copyup; ++ break; ++ ++ case Opt_dirwh: ++ sbinfo->si_dirwh = opt->dirwh; ++ break; ++ ++ case Opt_rdcache: ++ sbinfo->si_rdcache ++ = msecs_to_jiffies(opt->rdcache * MSEC_PER_SEC); ++ break; ++ case Opt_rdblk: ++ sbinfo->si_rdblk = opt->rdblk; ++ break; ++ case Opt_rdblk_def: ++ sbinfo->si_rdblk = AUFS_RDBLK_DEF; ++ break; ++ case Opt_rdhash: ++ sbinfo->si_rdhash = opt->rdhash; ++ break; ++ case Opt_rdhash_def: ++ sbinfo->si_rdhash = AUFS_RDHASH_DEF; ++ break; ++ ++ case Opt_shwh: ++ au_opt_set(sbinfo->si_mntflags, SHWH); ++ break; ++ case Opt_noshwh: ++ au_opt_clr(sbinfo->si_mntflags, SHWH); ++ break; ++ ++ case Opt_dirperm1: ++ au_opt_set(sbinfo->si_mntflags, DIRPERM1); ++ break; ++ case Opt_nodirperm1: ++ au_opt_clr(sbinfo->si_mntflags, DIRPERM1); ++ break; ++ ++ case Opt_trunc_xino: ++ au_opt_set(sbinfo->si_mntflags, TRUNC_XINO); ++ break; ++ case Opt_notrunc_xino: ++ au_opt_clr(sbinfo->si_mntflags, TRUNC_XINO); ++ break; ++ ++ case Opt_trunc_xino_path: ++ case Opt_itrunc_xino: ++ err = au_xino_trunc(sb, opt->xino_itrunc.bindex); ++ if (!err) ++ err = 1; ++ break; ++ ++ case Opt_trunc_xib: ++ au_fset_opts(opts->flags, TRUNC_XIB); ++ break; ++ case Opt_notrunc_xib: ++ au_fclr_opts(opts->flags, TRUNC_XIB); ++ break; ++ ++ case Opt_acl: ++ sb->s_flags |= MS_POSIXACL; ++ break; ++ case Opt_noacl: ++ sb->s_flags &= ~MS_POSIXACL; ++ break; ++ ++ default: ++ err = 0; ++ break; ++ } ++ ++ return err; ++} ++ ++/* ++ * returns tri-state. ++ * plus: processed without an error ++ * zero: unprocessed ++ * minus: error ++ */ ++static int au_opt_br(struct super_block *sb, struct au_opt *opt, ++ struct au_opts *opts) ++{ ++ int err, do_refresh; ++ ++ err = 0; ++ switch (opt->type) { ++ case Opt_append: ++ opt->add.bindex = au_sbend(sb) + 1; ++ if (opt->add.bindex < 0) ++ opt->add.bindex = 0; ++ goto add; ++ case Opt_prepend: ++ opt->add.bindex = 0; ++ add: /* indented label */ ++ case Opt_add: ++ err = au_br_add(sb, &opt->add, ++ au_ftest_opts(opts->flags, REMOUNT)); ++ if (!err) { ++ err = 1; ++ au_fset_opts(opts->flags, REFRESH); ++ } ++ break; ++ ++ case Opt_del: ++ case Opt_idel: ++ err = au_br_del(sb, &opt->del, ++ au_ftest_opts(opts->flags, REMOUNT)); ++ if (!err) { ++ err = 1; ++ au_fset_opts(opts->flags, TRUNC_XIB); ++ au_fset_opts(opts->flags, REFRESH); ++ } ++ break; ++ ++ case Opt_mod: ++ case Opt_imod: ++ err = au_br_mod(sb, &opt->mod, ++ au_ftest_opts(opts->flags, REMOUNT), ++ &do_refresh); ++ if (!err) { ++ err = 1; ++ if (do_refresh) ++ au_fset_opts(opts->flags, REFRESH); ++ } ++ break; ++ } ++ ++ return err; ++} ++ ++static int au_opt_xino(struct super_block *sb, struct au_opt *opt, ++ struct au_opt_xino **opt_xino, ++ struct au_opts *opts) ++{ ++ int err; ++ aufs_bindex_t bend, bindex; ++ struct dentry *root, *parent, *h_root; ++ ++ err = 0; ++ switch (opt->type) { ++ case Opt_xino: ++ err = au_xino_set(sb, &opt->xino, ++ !!au_ftest_opts(opts->flags, REMOUNT)); ++ if (unlikely(err)) ++ break; ++ ++ *opt_xino = &opt->xino; ++ au_xino_brid_set(sb, -1); ++ ++ /* safe d_parent access */ ++ parent = opt->xino.file->f_dentry->d_parent; ++ root = sb->s_root; ++ bend = au_sbend(sb); ++ for (bindex = 0; bindex <= bend; bindex++) { ++ h_root = au_h_dptr(root, bindex); ++ if (h_root == parent) { ++ au_xino_brid_set(sb, au_sbr_id(sb, bindex)); ++ break; ++ } ++ } ++ break; ++ ++ case Opt_noxino: ++ au_xino_clr(sb); ++ au_xino_brid_set(sb, -1); ++ *opt_xino = (void *)-1; ++ break; ++ } ++ ++ return err; ++} ++ ++int au_opts_verify(struct super_block *sb, unsigned long sb_flags, ++ unsigned int pending) ++{ ++ int err, fhsm; ++ aufs_bindex_t bindex, bend; ++ unsigned char do_plink, skip, do_free, can_no_dreval; ++ struct au_branch *br; ++ struct au_wbr *wbr; ++ struct dentry *root, *dentry; ++ struct inode *dir, *h_dir; ++ struct au_sbinfo *sbinfo; ++ struct au_hinode *hdir; ++ ++ SiMustAnyLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ AuDebugOn(!(sbinfo->si_mntflags & AuOptMask_UDBA)); ++ ++ if (!(sb_flags & MS_RDONLY)) { ++ if (unlikely(!au_br_writable(au_sbr_perm(sb, 0)))) ++ pr_warn("first branch should be rw\n"); ++ if (unlikely(au_opt_test(sbinfo->si_mntflags, SHWH))) ++ pr_warn_once("shwh should be used with ro\n"); ++ } ++ ++ if (au_opt_test((sbinfo->si_mntflags | pending), UDBA_HNOTIFY) ++ && !au_opt_test(sbinfo->si_mntflags, XINO)) ++ pr_warn_once("udba=*notify requires xino\n"); ++ ++ if (au_opt_test(sbinfo->si_mntflags, DIRPERM1)) ++ pr_warn_once("dirperm1 breaks the protection" ++ " by the permission bits on the lower branch\n"); ++ ++ err = 0; ++ fhsm = 0; ++ root = sb->s_root; ++ dir = root->d_inode; ++ do_plink = !!au_opt_test(sbinfo->si_mntflags, PLINK); ++ can_no_dreval = !!au_opt_test((sbinfo->si_mntflags | pending), ++ UDBA_NONE); ++ bend = au_sbend(sb); ++ for (bindex = 0; !err && bindex <= bend; bindex++) { ++ skip = 0; ++ h_dir = au_h_iptr(dir, bindex); ++ br = au_sbr(sb, bindex); ++ ++ if ((br->br_perm & AuBrAttr_ICEX) ++ && !h_dir->i_op->listxattr) ++ br->br_perm &= ~AuBrAttr_ICEX; ++#if 0 ++ if ((br->br_perm & AuBrAttr_ICEX_SEC) ++ && (au_br_sb(br)->s_flags & MS_NOSEC)) ++ br->br_perm &= ~AuBrAttr_ICEX_SEC; ++#endif ++ ++ do_free = 0; ++ wbr = br->br_wbr; ++ if (wbr) ++ wbr_wh_read_lock(wbr); ++ ++ if (!au_br_writable(br->br_perm)) { ++ do_free = !!wbr; ++ skip = (!wbr ++ || (!wbr->wbr_whbase ++ && !wbr->wbr_plink ++ && !wbr->wbr_orph)); ++ } else if (!au_br_wh_linkable(br->br_perm)) { ++ /* skip = (!br->br_whbase && !br->br_orph); */ ++ skip = (!wbr || !wbr->wbr_whbase); ++ if (skip && wbr) { ++ if (do_plink) ++ skip = !!wbr->wbr_plink; ++ else ++ skip = !wbr->wbr_plink; ++ } ++ } else { ++ /* skip = (br->br_whbase && br->br_ohph); */ ++ skip = (wbr && wbr->wbr_whbase); ++ if (skip) { ++ if (do_plink) ++ skip = !!wbr->wbr_plink; ++ else ++ skip = !wbr->wbr_plink; ++ } ++ } ++ if (wbr) ++ wbr_wh_read_unlock(wbr); ++ ++ if (can_no_dreval) { ++ dentry = br->br_path.dentry; ++ spin_lock(&dentry->d_lock); ++ if (dentry->d_flags & ++ (DCACHE_OP_REVALIDATE | DCACHE_OP_WEAK_REVALIDATE)) ++ can_no_dreval = 0; ++ spin_unlock(&dentry->d_lock); ++ } ++ ++ if (au_br_fhsm(br->br_perm)) { ++ fhsm++; ++ AuDebugOn(!br->br_fhsm); ++ } ++ ++ if (skip) ++ continue; ++ ++ hdir = au_hi(dir, bindex); ++ au_hn_imtx_lock_nested(hdir, AuLsc_I_PARENT); ++ if (wbr) ++ wbr_wh_write_lock(wbr); ++ err = au_wh_init(br, sb); ++ if (wbr) ++ wbr_wh_write_unlock(wbr); ++ au_hn_imtx_unlock(hdir); ++ ++ if (!err && do_free) { ++ kfree(wbr); ++ br->br_wbr = NULL; ++ } ++ } ++ ++ if (can_no_dreval) ++ au_fset_si(sbinfo, NO_DREVAL); ++ else ++ au_fclr_si(sbinfo, NO_DREVAL); ++ ++ if (fhsm >= 2) { ++ au_fset_si(sbinfo, FHSM); ++ for (bindex = bend; bindex >= 0; bindex--) { ++ br = au_sbr(sb, bindex); ++ if (au_br_fhsm(br->br_perm)) { ++ au_fhsm_set_bottom(sb, bindex); ++ break; ++ } ++ } ++ } else { ++ au_fclr_si(sbinfo, FHSM); ++ au_fhsm_set_bottom(sb, -1); ++ } ++ ++ return err; ++} ++ ++int au_opts_mount(struct super_block *sb, struct au_opts *opts) ++{ ++ int err; ++ unsigned int tmp; ++ aufs_bindex_t bindex, bend; ++ struct au_opt *opt; ++ struct au_opt_xino *opt_xino, xino; ++ struct au_sbinfo *sbinfo; ++ struct au_branch *br; ++ struct inode *dir; ++ ++ SiMustWriteLock(sb); ++ ++ err = 0; ++ opt_xino = NULL; ++ opt = opts->opt; ++ while (err >= 0 && opt->type != Opt_tail) ++ err = au_opt_simple(sb, opt++, opts); ++ if (err > 0) ++ err = 0; ++ else if (unlikely(err < 0)) ++ goto out; ++ ++ /* disable xino and udba temporary */ ++ sbinfo = au_sbi(sb); ++ tmp = sbinfo->si_mntflags; ++ au_opt_clr(sbinfo->si_mntflags, XINO); ++ au_opt_set_udba(sbinfo->si_mntflags, UDBA_REVAL); ++ ++ opt = opts->opt; ++ while (err >= 0 && opt->type != Opt_tail) ++ err = au_opt_br(sb, opt++, opts); ++ if (err > 0) ++ err = 0; ++ else if (unlikely(err < 0)) ++ goto out; ++ ++ bend = au_sbend(sb); ++ if (unlikely(bend < 0)) { ++ err = -EINVAL; ++ pr_err("no branches\n"); ++ goto out; ++ } ++ ++ if (au_opt_test(tmp, XINO)) ++ au_opt_set(sbinfo->si_mntflags, XINO); ++ opt = opts->opt; ++ while (!err && opt->type != Opt_tail) ++ err = au_opt_xino(sb, opt++, &opt_xino, opts); ++ if (unlikely(err)) ++ goto out; ++ ++ err = au_opts_verify(sb, sb->s_flags, tmp); ++ if (unlikely(err)) ++ goto out; ++ ++ /* restore xino */ ++ if (au_opt_test(tmp, XINO) && !opt_xino) { ++ xino.file = au_xino_def(sb); ++ err = PTR_ERR(xino.file); ++ if (IS_ERR(xino.file)) ++ goto out; ++ ++ err = au_xino_set(sb, &xino, /*remount*/0); ++ fput(xino.file); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++ /* restore udba */ ++ tmp &= AuOptMask_UDBA; ++ sbinfo->si_mntflags &= ~AuOptMask_UDBA; ++ sbinfo->si_mntflags |= tmp; ++ bend = au_sbend(sb); ++ for (bindex = 0; bindex <= bend; bindex++) { ++ br = au_sbr(sb, bindex); ++ err = au_hnotify_reset_br(tmp, br, br->br_perm); ++ if (unlikely(err)) ++ AuIOErr("hnotify failed on br %d, %d, ignored\n", ++ bindex, err); ++ /* go on even if err */ ++ } ++ if (au_opt_test(tmp, UDBA_HNOTIFY)) { ++ dir = sb->s_root->d_inode; ++ au_hn_reset(dir, au_hi_flags(dir, /*isdir*/1) & ~AuHi_XINO); ++ } ++ ++out: ++ return err; ++} ++ ++int au_opts_remount(struct super_block *sb, struct au_opts *opts) ++{ ++ int err, rerr; ++ unsigned char no_dreval; ++ struct inode *dir; ++ struct au_opt_xino *opt_xino; ++ struct au_opt *opt; ++ struct au_sbinfo *sbinfo; ++ ++ SiMustWriteLock(sb); ++ ++ err = 0; ++ dir = sb->s_root->d_inode; ++ sbinfo = au_sbi(sb); ++ opt_xino = NULL; ++ opt = opts->opt; ++ while (err >= 0 && opt->type != Opt_tail) { ++ err = au_opt_simple(sb, opt, opts); ++ if (!err) ++ err = au_opt_br(sb, opt, opts); ++ if (!err) ++ err = au_opt_xino(sb, opt, &opt_xino, opts); ++ opt++; ++ } ++ if (err > 0) ++ err = 0; ++ AuTraceErr(err); ++ /* go on even err */ ++ ++ no_dreval = !!au_ftest_si(sbinfo, NO_DREVAL); ++ rerr = au_opts_verify(sb, opts->sb_flags, /*pending*/0); ++ if (unlikely(rerr && !err)) ++ err = rerr; ++ ++ if (no_dreval != !!au_ftest_si(sbinfo, NO_DREVAL)) ++ au_fset_opts(opts->flags, REFRESH_IDOP); ++ ++ if (au_ftest_opts(opts->flags, TRUNC_XIB)) { ++ rerr = au_xib_trunc(sb); ++ if (unlikely(rerr && !err)) ++ err = rerr; ++ } ++ ++ /* will be handled by the caller */ ++ if (!au_ftest_opts(opts->flags, REFRESH) ++ && (opts->given_udba ++ || au_opt_test(sbinfo->si_mntflags, XINO) ++ || au_ftest_opts(opts->flags, REFRESH_IDOP) ++ )) ++ au_fset_opts(opts->flags, REFRESH); ++ ++ AuDbg("status 0x%x\n", opts->flags); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++unsigned int au_opt_udba(struct super_block *sb) ++{ ++ return au_mntflags(sb) & AuOptMask_UDBA; ++} +diff --git a/fs/aufs/opts.h b/fs/aufs/opts.h +new file mode 100644 +index 0000000..50949a0 +--- /dev/null ++++ b/fs/aufs/opts.h +@@ -0,0 +1,212 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * mount options/flags ++ */ ++ ++#ifndef __AUFS_OPTS_H__ ++#define __AUFS_OPTS_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++ ++struct file; ++struct super_block; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* mount flags */ ++#define AuOpt_XINO 1 /* external inode number bitmap ++ and translation table */ ++#define AuOpt_TRUNC_XINO (1 << 1) /* truncate xino files */ ++#define AuOpt_UDBA_NONE (1 << 2) /* users direct branch access */ ++#define AuOpt_UDBA_REVAL (1 << 3) ++#define AuOpt_UDBA_HNOTIFY (1 << 4) ++#define AuOpt_SHWH (1 << 5) /* show whiteout */ ++#define AuOpt_PLINK (1 << 6) /* pseudo-link */ ++#define AuOpt_DIRPERM1 (1 << 7) /* ignore the lower dir's perm ++ bits */ ++#define AuOpt_REFROF (1 << 8) /* unimplemented */ ++#define AuOpt_ALWAYS_DIROPQ (1 << 9) /* policy to creating diropq */ ++#define AuOpt_SUM (1 << 10) /* summation for statfs(2) */ ++#define AuOpt_SUM_W (1 << 11) /* unimplemented */ ++#define AuOpt_WARN_PERM (1 << 12) /* warn when add-branch */ ++#define AuOpt_VERBOSE (1 << 13) /* busy inode when del-branch */ ++#define AuOpt_DIO (1 << 14) /* direct io */ ++ ++#ifndef CONFIG_AUFS_HNOTIFY ++#undef AuOpt_UDBA_HNOTIFY ++#define AuOpt_UDBA_HNOTIFY 0 ++#endif ++#ifndef CONFIG_AUFS_SHWH ++#undef AuOpt_SHWH ++#define AuOpt_SHWH 0 ++#endif ++ ++#define AuOpt_Def (AuOpt_XINO \ ++ | AuOpt_UDBA_REVAL \ ++ | AuOpt_PLINK \ ++ /* | AuOpt_DIRPERM1 */ \ ++ | AuOpt_WARN_PERM) ++#define AuOptMask_UDBA (AuOpt_UDBA_NONE \ ++ | AuOpt_UDBA_REVAL \ ++ | AuOpt_UDBA_HNOTIFY) ++ ++#define au_opt_test(flags, name) (flags & AuOpt_##name) ++#define au_opt_set(flags, name) do { \ ++ BUILD_BUG_ON(AuOpt_##name & AuOptMask_UDBA); \ ++ ((flags) |= AuOpt_##name); \ ++} while (0) ++#define au_opt_set_udba(flags, name) do { \ ++ (flags) &= ~AuOptMask_UDBA; \ ++ ((flags) |= AuOpt_##name); \ ++} while (0) ++#define au_opt_clr(flags, name) do { \ ++ ((flags) &= ~AuOpt_##name); \ ++} while (0) ++ ++static inline unsigned int au_opts_plink(unsigned int mntflags) ++{ ++#ifdef CONFIG_PROC_FS ++ return mntflags; ++#else ++ return mntflags & ~AuOpt_PLINK; ++#endif ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* policies to select one among multiple writable branches */ ++enum { ++ AuWbrCreate_TDP, /* top down parent */ ++ AuWbrCreate_RR, /* round robin */ ++ AuWbrCreate_MFS, /* most free space */ ++ AuWbrCreate_MFSV, /* mfs with seconds */ ++ AuWbrCreate_MFSRR, /* mfs then rr */ ++ AuWbrCreate_MFSRRV, /* mfs then rr with seconds */ ++ AuWbrCreate_PMFS, /* parent and mfs */ ++ AuWbrCreate_PMFSV, /* parent and mfs with seconds */ ++ AuWbrCreate_PMFSRR, /* parent, mfs and round-robin */ ++ AuWbrCreate_PMFSRRV, /* plus seconds */ ++ ++ AuWbrCreate_Def = AuWbrCreate_TDP ++}; ++ ++enum { ++ AuWbrCopyup_TDP, /* top down parent */ ++ AuWbrCopyup_BUP, /* bottom up parent */ ++ AuWbrCopyup_BU, /* bottom up */ ++ ++ AuWbrCopyup_Def = AuWbrCopyup_TDP ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_opt_add { ++ aufs_bindex_t bindex; ++ char *pathname; ++ int perm; ++ struct path path; ++}; ++ ++struct au_opt_del { ++ char *pathname; ++ struct path h_path; ++}; ++ ++struct au_opt_mod { ++ char *path; ++ int perm; ++ struct dentry *h_root; ++}; ++ ++struct au_opt_xino { ++ char *path; ++ struct file *file; ++}; ++ ++struct au_opt_xino_itrunc { ++ aufs_bindex_t bindex; ++}; ++ ++struct au_opt_wbr_create { ++ int wbr_create; ++ int mfs_second; ++ unsigned long long mfsrr_watermark; ++}; ++ ++struct au_opt { ++ int type; ++ union { ++ struct au_opt_xino xino; ++ struct au_opt_xino_itrunc xino_itrunc; ++ struct au_opt_add add; ++ struct au_opt_del del; ++ struct au_opt_mod mod; ++ int dirwh; ++ int rdcache; ++ unsigned int rdblk; ++ unsigned int rdhash; ++ int udba; ++ struct au_opt_wbr_create wbr_create; ++ int wbr_copyup; ++ unsigned int fhsm_second; ++ }; ++}; ++ ++/* opts flags */ ++#define AuOpts_REMOUNT 1 ++#define AuOpts_REFRESH (1 << 1) ++#define AuOpts_TRUNC_XIB (1 << 2) ++#define AuOpts_REFRESH_DYAOP (1 << 3) ++#define AuOpts_REFRESH_IDOP (1 << 4) ++#define au_ftest_opts(flags, name) ((flags) & AuOpts_##name) ++#define au_fset_opts(flags, name) \ ++ do { (flags) |= AuOpts_##name; } while (0) ++#define au_fclr_opts(flags, name) \ ++ do { (flags) &= ~AuOpts_##name; } while (0) ++ ++struct au_opts { ++ struct au_opt *opt; ++ int max_opt; ++ ++ unsigned int given_udba; ++ unsigned int flags; ++ unsigned long sb_flags; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* opts.c */ ++void au_optstr_br_perm(au_br_perm_str_t *str, int perm); ++const char *au_optstr_udba(int udba); ++const char *au_optstr_wbr_copyup(int wbr_copyup); ++const char *au_optstr_wbr_create(int wbr_create); ++ ++void au_opts_free(struct au_opts *opts); ++int au_opts_parse(struct super_block *sb, char *str, struct au_opts *opts); ++int au_opts_verify(struct super_block *sb, unsigned long sb_flags, ++ unsigned int pending); ++int au_opts_mount(struct super_block *sb, struct au_opts *opts); ++int au_opts_remount(struct super_block *sb, struct au_opts *opts); ++ ++unsigned int au_opt_udba(struct super_block *sb); ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_OPTS_H__ */ +diff --git a/fs/aufs/plink.c b/fs/aufs/plink.c +new file mode 100644 +index 0000000..4f372ec +--- /dev/null ++++ b/fs/aufs/plink.c +@@ -0,0 +1,506 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * pseudo-link ++ */ ++ ++#include "aufs.h" ++ ++/* ++ * the pseudo-link maintenance mode. ++ * during a user process maintains the pseudo-links, ++ * prohibit adding a new plink and branch manipulation. ++ * ++ * Flags ++ * NOPLM: ++ * For entry functions which will handle plink, and i_mutex is already held ++ * in VFS. ++ * They cannot wait and should return an error at once. ++ * Callers has to check the error. ++ * NOPLMW: ++ * For entry functions which will handle plink, but i_mutex is not held ++ * in VFS. ++ * They can wait the plink maintenance mode to finish. ++ * ++ * They behave like F_SETLK and F_SETLKW. ++ * If the caller never handle plink, then both flags are unnecessary. ++ */ ++ ++int au_plink_maint(struct super_block *sb, int flags) ++{ ++ int err; ++ pid_t pid, ppid; ++ struct au_sbinfo *sbi; ++ ++ SiMustAnyLock(sb); ++ ++ err = 0; ++ if (!au_opt_test(au_mntflags(sb), PLINK)) ++ goto out; ++ ++ sbi = au_sbi(sb); ++ pid = sbi->si_plink_maint_pid; ++ if (!pid || pid == current->pid) ++ goto out; ++ ++ /* todo: it highly depends upon /sbin/mount.aufs */ ++ rcu_read_lock(); ++ ppid = task_pid_vnr(rcu_dereference(current->real_parent)); ++ rcu_read_unlock(); ++ if (pid == ppid) ++ goto out; ++ ++ if (au_ftest_lock(flags, NOPLMW)) { ++ /* if there is no i_mutex lock in VFS, we don't need to wait */ ++ /* AuDebugOn(!lockdep_depth(current)); */ ++ while (sbi->si_plink_maint_pid) { ++ si_read_unlock(sb); ++ /* gave up wake_up_bit() */ ++ wait_event(sbi->si_plink_wq, !sbi->si_plink_maint_pid); ++ ++ if (au_ftest_lock(flags, FLUSH)) ++ au_nwt_flush(&sbi->si_nowait); ++ si_noflush_read_lock(sb); ++ } ++ } else if (au_ftest_lock(flags, NOPLM)) { ++ AuDbg("ppid %d, pid %d\n", ppid, pid); ++ err = -EAGAIN; ++ } ++ ++out: ++ return err; ++} ++ ++void au_plink_maint_leave(struct au_sbinfo *sbinfo) ++{ ++ spin_lock(&sbinfo->si_plink_maint_lock); ++ sbinfo->si_plink_maint_pid = 0; ++ spin_unlock(&sbinfo->si_plink_maint_lock); ++ wake_up_all(&sbinfo->si_plink_wq); ++} ++ ++int au_plink_maint_enter(struct super_block *sb) ++{ ++ int err; ++ struct au_sbinfo *sbinfo; ++ ++ err = 0; ++ sbinfo = au_sbi(sb); ++ /* make sure i am the only one in this fs */ ++ si_write_lock(sb, AuLock_FLUSH); ++ if (au_opt_test(au_mntflags(sb), PLINK)) { ++ spin_lock(&sbinfo->si_plink_maint_lock); ++ if (!sbinfo->si_plink_maint_pid) ++ sbinfo->si_plink_maint_pid = current->pid; ++ else ++ err = -EBUSY; ++ spin_unlock(&sbinfo->si_plink_maint_lock); ++ } ++ si_write_unlock(sb); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_DEBUG ++void au_plink_list(struct super_block *sb) ++{ ++ int i; ++ struct au_sbinfo *sbinfo; ++ struct hlist_head *plink_hlist; ++ struct au_icntnr *icntnr; ++ ++ SiMustAnyLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK)); ++ AuDebugOn(au_plink_maint(sb, AuLock_NOPLM)); ++ ++ for (i = 0; i < AuPlink_NHASH; i++) { ++ plink_hlist = &sbinfo->si_plink[i].head; ++ rcu_read_lock(); ++ hlist_for_each_entry_rcu(icntnr, plink_hlist, plink) ++ AuDbg("%lu\n", icntnr->vfs_inode.i_ino); ++ rcu_read_unlock(); ++ } ++} ++#endif ++ ++/* is the inode pseudo-linked? */ ++int au_plink_test(struct inode *inode) ++{ ++ int found, i; ++ struct au_sbinfo *sbinfo; ++ struct hlist_head *plink_hlist; ++ struct au_icntnr *icntnr; ++ ++ sbinfo = au_sbi(inode->i_sb); ++ AuRwMustAnyLock(&sbinfo->si_rwsem); ++ AuDebugOn(!au_opt_test(au_mntflags(inode->i_sb), PLINK)); ++ AuDebugOn(au_plink_maint(inode->i_sb, AuLock_NOPLM)); ++ ++ found = 0; ++ i = au_plink_hash(inode->i_ino); ++ plink_hlist = &sbinfo->si_plink[i].head; ++ rcu_read_lock(); ++ hlist_for_each_entry_rcu(icntnr, plink_hlist, plink) ++ if (&icntnr->vfs_inode == inode) { ++ found = 1; ++ break; ++ } ++ rcu_read_unlock(); ++ return found; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * generate a name for plink. ++ * the file will be stored under AUFS_WH_PLINKDIR. ++ */ ++/* 20 is max digits length of ulong 64 */ ++#define PLINK_NAME_LEN ((20 + 1) * 2) ++ ++static int plink_name(char *name, int len, struct inode *inode, ++ aufs_bindex_t bindex) ++{ ++ int rlen; ++ struct inode *h_inode; ++ ++ h_inode = au_h_iptr(inode, bindex); ++ rlen = snprintf(name, len, "%lu.%lu", inode->i_ino, h_inode->i_ino); ++ return rlen; ++} ++ ++struct au_do_plink_lkup_args { ++ struct dentry **errp; ++ struct qstr *tgtname; ++ struct dentry *h_parent; ++ struct au_branch *br; ++}; ++ ++static struct dentry *au_do_plink_lkup(struct qstr *tgtname, ++ struct dentry *h_parent, ++ struct au_branch *br) ++{ ++ struct dentry *h_dentry; ++ struct mutex *h_mtx; ++ ++ h_mtx = &h_parent->d_inode->i_mutex; ++ mutex_lock_nested(h_mtx, AuLsc_I_CHILD2); ++ h_dentry = vfsub_lkup_one(tgtname, h_parent); ++ mutex_unlock(h_mtx); ++ return h_dentry; ++} ++ ++static void au_call_do_plink_lkup(void *args) ++{ ++ struct au_do_plink_lkup_args *a = args; ++ *a->errp = au_do_plink_lkup(a->tgtname, a->h_parent, a->br); ++} ++ ++/* lookup the plink-ed @inode under the branch at @bindex */ ++struct dentry *au_plink_lkup(struct inode *inode, aufs_bindex_t bindex) ++{ ++ struct dentry *h_dentry, *h_parent; ++ struct au_branch *br; ++ struct inode *h_dir; ++ int wkq_err; ++ char a[PLINK_NAME_LEN]; ++ struct qstr tgtname = QSTR_INIT(a, 0); ++ ++ AuDebugOn(au_plink_maint(inode->i_sb, AuLock_NOPLM)); ++ ++ br = au_sbr(inode->i_sb, bindex); ++ h_parent = br->br_wbr->wbr_plink; ++ h_dir = h_parent->d_inode; ++ tgtname.len = plink_name(a, sizeof(a), inode, bindex); ++ ++ if (!uid_eq(current_fsuid(), GLOBAL_ROOT_UID)) { ++ struct au_do_plink_lkup_args args = { ++ .errp = &h_dentry, ++ .tgtname = &tgtname, ++ .h_parent = h_parent, ++ .br = br ++ }; ++ ++ wkq_err = au_wkq_wait(au_call_do_plink_lkup, &args); ++ if (unlikely(wkq_err)) ++ h_dentry = ERR_PTR(wkq_err); ++ } else ++ h_dentry = au_do_plink_lkup(&tgtname, h_parent, br); ++ ++ return h_dentry; ++} ++ ++/* create a pseudo-link */ ++static int do_whplink(struct qstr *tgt, struct dentry *h_parent, ++ struct dentry *h_dentry, struct au_branch *br) ++{ ++ int err; ++ struct path h_path = { ++ .mnt = au_br_mnt(br) ++ }; ++ struct inode *h_dir, *delegated; ++ ++ h_dir = h_parent->d_inode; ++ mutex_lock_nested(&h_dir->i_mutex, AuLsc_I_CHILD2); ++again: ++ h_path.dentry = vfsub_lkup_one(tgt, h_parent); ++ err = PTR_ERR(h_path.dentry); ++ if (IS_ERR(h_path.dentry)) ++ goto out; ++ ++ err = 0; ++ /* wh.plink dir is not monitored */ ++ /* todo: is it really safe? */ ++ if (h_path.dentry->d_inode ++ && h_path.dentry->d_inode != h_dentry->d_inode) { ++ delegated = NULL; ++ err = vfsub_unlink(h_dir, &h_path, &delegated, /*force*/0); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ dput(h_path.dentry); ++ h_path.dentry = NULL; ++ if (!err) ++ goto again; ++ } ++ if (!err && !h_path.dentry->d_inode) { ++ delegated = NULL; ++ err = vfsub_link(h_dentry, h_dir, &h_path, &delegated); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal link\n"); ++ iput(delegated); ++ } ++ } ++ dput(h_path.dentry); ++ ++out: ++ mutex_unlock(&h_dir->i_mutex); ++ return err; ++} ++ ++struct do_whplink_args { ++ int *errp; ++ struct qstr *tgt; ++ struct dentry *h_parent; ++ struct dentry *h_dentry; ++ struct au_branch *br; ++}; ++ ++static void call_do_whplink(void *args) ++{ ++ struct do_whplink_args *a = args; ++ *a->errp = do_whplink(a->tgt, a->h_parent, a->h_dentry, a->br); ++} ++ ++static int whplink(struct dentry *h_dentry, struct inode *inode, ++ aufs_bindex_t bindex, struct au_branch *br) ++{ ++ int err, wkq_err; ++ struct au_wbr *wbr; ++ struct dentry *h_parent; ++ struct inode *h_dir; ++ char a[PLINK_NAME_LEN]; ++ struct qstr tgtname = QSTR_INIT(a, 0); ++ ++ wbr = au_sbr(inode->i_sb, bindex)->br_wbr; ++ h_parent = wbr->wbr_plink; ++ h_dir = h_parent->d_inode; ++ tgtname.len = plink_name(a, sizeof(a), inode, bindex); ++ ++ /* always superio. */ ++ if (!uid_eq(current_fsuid(), GLOBAL_ROOT_UID)) { ++ struct do_whplink_args args = { ++ .errp = &err, ++ .tgt = &tgtname, ++ .h_parent = h_parent, ++ .h_dentry = h_dentry, ++ .br = br ++ }; ++ wkq_err = au_wkq_wait(call_do_whplink, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } else ++ err = do_whplink(&tgtname, h_parent, h_dentry, br); ++ ++ return err; ++} ++ ++/* ++ * create a new pseudo-link for @h_dentry on @bindex. ++ * the linked inode is held in aufs @inode. ++ */ ++void au_plink_append(struct inode *inode, aufs_bindex_t bindex, ++ struct dentry *h_dentry) ++{ ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ struct hlist_head *plink_hlist; ++ struct au_icntnr *icntnr; ++ struct au_sphlhead *sphl; ++ int found, err, cnt, i; ++ ++ sb = inode->i_sb; ++ sbinfo = au_sbi(sb); ++ AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK)); ++ AuDebugOn(au_plink_maint(sb, AuLock_NOPLM)); ++ ++ found = au_plink_test(inode); ++ if (found) ++ return; ++ ++ i = au_plink_hash(inode->i_ino); ++ sphl = sbinfo->si_plink + i; ++ plink_hlist = &sphl->head; ++ au_igrab(inode); ++ ++ spin_lock(&sphl->spin); ++ hlist_for_each_entry(icntnr, plink_hlist, plink) { ++ if (&icntnr->vfs_inode == inode) { ++ found = 1; ++ break; ++ } ++ } ++ if (!found) { ++ icntnr = container_of(inode, struct au_icntnr, vfs_inode); ++ hlist_add_head_rcu(&icntnr->plink, plink_hlist); ++ } ++ spin_unlock(&sphl->spin); ++ if (!found) { ++ cnt = au_sphl_count(sphl); ++#define msg "unexpectedly unblanced or too many pseudo-links" ++ if (cnt > AUFS_PLINK_WARN) ++ AuWarn1(msg ", %d\n", cnt); ++#undef msg ++ err = whplink(h_dentry, inode, bindex, au_sbr(sb, bindex)); ++ if (unlikely(err)) { ++ pr_warn("err %d, damaged pseudo link.\n", err); ++ au_sphl_del_rcu(&icntnr->plink, sphl); ++ iput(&icntnr->vfs_inode); ++ } ++ } else ++ iput(&icntnr->vfs_inode); ++} ++ ++/* free all plinks */ ++void au_plink_put(struct super_block *sb, int verbose) ++{ ++ int i, warned; ++ struct au_sbinfo *sbinfo; ++ struct hlist_head *plink_hlist; ++ struct hlist_node *tmp; ++ struct au_icntnr *icntnr; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK)); ++ AuDebugOn(au_plink_maint(sb, AuLock_NOPLM)); ++ ++ /* no spin_lock since sbinfo is write-locked */ ++ warned = 0; ++ for (i = 0; i < AuPlink_NHASH; i++) { ++ plink_hlist = &sbinfo->si_plink[i].head; ++ if (!warned && verbose && !hlist_empty(plink_hlist)) { ++ pr_warn("pseudo-link is not flushed"); ++ warned = 1; ++ } ++ hlist_for_each_entry_safe(icntnr, tmp, plink_hlist, plink) ++ iput(&icntnr->vfs_inode); ++ INIT_HLIST_HEAD(plink_hlist); ++ } ++} ++ ++void au_plink_clean(struct super_block *sb, int verbose) ++{ ++ struct dentry *root; ++ ++ root = sb->s_root; ++ aufs_write_lock(root); ++ if (au_opt_test(au_mntflags(sb), PLINK)) ++ au_plink_put(sb, verbose); ++ aufs_write_unlock(root); ++} ++ ++static int au_plink_do_half_refresh(struct inode *inode, aufs_bindex_t br_id) ++{ ++ int do_put; ++ aufs_bindex_t bstart, bend, bindex; ++ ++ do_put = 0; ++ bstart = au_ibstart(inode); ++ bend = au_ibend(inode); ++ if (bstart >= 0) { ++ for (bindex = bstart; bindex <= bend; bindex++) { ++ if (!au_h_iptr(inode, bindex) ++ || au_ii_br_id(inode, bindex) != br_id) ++ continue; ++ au_set_h_iptr(inode, bindex, NULL, 0); ++ do_put = 1; ++ break; ++ } ++ if (do_put) ++ for (bindex = bstart; bindex <= bend; bindex++) ++ if (au_h_iptr(inode, bindex)) { ++ do_put = 0; ++ break; ++ } ++ } else ++ do_put = 1; ++ ++ return do_put; ++} ++ ++/* free the plinks on a branch specified by @br_id */ ++void au_plink_half_refresh(struct super_block *sb, aufs_bindex_t br_id) ++{ ++ struct au_sbinfo *sbinfo; ++ struct hlist_head *plink_hlist; ++ struct hlist_node *tmp; ++ struct au_icntnr *icntnr; ++ struct inode *inode; ++ int i, do_put; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK)); ++ AuDebugOn(au_plink_maint(sb, AuLock_NOPLM)); ++ ++ /* no spin_lock since sbinfo is write-locked */ ++ for (i = 0; i < AuPlink_NHASH; i++) { ++ plink_hlist = &sbinfo->si_plink[i].head; ++ hlist_for_each_entry_safe(icntnr, tmp, plink_hlist, plink) { ++ inode = au_igrab(&icntnr->vfs_inode); ++ ii_write_lock_child(inode); ++ do_put = au_plink_do_half_refresh(inode, br_id); ++ if (do_put) { ++ hlist_del(&icntnr->plink); ++ iput(inode); ++ } ++ ii_write_unlock(inode); ++ iput(inode); ++ } ++ } ++} +diff --git a/fs/aufs/poll.c b/fs/aufs/poll.c +new file mode 100644 +index 0000000..eea19e7 +--- /dev/null ++++ b/fs/aufs/poll.c +@@ -0,0 +1,52 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * poll operation ++ * There is only one filesystem which implements ->poll operation, currently. ++ */ ++ ++#include "aufs.h" ++ ++unsigned int aufs_poll(struct file *file, poll_table *wait) ++{ ++ unsigned int mask; ++ int err; ++ struct file *h_file; ++ struct super_block *sb; ++ ++ /* We should pretend an error happened. */ ++ mask = POLLERR /* | POLLIN | POLLOUT */; ++ sb = file->f_dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); ++ ++ h_file = au_read_pre(file, /*keep_fi*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ /* it is not an error if h_file has no operation */ ++ mask = DEFAULT_POLLMASK; ++ if (h_file->f_op->poll) ++ mask = h_file->f_op->poll(h_file, wait); ++ fput(h_file); /* instead of au_read_post() */ ++ ++out: ++ si_read_unlock(sb); ++ AuTraceErr((int)mask); ++ return mask; ++} +diff --git a/fs/aufs/posix_acl.c b/fs/aufs/posix_acl.c +new file mode 100644 +index 0000000..89b4127 +--- /dev/null ++++ b/fs/aufs/posix_acl.c +@@ -0,0 +1,98 @@ ++/* ++ * Copyright (C) 2014-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * posix acl operations ++ */ ++ ++#include ++#include "aufs.h" ++ ++struct posix_acl *aufs_get_acl(struct inode *inode, int type) ++{ ++ struct posix_acl *acl; ++ int err; ++ aufs_bindex_t bindex; ++ struct inode *h_inode; ++ struct super_block *sb; ++ ++ acl = NULL; ++ sb = inode->i_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ ii_read_lock_child(inode); ++ if (!(sb->s_flags & MS_POSIXACL)) ++ goto out; ++ ++ bindex = au_ibstart(inode); ++ h_inode = au_h_iptr(inode, bindex); ++ if (unlikely(!h_inode ++ || ((h_inode->i_mode & S_IFMT) ++ != (inode->i_mode & S_IFMT)))) { ++ err = au_busy_or_stale(); ++ acl = ERR_PTR(err); ++ goto out; ++ } ++ ++ /* always topmost only */ ++ acl = get_acl(h_inode, type); ++ ++out: ++ ii_read_unlock(inode); ++ si_read_unlock(sb); ++ ++ AuTraceErrPtr(acl); ++ return acl; ++} ++ ++int aufs_set_acl(struct inode *inode, struct posix_acl *acl, int type) ++{ ++ int err; ++ ssize_t ssz; ++ struct dentry *dentry; ++ struct au_srxattr arg = { ++ .type = AU_ACL_SET, ++ .u.acl_set = { ++ .acl = acl, ++ .type = type ++ }, ++ }; ++ ++ mutex_lock(&inode->i_mutex); ++ if (inode->i_ino == AUFS_ROOT_INO) ++ dentry = dget(inode->i_sb->s_root); ++ else { ++ dentry = d_find_alias(inode); ++ if (!dentry) ++ dentry = d_find_any_alias(inode); ++ if (!dentry) { ++ pr_warn("cannot handle this inode, " ++ "please report to aufs-users ML\n"); ++ err = -ENOENT; ++ goto out; ++ } ++ } ++ ++ ssz = au_srxattr(dentry, &arg); ++ dput(dentry); ++ err = ssz; ++ if (ssz >= 0) ++ err = 0; ++ ++out: ++ mutex_unlock(&inode->i_mutex); ++ return err; ++} +diff --git a/fs/aufs/procfs.c b/fs/aufs/procfs.c +new file mode 100644 +index 0000000..a334330 +--- /dev/null ++++ b/fs/aufs/procfs.c +@@ -0,0 +1,169 @@ ++/* ++ * Copyright (C) 2010-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * procfs interfaces ++ */ ++ ++#include ++#include "aufs.h" ++ ++static int au_procfs_plm_release(struct inode *inode, struct file *file) ++{ ++ struct au_sbinfo *sbinfo; ++ ++ sbinfo = file->private_data; ++ if (sbinfo) { ++ au_plink_maint_leave(sbinfo); ++ kobject_put(&sbinfo->si_kobj); ++ } ++ ++ return 0; ++} ++ ++static void au_procfs_plm_write_clean(struct file *file) ++{ ++ struct au_sbinfo *sbinfo; ++ ++ sbinfo = file->private_data; ++ if (sbinfo) ++ au_plink_clean(sbinfo->si_sb, /*verbose*/0); ++} ++ ++static int au_procfs_plm_write_si(struct file *file, unsigned long id) ++{ ++ int err; ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ ++ err = -EBUSY; ++ if (unlikely(file->private_data)) ++ goto out; ++ ++ sb = NULL; ++ /* don't use au_sbilist_lock() here */ ++ spin_lock(&au_sbilist.spin); ++ hlist_for_each_entry(sbinfo, &au_sbilist.head, si_list) ++ if (id == sysaufs_si_id(sbinfo)) { ++ kobject_get(&sbinfo->si_kobj); ++ sb = sbinfo->si_sb; ++ break; ++ } ++ spin_unlock(&au_sbilist.spin); ++ ++ err = -EINVAL; ++ if (unlikely(!sb)) ++ goto out; ++ ++ err = au_plink_maint_enter(sb); ++ if (!err) ++ /* keep kobject_get() */ ++ file->private_data = sbinfo; ++ else ++ kobject_put(&sbinfo->si_kobj); ++out: ++ return err; ++} ++ ++/* ++ * Accept a valid "si=xxxx" only. ++ * Once it is accepted successfully, accept "clean" too. ++ */ ++static ssize_t au_procfs_plm_write(struct file *file, const char __user *ubuf, ++ size_t count, loff_t *ppos) ++{ ++ ssize_t err; ++ unsigned long id; ++ /* last newline is allowed */ ++ char buf[3 + sizeof(unsigned long) * 2 + 1]; ++ ++ err = -EACCES; ++ if (unlikely(!capable(CAP_SYS_ADMIN))) ++ goto out; ++ ++ err = -EINVAL; ++ if (unlikely(count > sizeof(buf))) ++ goto out; ++ ++ err = copy_from_user(buf, ubuf, count); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ goto out; ++ } ++ buf[count] = 0; ++ ++ err = -EINVAL; ++ if (!strcmp("clean", buf)) { ++ au_procfs_plm_write_clean(file); ++ goto out_success; ++ } else if (unlikely(strncmp("si=", buf, 3))) ++ goto out; ++ ++ err = kstrtoul(buf + 3, 16, &id); ++ if (unlikely(err)) ++ goto out; ++ ++ err = au_procfs_plm_write_si(file, id); ++ if (unlikely(err)) ++ goto out; ++ ++out_success: ++ err = count; /* success */ ++out: ++ return err; ++} ++ ++static const struct file_operations au_procfs_plm_fop = { ++ .write = au_procfs_plm_write, ++ .release = au_procfs_plm_release, ++ .owner = THIS_MODULE ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct proc_dir_entry *au_procfs_dir; ++ ++void au_procfs_fin(void) ++{ ++ remove_proc_entry(AUFS_PLINK_MAINT_NAME, au_procfs_dir); ++ remove_proc_entry(AUFS_PLINK_MAINT_DIR, NULL); ++} ++ ++int __init au_procfs_init(void) ++{ ++ int err; ++ struct proc_dir_entry *entry; ++ ++ err = -ENOMEM; ++ au_procfs_dir = proc_mkdir(AUFS_PLINK_MAINT_DIR, NULL); ++ if (unlikely(!au_procfs_dir)) ++ goto out; ++ ++ entry = proc_create(AUFS_PLINK_MAINT_NAME, S_IFREG | S_IWUSR, ++ au_procfs_dir, &au_procfs_plm_fop); ++ if (unlikely(!entry)) ++ goto out_dir; ++ ++ err = 0; ++ goto out; /* success */ ++ ++ ++out_dir: ++ remove_proc_entry(AUFS_PLINK_MAINT_DIR, NULL); ++out: ++ return err; ++} +diff --git a/fs/aufs/rdu.c b/fs/aufs/rdu.c +new file mode 100644 +index 0000000..d22b2f8 +--- /dev/null ++++ b/fs/aufs/rdu.c +@@ -0,0 +1,388 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * readdir in userspace. ++ */ ++ ++#include ++#include ++#include ++#include "aufs.h" ++ ++/* bits for struct aufs_rdu.flags */ ++#define AuRdu_CALLED 1 ++#define AuRdu_CONT (1 << 1) ++#define AuRdu_FULL (1 << 2) ++#define au_ftest_rdu(flags, name) ((flags) & AuRdu_##name) ++#define au_fset_rdu(flags, name) \ ++ do { (flags) |= AuRdu_##name; } while (0) ++#define au_fclr_rdu(flags, name) \ ++ do { (flags) &= ~AuRdu_##name; } while (0) ++ ++struct au_rdu_arg { ++ struct dir_context ctx; ++ struct aufs_rdu *rdu; ++ union au_rdu_ent_ul ent; ++ unsigned long end; ++ ++ struct super_block *sb; ++ int err; ++}; ++ ++static int au_rdu_fill(struct dir_context *ctx, const char *name, int nlen, ++ loff_t offset, u64 h_ino, unsigned int d_type) ++{ ++ int err, len; ++ struct au_rdu_arg *arg = container_of(ctx, struct au_rdu_arg, ctx); ++ struct aufs_rdu *rdu = arg->rdu; ++ struct au_rdu_ent ent; ++ ++ err = 0; ++ arg->err = 0; ++ au_fset_rdu(rdu->cookie.flags, CALLED); ++ len = au_rdu_len(nlen); ++ if (arg->ent.ul + len < arg->end) { ++ ent.ino = h_ino; ++ ent.bindex = rdu->cookie.bindex; ++ ent.type = d_type; ++ ent.nlen = nlen; ++ if (unlikely(nlen > AUFS_MAX_NAMELEN)) ++ ent.type = DT_UNKNOWN; ++ ++ /* unnecessary to support mmap_sem since this is a dir */ ++ err = -EFAULT; ++ if (copy_to_user(arg->ent.e, &ent, sizeof(ent))) ++ goto out; ++ if (copy_to_user(arg->ent.e->name, name, nlen)) ++ goto out; ++ /* the terminating NULL */ ++ if (__put_user(0, arg->ent.e->name + nlen)) ++ goto out; ++ err = 0; ++ /* AuDbg("%p, %.*s\n", arg->ent.p, nlen, name); */ ++ arg->ent.ul += len; ++ rdu->rent++; ++ } else { ++ err = -EFAULT; ++ au_fset_rdu(rdu->cookie.flags, FULL); ++ rdu->full = 1; ++ rdu->tail = arg->ent; ++ } ++ ++out: ++ /* AuTraceErr(err); */ ++ return err; ++} ++ ++static int au_rdu_do(struct file *h_file, struct au_rdu_arg *arg) ++{ ++ int err; ++ loff_t offset; ++ struct au_rdu_cookie *cookie = &arg->rdu->cookie; ++ ++ /* we don't have to care (FMODE_32BITHASH | FMODE_64BITHASH) for ext4 */ ++ offset = vfsub_llseek(h_file, cookie->h_pos, SEEK_SET); ++ err = offset; ++ if (unlikely(offset != cookie->h_pos)) ++ goto out; ++ ++ err = 0; ++ do { ++ arg->err = 0; ++ au_fclr_rdu(cookie->flags, CALLED); ++ /* smp_mb(); */ ++ err = vfsub_iterate_dir(h_file, &arg->ctx); ++ if (err >= 0) ++ err = arg->err; ++ } while (!err ++ && au_ftest_rdu(cookie->flags, CALLED) ++ && !au_ftest_rdu(cookie->flags, FULL)); ++ cookie->h_pos = h_file->f_pos; ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_rdu(struct file *file, struct aufs_rdu *rdu) ++{ ++ int err; ++ aufs_bindex_t bend; ++ struct au_rdu_arg arg = { ++ .ctx = { ++ .actor = au_diractor(au_rdu_fill) ++ } ++ }; ++ struct dentry *dentry; ++ struct inode *inode; ++ struct file *h_file; ++ struct au_rdu_cookie *cookie = &rdu->cookie; ++ ++ err = !access_ok(VERIFY_WRITE, rdu->ent.e, rdu->sz); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ goto out; ++ } ++ rdu->rent = 0; ++ rdu->tail = rdu->ent; ++ rdu->full = 0; ++ arg.rdu = rdu; ++ arg.ent = rdu->ent; ++ arg.end = arg.ent.ul; ++ arg.end += rdu->sz; ++ ++ err = -ENOTDIR; ++ if (unlikely(!file->f_op->iterate)) ++ goto out; ++ ++ err = security_file_permission(file, MAY_READ); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ goto out; ++ ++ dentry = file->f_dentry; ++ inode = dentry->d_inode; ++#if 1 ++ mutex_lock(&inode->i_mutex); ++#else ++ err = mutex_lock_killable(&inode->i_mutex); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ goto out; ++#endif ++ ++ arg.sb = inode->i_sb; ++ err = si_read_lock(arg.sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (unlikely(err)) ++ goto out_mtx; ++ err = au_alive_dir(dentry); ++ if (unlikely(err)) ++ goto out_si; ++ /* todo: reval? */ ++ fi_read_lock(file); ++ ++ err = -EAGAIN; ++ if (unlikely(au_ftest_rdu(cookie->flags, CONT) ++ && cookie->generation != au_figen(file))) ++ goto out_unlock; ++ ++ err = 0; ++ if (!rdu->blk) { ++ rdu->blk = au_sbi(arg.sb)->si_rdblk; ++ if (!rdu->blk) ++ rdu->blk = au_dir_size(file, /*dentry*/NULL); ++ } ++ bend = au_fbstart(file); ++ if (cookie->bindex < bend) ++ cookie->bindex = bend; ++ bend = au_fbend_dir(file); ++ /* AuDbg("b%d, b%d\n", cookie->bindex, bend); */ ++ for (; !err && cookie->bindex <= bend; ++ cookie->bindex++, cookie->h_pos = 0) { ++ h_file = au_hf_dir(file, cookie->bindex); ++ if (!h_file) ++ continue; ++ ++ au_fclr_rdu(cookie->flags, FULL); ++ err = au_rdu_do(h_file, &arg); ++ AuTraceErr(err); ++ if (unlikely(au_ftest_rdu(cookie->flags, FULL) || err)) ++ break; ++ } ++ AuDbg("rent %llu\n", rdu->rent); ++ ++ if (!err && !au_ftest_rdu(cookie->flags, CONT)) { ++ rdu->shwh = !!au_opt_test(au_sbi(arg.sb)->si_mntflags, SHWH); ++ au_fset_rdu(cookie->flags, CONT); ++ cookie->generation = au_figen(file); ++ } ++ ++ ii_read_lock_child(inode); ++ fsstack_copy_attr_atime(inode, au_h_iptr(inode, au_ibstart(inode))); ++ ii_read_unlock(inode); ++ ++out_unlock: ++ fi_read_unlock(file); ++out_si: ++ si_read_unlock(arg.sb); ++out_mtx: ++ mutex_unlock(&inode->i_mutex); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_rdu_ino(struct file *file, struct aufs_rdu *rdu) ++{ ++ int err; ++ ino_t ino; ++ unsigned long long nent; ++ union au_rdu_ent_ul *u; ++ struct au_rdu_ent ent; ++ struct super_block *sb; ++ ++ err = 0; ++ nent = rdu->nent; ++ u = &rdu->ent; ++ sb = file->f_dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ while (nent-- > 0) { ++ /* unnecessary to support mmap_sem since this is a dir */ ++ err = copy_from_user(&ent, u->e, sizeof(ent)); ++ if (!err) ++ err = !access_ok(VERIFY_WRITE, &u->e->ino, sizeof(ino)); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ break; ++ } ++ ++ /* AuDbg("b%d, i%llu\n", ent.bindex, ent.ino); */ ++ if (!ent.wh) ++ err = au_ino(sb, ent.bindex, ent.ino, ent.type, &ino); ++ else ++ err = au_wh_ino(sb, ent.bindex, ent.ino, ent.type, ++ &ino); ++ if (unlikely(err)) { ++ AuTraceErr(err); ++ break; ++ } ++ ++ err = __put_user(ino, &u->e->ino); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ break; ++ } ++ u->ul += au_rdu_len(ent.nlen); ++ } ++ si_read_unlock(sb); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_rdu_verify(struct aufs_rdu *rdu) ++{ ++ AuDbg("rdu{%llu, %p, %u | %u | %llu, %u, %u | " ++ "%llu, b%d, 0x%x, g%u}\n", ++ rdu->sz, rdu->ent.e, rdu->verify[AufsCtlRduV_SZ], ++ rdu->blk, ++ rdu->rent, rdu->shwh, rdu->full, ++ rdu->cookie.h_pos, rdu->cookie.bindex, rdu->cookie.flags, ++ rdu->cookie.generation); ++ ++ if (rdu->verify[AufsCtlRduV_SZ] == sizeof(*rdu)) ++ return 0; ++ ++ AuDbg("%u:%u\n", ++ rdu->verify[AufsCtlRduV_SZ], (unsigned int)sizeof(*rdu)); ++ return -EINVAL; ++} ++ ++long au_rdu_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ long err, e; ++ struct aufs_rdu rdu; ++ void __user *p = (void __user *)arg; ++ ++ err = copy_from_user(&rdu, p, sizeof(rdu)); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ goto out; ++ } ++ err = au_rdu_verify(&rdu); ++ if (unlikely(err)) ++ goto out; ++ ++ switch (cmd) { ++ case AUFS_CTL_RDU: ++ err = au_rdu(file, &rdu); ++ if (unlikely(err)) ++ break; ++ ++ e = copy_to_user(p, &rdu, sizeof(rdu)); ++ if (unlikely(e)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ } ++ break; ++ case AUFS_CTL_RDU_INO: ++ err = au_rdu_ino(file, &rdu); ++ break; ++ ++ default: ++ /* err = -ENOTTY; */ ++ err = -EINVAL; ++ } ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++#ifdef CONFIG_COMPAT ++long au_rdu_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ long err, e; ++ struct aufs_rdu rdu; ++ void __user *p = compat_ptr(arg); ++ ++ /* todo: get_user()? */ ++ err = copy_from_user(&rdu, p, sizeof(rdu)); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ goto out; ++ } ++ rdu.ent.e = compat_ptr(rdu.ent.ul); ++ err = au_rdu_verify(&rdu); ++ if (unlikely(err)) ++ goto out; ++ ++ switch (cmd) { ++ case AUFS_CTL_RDU: ++ err = au_rdu(file, &rdu); ++ if (unlikely(err)) ++ break; ++ ++ rdu.ent.ul = ptr_to_compat(rdu.ent.e); ++ rdu.tail.ul = ptr_to_compat(rdu.tail.e); ++ e = copy_to_user(p, &rdu, sizeof(rdu)); ++ if (unlikely(e)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ } ++ break; ++ case AUFS_CTL_RDU_INO: ++ err = au_rdu_ino(file, &rdu); ++ break; ++ ++ default: ++ /* err = -ENOTTY; */ ++ err = -EINVAL; ++ } ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++#endif +diff --git a/fs/aufs/rwsem.h b/fs/aufs/rwsem.h +new file mode 100644 +index 0000000..09ed5a0 +--- /dev/null ++++ b/fs/aufs/rwsem.h +@@ -0,0 +1,191 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * simple read-write semaphore wrappers ++ */ ++ ++#ifndef __AUFS_RWSEM_H__ ++#define __AUFS_RWSEM_H__ ++ ++#ifdef __KERNEL__ ++ ++#include "debug.h" ++ ++struct au_rwsem { ++ struct rw_semaphore rwsem; ++#ifdef CONFIG_AUFS_DEBUG ++ /* just for debugging, not almighty counter */ ++ atomic_t rcnt, wcnt; ++#endif ++}; ++ ++#ifdef CONFIG_AUFS_DEBUG ++#define AuDbgCntInit(rw) do { \ ++ atomic_set(&(rw)->rcnt, 0); \ ++ atomic_set(&(rw)->wcnt, 0); \ ++ smp_mb(); /* atomic set */ \ ++} while (0) ++ ++#define AuDbgRcntInc(rw) atomic_inc(&(rw)->rcnt) ++#define AuDbgRcntDec(rw) WARN_ON(atomic_dec_return(&(rw)->rcnt) < 0) ++#define AuDbgWcntInc(rw) atomic_inc(&(rw)->wcnt) ++#define AuDbgWcntDec(rw) WARN_ON(atomic_dec_return(&(rw)->wcnt) < 0) ++#else ++#define AuDbgCntInit(rw) do {} while (0) ++#define AuDbgRcntInc(rw) do {} while (0) ++#define AuDbgRcntDec(rw) do {} while (0) ++#define AuDbgWcntInc(rw) do {} while (0) ++#define AuDbgWcntDec(rw) do {} while (0) ++#endif /* CONFIG_AUFS_DEBUG */ ++ ++/* to debug easier, do not make them inlined functions */ ++#define AuRwMustNoWaiters(rw) AuDebugOn(!list_empty(&(rw)->rwsem.wait_list)) ++/* rwsem_is_locked() is unusable */ ++#define AuRwMustReadLock(rw) AuDebugOn(atomic_read(&(rw)->rcnt) <= 0) ++#define AuRwMustWriteLock(rw) AuDebugOn(atomic_read(&(rw)->wcnt) <= 0) ++#define AuRwMustAnyLock(rw) AuDebugOn(atomic_read(&(rw)->rcnt) <= 0 \ ++ && atomic_read(&(rw)->wcnt) <= 0) ++#define AuRwDestroy(rw) AuDebugOn(atomic_read(&(rw)->rcnt) \ ++ || atomic_read(&(rw)->wcnt)) ++ ++#define au_rw_class(rw, key) lockdep_set_class(&(rw)->rwsem, key) ++ ++static inline void au_rw_init(struct au_rwsem *rw) ++{ ++ AuDbgCntInit(rw); ++ init_rwsem(&rw->rwsem); ++} ++ ++static inline void au_rw_init_wlock(struct au_rwsem *rw) ++{ ++ au_rw_init(rw); ++ down_write(&rw->rwsem); ++ AuDbgWcntInc(rw); ++} ++ ++static inline void au_rw_init_wlock_nested(struct au_rwsem *rw, ++ unsigned int lsc) ++{ ++ au_rw_init(rw); ++ down_write_nested(&rw->rwsem, lsc); ++ AuDbgWcntInc(rw); ++} ++ ++static inline void au_rw_read_lock(struct au_rwsem *rw) ++{ ++ down_read(&rw->rwsem); ++ AuDbgRcntInc(rw); ++} ++ ++static inline void au_rw_read_lock_nested(struct au_rwsem *rw, unsigned int lsc) ++{ ++ down_read_nested(&rw->rwsem, lsc); ++ AuDbgRcntInc(rw); ++} ++ ++static inline void au_rw_read_unlock(struct au_rwsem *rw) ++{ ++ AuRwMustReadLock(rw); ++ AuDbgRcntDec(rw); ++ up_read(&rw->rwsem); ++} ++ ++static inline void au_rw_dgrade_lock(struct au_rwsem *rw) ++{ ++ AuRwMustWriteLock(rw); ++ AuDbgRcntInc(rw); ++ AuDbgWcntDec(rw); ++ downgrade_write(&rw->rwsem); ++} ++ ++static inline void au_rw_write_lock(struct au_rwsem *rw) ++{ ++ down_write(&rw->rwsem); ++ AuDbgWcntInc(rw); ++} ++ ++static inline void au_rw_write_lock_nested(struct au_rwsem *rw, ++ unsigned int lsc) ++{ ++ down_write_nested(&rw->rwsem, lsc); ++ AuDbgWcntInc(rw); ++} ++ ++static inline void au_rw_write_unlock(struct au_rwsem *rw) ++{ ++ AuRwMustWriteLock(rw); ++ AuDbgWcntDec(rw); ++ up_write(&rw->rwsem); ++} ++ ++/* why is not _nested version defined */ ++static inline int au_rw_read_trylock(struct au_rwsem *rw) ++{ ++ int ret; ++ ++ ret = down_read_trylock(&rw->rwsem); ++ if (ret) ++ AuDbgRcntInc(rw); ++ return ret; ++} ++ ++static inline int au_rw_write_trylock(struct au_rwsem *rw) ++{ ++ int ret; ++ ++ ret = down_write_trylock(&rw->rwsem); ++ if (ret) ++ AuDbgWcntInc(rw); ++ return ret; ++} ++ ++#undef AuDbgCntInit ++#undef AuDbgRcntInc ++#undef AuDbgRcntDec ++#undef AuDbgWcntInc ++#undef AuDbgWcntDec ++ ++#define AuSimpleLockRwsemFuncs(prefix, param, rwsem) \ ++static inline void prefix##_read_lock(param) \ ++{ au_rw_read_lock(rwsem); } \ ++static inline void prefix##_write_lock(param) \ ++{ au_rw_write_lock(rwsem); } \ ++static inline int prefix##_read_trylock(param) \ ++{ return au_rw_read_trylock(rwsem); } \ ++static inline int prefix##_write_trylock(param) \ ++{ return au_rw_write_trylock(rwsem); } ++/* why is not _nested version defined */ ++/* static inline void prefix##_read_trylock_nested(param, lsc) ++{ au_rw_read_trylock_nested(rwsem, lsc)); } ++static inline void prefix##_write_trylock_nestd(param, lsc) ++{ au_rw_write_trylock_nested(rwsem, lsc); } */ ++ ++#define AuSimpleUnlockRwsemFuncs(prefix, param, rwsem) \ ++static inline void prefix##_read_unlock(param) \ ++{ au_rw_read_unlock(rwsem); } \ ++static inline void prefix##_write_unlock(param) \ ++{ au_rw_write_unlock(rwsem); } \ ++static inline void prefix##_downgrade_lock(param) \ ++{ au_rw_dgrade_lock(rwsem); } ++ ++#define AuSimpleRwsemFuncs(prefix, param, rwsem) \ ++ AuSimpleLockRwsemFuncs(prefix, param, rwsem) \ ++ AuSimpleUnlockRwsemFuncs(prefix, param, rwsem) ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_RWSEM_H__ */ +diff --git a/fs/aufs/sbinfo.c b/fs/aufs/sbinfo.c +new file mode 100644 +index 0000000..ff13c9f +--- /dev/null ++++ b/fs/aufs/sbinfo.c +@@ -0,0 +1,348 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * superblock private data ++ */ ++ ++#include "aufs.h" ++ ++/* ++ * they are necessary regardless sysfs is disabled. ++ */ ++void au_si_free(struct kobject *kobj) ++{ ++ int i; ++ struct au_sbinfo *sbinfo; ++ char *locked __maybe_unused; /* debug only */ ++ ++ sbinfo = container_of(kobj, struct au_sbinfo, si_kobj); ++ for (i = 0; i < AuPlink_NHASH; i++) ++ AuDebugOn(!hlist_empty(&sbinfo->si_plink[i].head)); ++ AuDebugOn(atomic_read(&sbinfo->si_nowait.nw_len)); ++ ++ au_rw_write_lock(&sbinfo->si_rwsem); ++ au_br_free(sbinfo); ++ au_rw_write_unlock(&sbinfo->si_rwsem); ++ ++ kfree(sbinfo->si_branch); ++ for (i = 0; i < AU_NPIDMAP; i++) ++ kfree(sbinfo->au_si_pid.pid_bitmap[i]); ++ mutex_destroy(&sbinfo->au_si_pid.pid_mtx); ++ mutex_destroy(&sbinfo->si_xib_mtx); ++ AuRwDestroy(&sbinfo->si_rwsem); ++ ++ kfree(sbinfo); ++} ++ ++int au_si_alloc(struct super_block *sb) ++{ ++ int err, i; ++ struct au_sbinfo *sbinfo; ++ static struct lock_class_key aufs_si; ++ ++ err = -ENOMEM; ++ sbinfo = kzalloc(sizeof(*sbinfo), GFP_NOFS); ++ if (unlikely(!sbinfo)) ++ goto out; ++ ++ /* will be reallocated separately */ ++ sbinfo->si_branch = kzalloc(sizeof(*sbinfo->si_branch), GFP_NOFS); ++ if (unlikely(!sbinfo->si_branch)) ++ goto out_sbinfo; ++ ++ err = sysaufs_si_init(sbinfo); ++ if (unlikely(err)) ++ goto out_br; ++ ++ au_nwt_init(&sbinfo->si_nowait); ++ au_rw_init_wlock(&sbinfo->si_rwsem); ++ au_rw_class(&sbinfo->si_rwsem, &aufs_si); ++ mutex_init(&sbinfo->au_si_pid.pid_mtx); ++ ++ atomic_long_set(&sbinfo->si_ninodes, 0); ++ atomic_long_set(&sbinfo->si_nfiles, 0); ++ ++ sbinfo->si_bend = -1; ++ sbinfo->si_last_br_id = AUFS_BRANCH_MAX / 2; ++ ++ sbinfo->si_wbr_copyup = AuWbrCopyup_Def; ++ sbinfo->si_wbr_create = AuWbrCreate_Def; ++ sbinfo->si_wbr_copyup_ops = au_wbr_copyup_ops + sbinfo->si_wbr_copyup; ++ sbinfo->si_wbr_create_ops = au_wbr_create_ops + sbinfo->si_wbr_create; ++ ++ au_fhsm_init(sbinfo); ++ ++ sbinfo->si_mntflags = au_opts_plink(AuOpt_Def); ++ ++ sbinfo->si_xino_jiffy = jiffies; ++ sbinfo->si_xino_expire ++ = msecs_to_jiffies(AUFS_XINO_DEF_SEC * MSEC_PER_SEC); ++ mutex_init(&sbinfo->si_xib_mtx); ++ sbinfo->si_xino_brid = -1; ++ /* leave si_xib_last_pindex and si_xib_next_bit */ ++ ++ au_sphl_init(&sbinfo->si_aopen); ++ ++ sbinfo->si_rdcache = msecs_to_jiffies(AUFS_RDCACHE_DEF * MSEC_PER_SEC); ++ sbinfo->si_rdblk = AUFS_RDBLK_DEF; ++ sbinfo->si_rdhash = AUFS_RDHASH_DEF; ++ sbinfo->si_dirwh = AUFS_DIRWH_DEF; ++ ++ for (i = 0; i < AuPlink_NHASH; i++) ++ au_sphl_init(sbinfo->si_plink + i); ++ init_waitqueue_head(&sbinfo->si_plink_wq); ++ spin_lock_init(&sbinfo->si_plink_maint_lock); ++ ++ au_sphl_init(&sbinfo->si_files); ++ ++ /* with getattr by default */ ++ sbinfo->si_iop_array = aufs_iop; ++ ++ /* leave other members for sysaufs and si_mnt. */ ++ sbinfo->si_sb = sb; ++ sb->s_fs_info = sbinfo; ++ si_pid_set(sb); ++ return 0; /* success */ ++ ++out_br: ++ kfree(sbinfo->si_branch); ++out_sbinfo: ++ kfree(sbinfo); ++out: ++ return err; ++} ++ ++int au_sbr_realloc(struct au_sbinfo *sbinfo, int nbr) ++{ ++ int err, sz; ++ struct au_branch **brp; ++ ++ AuRwMustWriteLock(&sbinfo->si_rwsem); ++ ++ err = -ENOMEM; ++ sz = sizeof(*brp) * (sbinfo->si_bend + 1); ++ if (unlikely(!sz)) ++ sz = sizeof(*brp); ++ brp = au_kzrealloc(sbinfo->si_branch, sz, sizeof(*brp) * nbr, GFP_NOFS); ++ if (brp) { ++ sbinfo->si_branch = brp; ++ err = 0; ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++unsigned int au_sigen_inc(struct super_block *sb) ++{ ++ unsigned int gen; ++ ++ SiMustWriteLock(sb); ++ ++ gen = ++au_sbi(sb)->si_generation; ++ au_update_digen(sb->s_root); ++ au_update_iigen(sb->s_root->d_inode, /*half*/0); ++ sb->s_root->d_inode->i_version++; ++ return gen; ++} ++ ++aufs_bindex_t au_new_br_id(struct super_block *sb) ++{ ++ aufs_bindex_t br_id; ++ int i; ++ struct au_sbinfo *sbinfo; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ for (i = 0; i <= AUFS_BRANCH_MAX; i++) { ++ br_id = ++sbinfo->si_last_br_id; ++ AuDebugOn(br_id < 0); ++ if (br_id && au_br_index(sb, br_id) < 0) ++ return br_id; ++ } ++ ++ return -1; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* it is ok that new 'nwt' tasks are appended while we are sleeping */ ++int si_read_lock(struct super_block *sb, int flags) ++{ ++ int err; ++ ++ err = 0; ++ if (au_ftest_lock(flags, FLUSH)) ++ au_nwt_flush(&au_sbi(sb)->si_nowait); ++ ++ si_noflush_read_lock(sb); ++ err = au_plink_maint(sb, flags); ++ if (unlikely(err)) ++ si_read_unlock(sb); ++ ++ return err; ++} ++ ++int si_write_lock(struct super_block *sb, int flags) ++{ ++ int err; ++ ++ if (au_ftest_lock(flags, FLUSH)) ++ au_nwt_flush(&au_sbi(sb)->si_nowait); ++ ++ si_noflush_write_lock(sb); ++ err = au_plink_maint(sb, flags); ++ if (unlikely(err)) ++ si_write_unlock(sb); ++ ++ return err; ++} ++ ++/* dentry and super_block lock. call at entry point */ ++int aufs_read_lock(struct dentry *dentry, int flags) ++{ ++ int err; ++ struct super_block *sb; ++ ++ sb = dentry->d_sb; ++ err = si_read_lock(sb, flags); ++ if (unlikely(err)) ++ goto out; ++ ++ if (au_ftest_lock(flags, DW)) ++ di_write_lock_child(dentry); ++ else ++ di_read_lock_child(dentry, flags); ++ ++ if (au_ftest_lock(flags, GEN)) { ++ err = au_digen_test(dentry, au_sigen(sb)); ++ if (!au_opt_test(au_mntflags(sb), UDBA_NONE)) ++ AuDebugOn(!err && au_dbrange_test(dentry)); ++ else if (!err) ++ err = au_dbrange_test(dentry); ++ if (unlikely(err)) ++ aufs_read_unlock(dentry, flags); ++ } ++ ++out: ++ return err; ++} ++ ++void aufs_read_unlock(struct dentry *dentry, int flags) ++{ ++ if (au_ftest_lock(flags, DW)) ++ di_write_unlock(dentry); ++ else ++ di_read_unlock(dentry, flags); ++ si_read_unlock(dentry->d_sb); ++} ++ ++void aufs_write_lock(struct dentry *dentry) ++{ ++ si_write_lock(dentry->d_sb, AuLock_FLUSH | AuLock_NOPLMW); ++ di_write_lock_child(dentry); ++} ++ ++void aufs_write_unlock(struct dentry *dentry) ++{ ++ di_write_unlock(dentry); ++ si_write_unlock(dentry->d_sb); ++} ++ ++int aufs_read_and_write_lock2(struct dentry *d1, struct dentry *d2, int flags) ++{ ++ int err; ++ unsigned int sigen; ++ struct super_block *sb; ++ ++ sb = d1->d_sb; ++ err = si_read_lock(sb, flags); ++ if (unlikely(err)) ++ goto out; ++ ++ di_write_lock2_child(d1, d2, au_ftest_lock(flags, DIRS)); ++ ++ if (au_ftest_lock(flags, GEN)) { ++ sigen = au_sigen(sb); ++ err = au_digen_test(d1, sigen); ++ AuDebugOn(!err && au_dbrange_test(d1)); ++ if (!err) { ++ err = au_digen_test(d2, sigen); ++ AuDebugOn(!err && au_dbrange_test(d2)); ++ } ++ if (unlikely(err)) ++ aufs_read_and_write_unlock2(d1, d2); ++ } ++ ++out: ++ return err; ++} ++ ++void aufs_read_and_write_unlock2(struct dentry *d1, struct dentry *d2) ++{ ++ di_write_unlock2(d1, d2); ++ si_read_unlock(d1->d_sb); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void si_pid_alloc(struct au_si_pid *au_si_pid, int idx) ++{ ++ unsigned long *p; ++ ++ BUILD_BUG_ON(sizeof(unsigned long) != ++ sizeof(*au_si_pid->pid_bitmap)); ++ ++ mutex_lock(&au_si_pid->pid_mtx); ++ p = au_si_pid->pid_bitmap[idx]; ++ while (!p) { ++ /* ++ * bad approach. ++ * but keeping 'si_pid_set()' void is more important. ++ */ ++ p = kcalloc(BITS_TO_LONGS(AU_PIDSTEP), ++ sizeof(*au_si_pid->pid_bitmap), ++ GFP_NOFS); ++ if (p) ++ break; ++ cond_resched(); ++ } ++ au_si_pid->pid_bitmap[idx] = p; ++ mutex_unlock(&au_si_pid->pid_mtx); ++} ++ ++void si_pid_set(struct super_block *sb) ++{ ++ pid_t bit; ++ int idx; ++ unsigned long *bitmap; ++ struct au_si_pid *au_si_pid; ++ ++ si_pid_idx_bit(&idx, &bit); ++ au_si_pid = &au_sbi(sb)->au_si_pid; ++ bitmap = au_si_pid->pid_bitmap[idx]; ++ if (!bitmap) { ++ si_pid_alloc(au_si_pid, idx); ++ bitmap = au_si_pid->pid_bitmap[idx]; ++ } ++ AuDebugOn(test_bit(bit, bitmap)); ++ set_bit(bit, bitmap); ++ /* smp_mb(); */ ++} +diff --git a/fs/aufs/spl.h b/fs/aufs/spl.h +new file mode 100644 +index 0000000..945343a +--- /dev/null ++++ b/fs/aufs/spl.h +@@ -0,0 +1,111 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * simple list protected by a spinlock ++ */ ++ ++#ifndef __AUFS_SPL_H__ ++#define __AUFS_SPL_H__ ++ ++#ifdef __KERNEL__ ++ ++struct au_splhead { ++ spinlock_t spin; ++ struct list_head head; ++}; ++ ++static inline void au_spl_init(struct au_splhead *spl) ++{ ++ spin_lock_init(&spl->spin); ++ INIT_LIST_HEAD(&spl->head); ++} ++ ++static inline void au_spl_add(struct list_head *list, struct au_splhead *spl) ++{ ++ spin_lock(&spl->spin); ++ list_add(list, &spl->head); ++ spin_unlock(&spl->spin); ++} ++ ++static inline void au_spl_del(struct list_head *list, struct au_splhead *spl) ++{ ++ spin_lock(&spl->spin); ++ list_del(list); ++ spin_unlock(&spl->spin); ++} ++ ++static inline void au_spl_del_rcu(struct list_head *list, ++ struct au_splhead *spl) ++{ ++ spin_lock(&spl->spin); ++ list_del_rcu(list); ++ spin_unlock(&spl->spin); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_sphlhead { ++ spinlock_t spin; ++ struct hlist_head head; ++}; ++ ++static inline void au_sphl_init(struct au_sphlhead *sphl) ++{ ++ spin_lock_init(&sphl->spin); ++ INIT_HLIST_HEAD(&sphl->head); ++} ++ ++static inline void au_sphl_add(struct hlist_node *hlist, ++ struct au_sphlhead *sphl) ++{ ++ spin_lock(&sphl->spin); ++ hlist_add_head(hlist, &sphl->head); ++ spin_unlock(&sphl->spin); ++} ++ ++static inline void au_sphl_del(struct hlist_node *hlist, ++ struct au_sphlhead *sphl) ++{ ++ spin_lock(&sphl->spin); ++ hlist_del(hlist); ++ spin_unlock(&sphl->spin); ++} ++ ++static inline void au_sphl_del_rcu(struct hlist_node *hlist, ++ struct au_sphlhead *sphl) ++{ ++ spin_lock(&sphl->spin); ++ hlist_del_rcu(hlist); ++ spin_unlock(&sphl->spin); ++} ++ ++static inline unsigned long au_sphl_count(struct au_sphlhead *sphl) ++{ ++ unsigned long cnt; ++ struct hlist_node *pos; ++ ++ cnt = 0; ++ spin_lock(&sphl->spin); ++ hlist_for_each(pos, &sphl->head) ++ cnt++; ++ spin_unlock(&sphl->spin); ++ return cnt; ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_SPL_H__ */ +diff --git a/fs/aufs/super.c b/fs/aufs/super.c +new file mode 100644 +index 0000000..64a6bb4 +--- /dev/null ++++ b/fs/aufs/super.c +@@ -0,0 +1,1041 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * mount and super_block operations ++ */ ++ ++#include ++#include ++#include ++#include ++#include "aufs.h" ++ ++/* ++ * super_operations ++ */ ++static struct inode *aufs_alloc_inode(struct super_block *sb __maybe_unused) ++{ ++ struct au_icntnr *c; ++ ++ c = au_cache_alloc_icntnr(); ++ if (c) { ++ au_icntnr_init(c); ++ c->vfs_inode.i_version = 1; /* sigen(sb); */ ++ c->iinfo.ii_hinode = NULL; ++ return &c->vfs_inode; ++ } ++ return NULL; ++} ++ ++static void aufs_destroy_inode_cb(struct rcu_head *head) ++{ ++ struct inode *inode = container_of(head, struct inode, i_rcu); ++ ++ INIT_HLIST_HEAD(&inode->i_dentry); ++ au_cache_free_icntnr(container_of(inode, struct au_icntnr, vfs_inode)); ++} ++ ++static void aufs_destroy_inode(struct inode *inode) ++{ ++ au_iinfo_fin(inode); ++ call_rcu(&inode->i_rcu, aufs_destroy_inode_cb); ++} ++ ++struct inode *au_iget_locked(struct super_block *sb, ino_t ino) ++{ ++ struct inode *inode; ++ int err; ++ ++ inode = iget_locked(sb, ino); ++ if (unlikely(!inode)) { ++ inode = ERR_PTR(-ENOMEM); ++ goto out; ++ } ++ if (!(inode->i_state & I_NEW)) ++ goto out; ++ ++ err = au_xigen_new(inode); ++ if (!err) ++ err = au_iinfo_init(inode); ++ if (!err) ++ inode->i_version++; ++ else { ++ iget_failed(inode); ++ inode = ERR_PTR(err); ++ } ++ ++out: ++ /* never return NULL */ ++ AuDebugOn(!inode); ++ AuTraceErrPtr(inode); ++ return inode; ++} ++ ++/* lock free root dinfo */ ++static int au_show_brs(struct seq_file *seq, struct super_block *sb) ++{ ++ int err; ++ aufs_bindex_t bindex, bend; ++ struct path path; ++ struct au_hdentry *hdp; ++ struct au_branch *br; ++ au_br_perm_str_t perm; ++ ++ err = 0; ++ bend = au_sbend(sb); ++ hdp = au_di(sb->s_root)->di_hdentry; ++ for (bindex = 0; !err && bindex <= bend; bindex++) { ++ br = au_sbr(sb, bindex); ++ path.mnt = au_br_mnt(br); ++ path.dentry = hdp[bindex].hd_dentry; ++ err = au_seq_path(seq, &path); ++ if (!err) { ++ au_optstr_br_perm(&perm, br->br_perm); ++ err = seq_printf(seq, "=%s", perm.a); ++ if (err == -1) ++ err = -E2BIG; ++ } ++ if (!err && bindex != bend) ++ err = seq_putc(seq, ':'); ++ } ++ ++ return err; ++} ++ ++static void au_show_wbr_create(struct seq_file *m, int v, ++ struct au_sbinfo *sbinfo) ++{ ++ const char *pat; ++ ++ AuRwMustAnyLock(&sbinfo->si_rwsem); ++ ++ seq_puts(m, ",create="); ++ pat = au_optstr_wbr_create(v); ++ switch (v) { ++ case AuWbrCreate_TDP: ++ case AuWbrCreate_RR: ++ case AuWbrCreate_MFS: ++ case AuWbrCreate_PMFS: ++ seq_puts(m, pat); ++ break; ++ case AuWbrCreate_MFSV: ++ seq_printf(m, /*pat*/"mfs:%lu", ++ jiffies_to_msecs(sbinfo->si_wbr_mfs.mfs_expire) ++ / MSEC_PER_SEC); ++ break; ++ case AuWbrCreate_PMFSV: ++ seq_printf(m, /*pat*/"pmfs:%lu", ++ jiffies_to_msecs(sbinfo->si_wbr_mfs.mfs_expire) ++ / MSEC_PER_SEC); ++ break; ++ case AuWbrCreate_MFSRR: ++ seq_printf(m, /*pat*/"mfsrr:%llu", ++ sbinfo->si_wbr_mfs.mfsrr_watermark); ++ break; ++ case AuWbrCreate_MFSRRV: ++ seq_printf(m, /*pat*/"mfsrr:%llu:%lu", ++ sbinfo->si_wbr_mfs.mfsrr_watermark, ++ jiffies_to_msecs(sbinfo->si_wbr_mfs.mfs_expire) ++ / MSEC_PER_SEC); ++ break; ++ case AuWbrCreate_PMFSRR: ++ seq_printf(m, /*pat*/"pmfsrr:%llu", ++ sbinfo->si_wbr_mfs.mfsrr_watermark); ++ break; ++ case AuWbrCreate_PMFSRRV: ++ seq_printf(m, /*pat*/"pmfsrr:%llu:%lu", ++ sbinfo->si_wbr_mfs.mfsrr_watermark, ++ jiffies_to_msecs(sbinfo->si_wbr_mfs.mfs_expire) ++ / MSEC_PER_SEC); ++ break; ++ } ++} ++ ++static int au_show_xino(struct seq_file *seq, struct super_block *sb) ++{ ++#ifdef CONFIG_SYSFS ++ return 0; ++#else ++ int err; ++ const int len = sizeof(AUFS_XINO_FNAME) - 1; ++ aufs_bindex_t bindex, brid; ++ struct qstr *name; ++ struct file *f; ++ struct dentry *d, *h_root; ++ struct au_hdentry *hdp; ++ ++ AuRwMustAnyLock(&sbinfo->si_rwsem); ++ ++ err = 0; ++ f = au_sbi(sb)->si_xib; ++ if (!f) ++ goto out; ++ ++ /* stop printing the default xino path on the first writable branch */ ++ h_root = NULL; ++ brid = au_xino_brid(sb); ++ if (brid >= 0) { ++ bindex = au_br_index(sb, brid); ++ hdp = au_di(sb->s_root)->di_hdentry; ++ h_root = hdp[0 + bindex].hd_dentry; ++ } ++ d = f->f_dentry; ++ name = &d->d_name; ++ /* safe ->d_parent because the file is unlinked */ ++ if (d->d_parent == h_root ++ && name->len == len ++ && !memcmp(name->name, AUFS_XINO_FNAME, len)) ++ goto out; ++ ++ seq_puts(seq, ",xino="); ++ err = au_xino_path(seq, f); ++ ++out: ++ return err; ++#endif ++} ++ ++/* seq_file will re-call me in case of too long string */ ++static int aufs_show_options(struct seq_file *m, struct dentry *dentry) ++{ ++ int err; ++ unsigned int mnt_flags, v; ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ ++#define AuBool(name, str) do { \ ++ v = au_opt_test(mnt_flags, name); \ ++ if (v != au_opt_test(AuOpt_Def, name)) \ ++ seq_printf(m, ",%s" #str, v ? "" : "no"); \ ++} while (0) ++ ++#define AuStr(name, str) do { \ ++ v = mnt_flags & AuOptMask_##name; \ ++ if (v != (AuOpt_Def & AuOptMask_##name)) \ ++ seq_printf(m, "," #str "=%s", au_optstr_##str(v)); \ ++} while (0) ++ ++#define AuUInt(name, str, val) do { \ ++ if (val != AUFS_##name##_DEF) \ ++ seq_printf(m, "," #str "=%u", val); \ ++} while (0) ++ ++ sb = dentry->d_sb; ++ if (sb->s_flags & MS_POSIXACL) ++ seq_puts(m, ",acl"); ++ ++ /* lock free root dinfo */ ++ si_noflush_read_lock(sb); ++ sbinfo = au_sbi(sb); ++ seq_printf(m, ",si=%lx", sysaufs_si_id(sbinfo)); ++ ++ mnt_flags = au_mntflags(sb); ++ if (au_opt_test(mnt_flags, XINO)) { ++ err = au_show_xino(m, sb); ++ if (unlikely(err)) ++ goto out; ++ } else ++ seq_puts(m, ",noxino"); ++ ++ AuBool(TRUNC_XINO, trunc_xino); ++ AuStr(UDBA, udba); ++ AuBool(SHWH, shwh); ++ AuBool(PLINK, plink); ++ AuBool(DIO, dio); ++ AuBool(DIRPERM1, dirperm1); ++ /* AuBool(REFROF, refrof); */ ++ ++ v = sbinfo->si_wbr_create; ++ if (v != AuWbrCreate_Def) ++ au_show_wbr_create(m, v, sbinfo); ++ ++ v = sbinfo->si_wbr_copyup; ++ if (v != AuWbrCopyup_Def) ++ seq_printf(m, ",cpup=%s", au_optstr_wbr_copyup(v)); ++ ++ v = au_opt_test(mnt_flags, ALWAYS_DIROPQ); ++ if (v != au_opt_test(AuOpt_Def, ALWAYS_DIROPQ)) ++ seq_printf(m, ",diropq=%c", v ? 'a' : 'w'); ++ ++ AuUInt(DIRWH, dirwh, sbinfo->si_dirwh); ++ ++ v = jiffies_to_msecs(sbinfo->si_rdcache) / MSEC_PER_SEC; ++ AuUInt(RDCACHE, rdcache, v); ++ ++ AuUInt(RDBLK, rdblk, sbinfo->si_rdblk); ++ AuUInt(RDHASH, rdhash, sbinfo->si_rdhash); ++ ++ au_fhsm_show(m, sbinfo); ++ ++ AuBool(SUM, sum); ++ /* AuBool(SUM_W, wsum); */ ++ AuBool(WARN_PERM, warn_perm); ++ AuBool(VERBOSE, verbose); ++ ++out: ++ /* be sure to print "br:" last */ ++ if (!sysaufs_brs) { ++ seq_puts(m, ",br:"); ++ au_show_brs(m, sb); ++ } ++ si_read_unlock(sb); ++ return 0; ++ ++#undef AuBool ++#undef AuStr ++#undef AuUInt ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* sum mode which returns the summation for statfs(2) */ ++ ++static u64 au_add_till_max(u64 a, u64 b) ++{ ++ u64 old; ++ ++ old = a; ++ a += b; ++ if (old <= a) ++ return a; ++ return ULLONG_MAX; ++} ++ ++static u64 au_mul_till_max(u64 a, long mul) ++{ ++ u64 old; ++ ++ old = a; ++ a *= mul; ++ if (old <= a) ++ return a; ++ return ULLONG_MAX; ++} ++ ++static int au_statfs_sum(struct super_block *sb, struct kstatfs *buf) ++{ ++ int err; ++ long bsize, factor; ++ u64 blocks, bfree, bavail, files, ffree; ++ aufs_bindex_t bend, bindex, i; ++ unsigned char shared; ++ struct path h_path; ++ struct super_block *h_sb; ++ ++ err = 0; ++ bsize = LONG_MAX; ++ files = 0; ++ ffree = 0; ++ blocks = 0; ++ bfree = 0; ++ bavail = 0; ++ bend = au_sbend(sb); ++ for (bindex = 0; bindex <= bend; bindex++) { ++ h_path.mnt = au_sbr_mnt(sb, bindex); ++ h_sb = h_path.mnt->mnt_sb; ++ shared = 0; ++ for (i = 0; !shared && i < bindex; i++) ++ shared = (au_sbr_sb(sb, i) == h_sb); ++ if (shared) ++ continue; ++ ++ /* sb->s_root for NFS is unreliable */ ++ h_path.dentry = h_path.mnt->mnt_root; ++ err = vfs_statfs(&h_path, buf); ++ if (unlikely(err)) ++ goto out; ++ ++ if (bsize > buf->f_bsize) { ++ /* ++ * we will reduce bsize, so we have to expand blocks ++ * etc. to match them again ++ */ ++ factor = (bsize / buf->f_bsize); ++ blocks = au_mul_till_max(blocks, factor); ++ bfree = au_mul_till_max(bfree, factor); ++ bavail = au_mul_till_max(bavail, factor); ++ bsize = buf->f_bsize; ++ } ++ ++ factor = (buf->f_bsize / bsize); ++ blocks = au_add_till_max(blocks, ++ au_mul_till_max(buf->f_blocks, factor)); ++ bfree = au_add_till_max(bfree, ++ au_mul_till_max(buf->f_bfree, factor)); ++ bavail = au_add_till_max(bavail, ++ au_mul_till_max(buf->f_bavail, factor)); ++ files = au_add_till_max(files, buf->f_files); ++ ffree = au_add_till_max(ffree, buf->f_ffree); ++ } ++ ++ buf->f_bsize = bsize; ++ buf->f_blocks = blocks; ++ buf->f_bfree = bfree; ++ buf->f_bavail = bavail; ++ buf->f_files = files; ++ buf->f_ffree = ffree; ++ buf->f_frsize = 0; ++ ++out: ++ return err; ++} ++ ++static int aufs_statfs(struct dentry *dentry, struct kstatfs *buf) ++{ ++ int err; ++ struct path h_path; ++ struct super_block *sb; ++ ++ /* lock free root dinfo */ ++ sb = dentry->d_sb; ++ si_noflush_read_lock(sb); ++ if (!au_opt_test(au_mntflags(sb), SUM)) { ++ /* sb->s_root for NFS is unreliable */ ++ h_path.mnt = au_sbr_mnt(sb, 0); ++ h_path.dentry = h_path.mnt->mnt_root; ++ err = vfs_statfs(&h_path, buf); ++ } else ++ err = au_statfs_sum(sb, buf); ++ si_read_unlock(sb); ++ ++ if (!err) { ++ buf->f_type = AUFS_SUPER_MAGIC; ++ buf->f_namelen = AUFS_MAX_NAMELEN; ++ memset(&buf->f_fsid, 0, sizeof(buf->f_fsid)); ++ } ++ /* buf->f_bsize = buf->f_blocks = buf->f_bfree = buf->f_bavail = -1; */ ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int aufs_sync_fs(struct super_block *sb, int wait) ++{ ++ int err, e; ++ aufs_bindex_t bend, bindex; ++ struct au_branch *br; ++ struct super_block *h_sb; ++ ++ err = 0; ++ si_noflush_read_lock(sb); ++ bend = au_sbend(sb); ++ for (bindex = 0; bindex <= bend; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (!au_br_writable(br->br_perm)) ++ continue; ++ ++ h_sb = au_sbr_sb(sb, bindex); ++ if (h_sb->s_op->sync_fs) { ++ e = h_sb->s_op->sync_fs(h_sb, wait); ++ if (unlikely(e && !err)) ++ err = e; ++ /* go on even if an error happens */ ++ } ++ } ++ si_read_unlock(sb); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* final actions when unmounting a file system */ ++static void aufs_put_super(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ ++ sbinfo = au_sbi(sb); ++ if (!sbinfo) ++ return; ++ ++ dbgaufs_si_fin(sbinfo); ++ kobject_put(&sbinfo->si_kobj); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void *au_array_alloc(unsigned long long *hint, au_arraycb_t cb, void *arg) ++{ ++ void *array; ++ unsigned long long n, sz; ++ ++ array = NULL; ++ n = 0; ++ if (!*hint) ++ goto out; ++ ++ if (*hint > ULLONG_MAX / sizeof(array)) { ++ array = ERR_PTR(-EMFILE); ++ pr_err("hint %llu\n", *hint); ++ goto out; ++ } ++ ++ sz = sizeof(array) * *hint; ++ array = kzalloc(sz, GFP_NOFS); ++ if (unlikely(!array)) ++ array = vzalloc(sz); ++ if (unlikely(!array)) { ++ array = ERR_PTR(-ENOMEM); ++ goto out; ++ } ++ ++ n = cb(array, *hint, arg); ++ AuDebugOn(n > *hint); ++ ++out: ++ *hint = n; ++ return array; ++} ++ ++static unsigned long long au_iarray_cb(void *a, ++ unsigned long long max __maybe_unused, ++ void *arg) ++{ ++ unsigned long long n; ++ struct inode **p, *inode; ++ struct list_head *head; ++ ++ n = 0; ++ p = a; ++ head = arg; ++ spin_lock(&inode_sb_list_lock); ++ list_for_each_entry(inode, head, i_sb_list) { ++ if (!is_bad_inode(inode) ++ && au_ii(inode)->ii_bstart >= 0) { ++ spin_lock(&inode->i_lock); ++ if (atomic_read(&inode->i_count)) { ++ au_igrab(inode); ++ *p++ = inode; ++ n++; ++ AuDebugOn(n > max); ++ } ++ spin_unlock(&inode->i_lock); ++ } ++ } ++ spin_unlock(&inode_sb_list_lock); ++ ++ return n; ++} ++ ++struct inode **au_iarray_alloc(struct super_block *sb, unsigned long long *max) ++{ ++ *max = atomic_long_read(&au_sbi(sb)->si_ninodes); ++ return au_array_alloc(max, au_iarray_cb, &sb->s_inodes); ++} ++ ++void au_iarray_free(struct inode **a, unsigned long long max) ++{ ++ unsigned long long ull; ++ ++ for (ull = 0; ull < max; ull++) ++ iput(a[ull]); ++ kvfree(a); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * refresh dentry and inode at remount time. ++ */ ++/* todo: consolidate with simple_reval_dpath() and au_reval_for_attr() */ ++static int au_do_refresh(struct dentry *dentry, unsigned int dir_flags, ++ struct dentry *parent) ++{ ++ int err; ++ ++ di_write_lock_child(dentry); ++ di_read_lock_parent(parent, AuLock_IR); ++ err = au_refresh_dentry(dentry, parent); ++ if (!err && dir_flags) ++ au_hn_reset(dentry->d_inode, dir_flags); ++ di_read_unlock(parent, AuLock_IR); ++ di_write_unlock(dentry); ++ ++ return err; ++} ++ ++static int au_do_refresh_d(struct dentry *dentry, unsigned int sigen, ++ struct au_sbinfo *sbinfo, ++ const unsigned int dir_flags, unsigned int do_idop) ++{ ++ int err; ++ struct dentry *parent; ++ struct inode *inode; ++ ++ err = 0; ++ parent = dget_parent(dentry); ++ if (!au_digen_test(parent, sigen) && au_digen_test(dentry, sigen)) { ++ inode = dentry->d_inode; ++ if (inode) { ++ if (!S_ISDIR(inode->i_mode)) ++ err = au_do_refresh(dentry, /*dir_flags*/0, ++ parent); ++ else { ++ err = au_do_refresh(dentry, dir_flags, parent); ++ if (unlikely(err)) ++ au_fset_si(sbinfo, FAILED_REFRESH_DIR); ++ } ++ } else ++ err = au_do_refresh(dentry, /*dir_flags*/0, parent); ++ AuDbgDentry(dentry); ++ } ++ dput(parent); ++ ++ if (!err) { ++ if (do_idop) ++ au_refresh_dop(dentry, /*force_reval*/0); ++ } else ++ au_refresh_dop(dentry, /*force_reval*/1); ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_refresh_d(struct super_block *sb, unsigned int do_idop) ++{ ++ int err, i, j, ndentry, e; ++ unsigned int sigen; ++ struct au_dcsub_pages dpages; ++ struct au_dpage *dpage; ++ struct dentry **dentries, *d; ++ struct au_sbinfo *sbinfo; ++ struct dentry *root = sb->s_root; ++ const unsigned int dir_flags = au_hi_flags(root->d_inode, /*isdir*/1); ++ ++ if (do_idop) ++ au_refresh_dop(root, /*force_reval*/0); ++ ++ err = au_dpages_init(&dpages, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ err = au_dcsub_pages(&dpages, root, NULL, NULL); ++ if (unlikely(err)) ++ goto out_dpages; ++ ++ sigen = au_sigen(sb); ++ sbinfo = au_sbi(sb); ++ for (i = 0; i < dpages.ndpage; i++) { ++ dpage = dpages.dpages + i; ++ dentries = dpage->dentries; ++ ndentry = dpage->ndentry; ++ for (j = 0; j < ndentry; j++) { ++ d = dentries[j]; ++ e = au_do_refresh_d(d, sigen, sbinfo, dir_flags, ++ do_idop); ++ if (unlikely(e && !err)) ++ err = e; ++ /* go on even err */ ++ } ++ } ++ ++out_dpages: ++ au_dpages_free(&dpages); ++out: ++ return err; ++} ++ ++static int au_refresh_i(struct super_block *sb, unsigned int do_idop) ++{ ++ int err, e; ++ unsigned int sigen; ++ unsigned long long max, ull; ++ struct inode *inode, **array; ++ ++ array = au_iarray_alloc(sb, &max); ++ err = PTR_ERR(array); ++ if (IS_ERR(array)) ++ goto out; ++ ++ err = 0; ++ sigen = au_sigen(sb); ++ for (ull = 0; ull < max; ull++) { ++ inode = array[ull]; ++ if (unlikely(!inode)) ++ break; ++ ++ e = 0; ++ ii_write_lock_child(inode); ++ if (au_iigen(inode, NULL) != sigen) { ++ e = au_refresh_hinode_self(inode); ++ if (unlikely(e)) { ++ au_refresh_iop(inode, /*force_getattr*/1); ++ pr_err("error %d, i%lu\n", e, inode->i_ino); ++ if (!err) ++ err = e; ++ /* go on even if err */ ++ } ++ } ++ if (!e && do_idop) ++ au_refresh_iop(inode, /*force_getattr*/0); ++ ii_write_unlock(inode); ++ } ++ ++ au_iarray_free(array, max); ++ ++out: ++ return err; ++} ++ ++static void au_remount_refresh(struct super_block *sb, unsigned int do_idop) ++{ ++ int err, e; ++ unsigned int udba; ++ aufs_bindex_t bindex, bend; ++ struct dentry *root; ++ struct inode *inode; ++ struct au_branch *br; ++ struct au_sbinfo *sbi; ++ ++ au_sigen_inc(sb); ++ sbi = au_sbi(sb); ++ au_fclr_si(sbi, FAILED_REFRESH_DIR); ++ ++ root = sb->s_root; ++ DiMustNoWaiters(root); ++ inode = root->d_inode; ++ IiMustNoWaiters(inode); ++ ++ udba = au_opt_udba(sb); ++ bend = au_sbend(sb); ++ for (bindex = 0; bindex <= bend; bindex++) { ++ br = au_sbr(sb, bindex); ++ err = au_hnotify_reset_br(udba, br, br->br_perm); ++ if (unlikely(err)) ++ AuIOErr("hnotify failed on br %d, %d, ignored\n", ++ bindex, err); ++ /* go on even if err */ ++ } ++ au_hn_reset(inode, au_hi_flags(inode, /*isdir*/1)); ++ ++ if (do_idop) { ++ if (au_ftest_si(sbi, NO_DREVAL)) { ++ AuDebugOn(sb->s_d_op == &aufs_dop_noreval); ++ sb->s_d_op = &aufs_dop_noreval; ++ AuDebugOn(sbi->si_iop_array == aufs_iop_nogetattr); ++ sbi->si_iop_array = aufs_iop_nogetattr; ++ } else { ++ AuDebugOn(sb->s_d_op == &aufs_dop); ++ sb->s_d_op = &aufs_dop; ++ AuDebugOn(sbi->si_iop_array == aufs_iop); ++ sbi->si_iop_array = aufs_iop; ++ } ++ pr_info("reset to %pf and %pf\n", ++ sb->s_d_op, sbi->si_iop_array); ++ } ++ ++ di_write_unlock(root); ++ err = au_refresh_d(sb, do_idop); ++ e = au_refresh_i(sb, do_idop); ++ if (unlikely(e && !err)) ++ err = e; ++ /* aufs_write_lock() calls ..._child() */ ++ di_write_lock_child(root); ++ ++ au_cpup_attr_all(inode, /*force*/1); ++ ++ if (unlikely(err)) ++ AuIOErr("refresh failed, ignored, %d\n", err); ++} ++ ++/* stop extra interpretation of errno in mount(8), and strange error messages */ ++static int cvt_err(int err) ++{ ++ AuTraceErr(err); ++ ++ switch (err) { ++ case -ENOENT: ++ case -ENOTDIR: ++ case -EEXIST: ++ case -EIO: ++ err = -EINVAL; ++ } ++ return err; ++} ++ ++static int aufs_remount_fs(struct super_block *sb, int *flags, char *data) ++{ ++ int err, do_dx; ++ unsigned int mntflags; ++ struct au_opts opts = { ++ .opt = NULL ++ }; ++ struct dentry *root; ++ struct inode *inode; ++ struct au_sbinfo *sbinfo; ++ ++ err = 0; ++ root = sb->s_root; ++ if (!data || !*data) { ++ err = si_write_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (!err) { ++ di_write_lock_child(root); ++ err = au_opts_verify(sb, *flags, /*pending*/0); ++ aufs_write_unlock(root); ++ } ++ goto out; ++ } ++ ++ err = -ENOMEM; ++ opts.opt = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!opts.opt)) ++ goto out; ++ opts.max_opt = PAGE_SIZE / sizeof(*opts.opt); ++ opts.flags = AuOpts_REMOUNT; ++ opts.sb_flags = *flags; ++ ++ /* parse it before aufs lock */ ++ err = au_opts_parse(sb, data, &opts); ++ if (unlikely(err)) ++ goto out_opts; ++ ++ sbinfo = au_sbi(sb); ++ inode = root->d_inode; ++ mutex_lock(&inode->i_mutex); ++ err = si_write_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (unlikely(err)) ++ goto out_mtx; ++ di_write_lock_child(root); ++ ++ /* au_opts_remount() may return an error */ ++ err = au_opts_remount(sb, &opts); ++ au_opts_free(&opts); ++ ++ if (au_ftest_opts(opts.flags, REFRESH)) ++ au_remount_refresh(sb, au_ftest_opts(opts.flags, REFRESH_IDOP)); ++ ++ if (au_ftest_opts(opts.flags, REFRESH_DYAOP)) { ++ mntflags = au_mntflags(sb); ++ do_dx = !!au_opt_test(mntflags, DIO); ++ au_dy_arefresh(do_dx); ++ } ++ ++ au_fhsm_wrote_all(sb, /*force*/1); /* ?? */ ++ aufs_write_unlock(root); ++ ++out_mtx: ++ mutex_unlock(&inode->i_mutex); ++out_opts: ++ free_page((unsigned long)opts.opt); ++out: ++ err = cvt_err(err); ++ AuTraceErr(err); ++ return err; ++} ++ ++static const struct super_operations aufs_sop = { ++ .alloc_inode = aufs_alloc_inode, ++ .destroy_inode = aufs_destroy_inode, ++ /* always deleting, no clearing */ ++ .drop_inode = generic_delete_inode, ++ .show_options = aufs_show_options, ++ .statfs = aufs_statfs, ++ .put_super = aufs_put_super, ++ .sync_fs = aufs_sync_fs, ++ .remount_fs = aufs_remount_fs ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int alloc_root(struct super_block *sb) ++{ ++ int err; ++ struct inode *inode; ++ struct dentry *root; ++ ++ err = -ENOMEM; ++ inode = au_iget_locked(sb, AUFS_ROOT_INO); ++ err = PTR_ERR(inode); ++ if (IS_ERR(inode)) ++ goto out; ++ ++ inode->i_op = aufs_iop + AuIop_DIR; /* with getattr by default */ ++ inode->i_fop = &aufs_dir_fop; ++ inode->i_mode = S_IFDIR; ++ set_nlink(inode, 2); ++ unlock_new_inode(inode); ++ ++ root = d_make_root(inode); ++ if (unlikely(!root)) ++ goto out; ++ err = PTR_ERR(root); ++ if (IS_ERR(root)) ++ goto out; ++ ++ err = au_di_init(root); ++ if (!err) { ++ sb->s_root = root; ++ return 0; /* success */ ++ } ++ dput(root); ++ ++out: ++ return err; ++} ++ ++static int aufs_fill_super(struct super_block *sb, void *raw_data, ++ int silent __maybe_unused) ++{ ++ int err; ++ struct au_opts opts = { ++ .opt = NULL ++ }; ++ struct au_sbinfo *sbinfo; ++ struct dentry *root; ++ struct inode *inode; ++ char *arg = raw_data; ++ ++ if (unlikely(!arg || !*arg)) { ++ err = -EINVAL; ++ pr_err("no arg\n"); ++ goto out; ++ } ++ ++ err = -ENOMEM; ++ opts.opt = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!opts.opt)) ++ goto out; ++ opts.max_opt = PAGE_SIZE / sizeof(*opts.opt); ++ opts.sb_flags = sb->s_flags; ++ ++ err = au_si_alloc(sb); ++ if (unlikely(err)) ++ goto out_opts; ++ sbinfo = au_sbi(sb); ++ ++ /* all timestamps always follow the ones on the branch */ ++ sb->s_flags |= MS_NOATIME | MS_NODIRATIME; ++ sb->s_op = &aufs_sop; ++ sb->s_d_op = &aufs_dop; ++ sb->s_magic = AUFS_SUPER_MAGIC; ++ sb->s_maxbytes = 0; ++ sb->s_stack_depth = 1; ++ au_export_init(sb); ++ /* au_xattr_init(sb); */ ++ ++ err = alloc_root(sb); ++ if (unlikely(err)) { ++ si_write_unlock(sb); ++ goto out_info; ++ } ++ root = sb->s_root; ++ inode = root->d_inode; ++ ++ /* ++ * actually we can parse options regardless aufs lock here. ++ * but at remount time, parsing must be done before aufs lock. ++ * so we follow the same rule. ++ */ ++ ii_write_lock_parent(inode); ++ aufs_write_unlock(root); ++ err = au_opts_parse(sb, arg, &opts); ++ if (unlikely(err)) ++ goto out_root; ++ ++ /* lock vfs_inode first, then aufs. */ ++ mutex_lock(&inode->i_mutex); ++ aufs_write_lock(root); ++ err = au_opts_mount(sb, &opts); ++ au_opts_free(&opts); ++ if (!err && au_ftest_si(sbinfo, NO_DREVAL)) { ++ sb->s_d_op = &aufs_dop_noreval; ++ pr_info("%pf\n", sb->s_d_op); ++ au_refresh_dop(root, /*force_reval*/0); ++ sbinfo->si_iop_array = aufs_iop_nogetattr; ++ au_refresh_iop(inode, /*force_getattr*/0); ++ } ++ aufs_write_unlock(root); ++ mutex_unlock(&inode->i_mutex); ++ if (!err) ++ goto out_opts; /* success */ ++ ++out_root: ++ dput(root); ++ sb->s_root = NULL; ++out_info: ++ dbgaufs_si_fin(sbinfo); ++ kobject_put(&sbinfo->si_kobj); ++ sb->s_fs_info = NULL; ++out_opts: ++ free_page((unsigned long)opts.opt); ++out: ++ AuTraceErr(err); ++ err = cvt_err(err); ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct dentry *aufs_mount(struct file_system_type *fs_type, int flags, ++ const char *dev_name __maybe_unused, ++ void *raw_data) ++{ ++ struct dentry *root; ++ struct super_block *sb; ++ ++ /* all timestamps always follow the ones on the branch */ ++ /* mnt->mnt_flags |= MNT_NOATIME | MNT_NODIRATIME; */ ++ root = mount_nodev(fs_type, flags, raw_data, aufs_fill_super); ++ if (IS_ERR(root)) ++ goto out; ++ ++ sb = root->d_sb; ++ si_write_lock(sb, !AuLock_FLUSH); ++ sysaufs_brs_add(sb, 0); ++ si_write_unlock(sb); ++ au_sbilist_add(sb); ++ ++out: ++ return root; ++} ++ ++static void aufs_kill_sb(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ ++ sbinfo = au_sbi(sb); ++ if (sbinfo) { ++ au_sbilist_del(sb); ++ aufs_write_lock(sb->s_root); ++ au_fhsm_fin(sb); ++ if (sbinfo->si_wbr_create_ops->fin) ++ sbinfo->si_wbr_create_ops->fin(sb); ++ if (au_opt_test(sbinfo->si_mntflags, UDBA_HNOTIFY)) { ++ au_opt_set_udba(sbinfo->si_mntflags, UDBA_NONE); ++ au_remount_refresh(sb, /*do_idop*/0); ++ } ++ if (au_opt_test(sbinfo->si_mntflags, PLINK)) ++ au_plink_put(sb, /*verbose*/1); ++ au_xino_clr(sb); ++ sbinfo->si_sb = NULL; ++ aufs_write_unlock(sb->s_root); ++ au_nwt_flush(&sbinfo->si_nowait); ++ } ++ kill_anon_super(sb); ++} ++ ++struct file_system_type aufs_fs_type = { ++ .name = AUFS_FSTYPE, ++ /* a race between rename and others */ ++ .fs_flags = FS_RENAME_DOES_D_MOVE, ++ .mount = aufs_mount, ++ .kill_sb = aufs_kill_sb, ++ /* no need to __module_get() and module_put(). */ ++ .owner = THIS_MODULE, ++}; +diff --git a/fs/aufs/super.h b/fs/aufs/super.h +new file mode 100644 +index 0000000..ecd364b +--- /dev/null ++++ b/fs/aufs/super.h +@@ -0,0 +1,626 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * super_block operations ++ */ ++ ++#ifndef __AUFS_SUPER_H__ ++#define __AUFS_SUPER_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include "rwsem.h" ++#include "spl.h" ++#include "wkq.h" ++ ++typedef ssize_t (*au_readf_t)(struct file *, char __user *, size_t, loff_t *); ++typedef ssize_t (*au_writef_t)(struct file *, const char __user *, size_t, ++ loff_t *); ++ ++/* policies to select one among multiple writable branches */ ++struct au_wbr_copyup_operations { ++ int (*copyup)(struct dentry *dentry); ++}; ++ ++#define AuWbr_DIR 1 /* target is a dir */ ++#define AuWbr_PARENT (1 << 1) /* always require a parent */ ++ ++#define au_ftest_wbr(flags, name) ((flags) & AuWbr_##name) ++#define au_fset_wbr(flags, name) { (flags) |= AuWbr_##name; } ++#define au_fclr_wbr(flags, name) { (flags) &= ~AuWbr_##name; } ++ ++struct au_wbr_create_operations { ++ int (*create)(struct dentry *dentry, unsigned int flags); ++ int (*init)(struct super_block *sb); ++ int (*fin)(struct super_block *sb); ++}; ++ ++struct au_wbr_mfs { ++ struct mutex mfs_lock; /* protect this structure */ ++ unsigned long mfs_jiffy; ++ unsigned long mfs_expire; ++ aufs_bindex_t mfs_bindex; ++ ++ unsigned long long mfsrr_bytes; ++ unsigned long long mfsrr_watermark; ++}; ++ ++#define AuPlink_NHASH 100 ++static inline int au_plink_hash(ino_t ino) ++{ ++ return ino % AuPlink_NHASH; ++} ++ ++/* File-based Hierarchical Storage Management */ ++struct au_fhsm { ++#ifdef CONFIG_AUFS_FHSM ++ /* allow only one process who can receive the notification */ ++ spinlock_t fhsm_spin; ++ pid_t fhsm_pid; ++ wait_queue_head_t fhsm_wqh; ++ atomic_t fhsm_readable; ++ ++ /* these are protected by si_rwsem */ ++ unsigned long fhsm_expire; ++ aufs_bindex_t fhsm_bottom; ++#endif ++}; ++ ++#define AU_PIDSTEP (int)(BITS_TO_LONGS(PID_MAX_DEFAULT) * BITS_PER_LONG) ++#define AU_NPIDMAP (int)DIV_ROUND_UP(PID_MAX_LIMIT, AU_PIDSTEP) ++struct au_si_pid { ++ unsigned long *pid_bitmap[AU_NPIDMAP]; ++ struct mutex pid_mtx; ++}; ++ ++struct au_branch; ++struct au_sbinfo { ++ /* nowait tasks in the system-wide workqueue */ ++ struct au_nowait_tasks si_nowait; ++ ++ /* ++ * tried sb->s_umount, but failed due to the dependecy between i_mutex. ++ * rwsem for au_sbinfo is necessary. ++ */ ++ struct au_rwsem si_rwsem; ++ ++ /* prevent recursive locking in deleting inode */ ++ struct au_si_pid au_si_pid; ++ ++ /* ++ * dirty approach to protect sb->sb_inodes and ->s_files (gone) from ++ * remount. ++ */ ++ atomic_long_t si_ninodes, si_nfiles; ++ ++ /* branch management */ ++ unsigned int si_generation; ++ ++ /* see AuSi_ flags */ ++ unsigned char au_si_status; ++ ++ aufs_bindex_t si_bend; ++ ++ /* dirty trick to keep br_id plus */ ++ unsigned int si_last_br_id : ++ sizeof(aufs_bindex_t) * BITS_PER_BYTE - 1; ++ struct au_branch **si_branch; ++ ++ /* policy to select a writable branch */ ++ unsigned char si_wbr_copyup; ++ unsigned char si_wbr_create; ++ struct au_wbr_copyup_operations *si_wbr_copyup_ops; ++ struct au_wbr_create_operations *si_wbr_create_ops; ++ ++ /* round robin */ ++ atomic_t si_wbr_rr_next; ++ ++ /* most free space */ ++ struct au_wbr_mfs si_wbr_mfs; ++ ++ /* File-based Hierarchical Storage Management */ ++ struct au_fhsm si_fhsm; ++ ++ /* mount flags */ ++ /* include/asm-ia64/siginfo.h defines a macro named si_flags */ ++ unsigned int si_mntflags; ++ ++ /* external inode number (bitmap and translation table) */ ++ au_readf_t si_xread; ++ au_writef_t si_xwrite; ++ struct file *si_xib; ++ struct mutex si_xib_mtx; /* protect xib members */ ++ unsigned long *si_xib_buf; ++ unsigned long si_xib_last_pindex; ++ int si_xib_next_bit; ++ aufs_bindex_t si_xino_brid; ++ unsigned long si_xino_jiffy; ++ unsigned long si_xino_expire; ++ /* reserved for future use */ ++ /* unsigned long long si_xib_limit; */ /* Max xib file size */ ++ ++#ifdef CONFIG_AUFS_EXPORT ++ /* i_generation */ ++ struct file *si_xigen; ++ atomic_t si_xigen_next; ++#endif ++ ++ /* dirty trick to suppoer atomic_open */ ++ struct au_sphlhead si_aopen; ++ ++ /* vdir parameters */ ++ unsigned long si_rdcache; /* max cache time in jiffies */ ++ unsigned int si_rdblk; /* deblk size */ ++ unsigned int si_rdhash; /* hash size */ ++ ++ /* ++ * If the number of whiteouts are larger than si_dirwh, leave all of ++ * them after au_whtmp_ren to reduce the cost of rmdir(2). ++ * future fsck.aufs or kernel thread will remove them later. ++ * Otherwise, remove all whiteouts and the dir in rmdir(2). ++ */ ++ unsigned int si_dirwh; ++ ++ /* pseudo_link list */ ++ struct au_sphlhead si_plink[AuPlink_NHASH]; ++ wait_queue_head_t si_plink_wq; ++ spinlock_t si_plink_maint_lock; ++ pid_t si_plink_maint_pid; ++ ++ /* file list */ ++ struct au_sphlhead si_files; ++ ++ /* with/without getattr, brother of sb->s_d_op */ ++ struct inode_operations *si_iop_array; ++ ++ /* ++ * sysfs and lifetime management. ++ * this is not a small structure and it may be a waste of memory in case ++ * of sysfs is disabled, particulary when many aufs-es are mounted. ++ * but using sysfs is majority. ++ */ ++ struct kobject si_kobj; ++#ifdef CONFIG_DEBUG_FS ++ struct dentry *si_dbgaufs; ++ struct dentry *si_dbgaufs_plink; ++ struct dentry *si_dbgaufs_xib; ++#ifdef CONFIG_AUFS_EXPORT ++ struct dentry *si_dbgaufs_xigen; ++#endif ++#endif ++ ++#ifdef CONFIG_AUFS_SBILIST ++ struct hlist_node si_list; ++#endif ++ ++ /* dirty, necessary for unmounting, sysfs and sysrq */ ++ struct super_block *si_sb; ++}; ++ ++/* sbinfo status flags */ ++/* ++ * set true when refresh_dirs() failed at remount time. ++ * then try refreshing dirs at access time again. ++ * if it is false, refreshing dirs at access time is unnecesary ++ */ ++#define AuSi_FAILED_REFRESH_DIR 1 ++#define AuSi_FHSM (1 << 1) /* fhsm is active now */ ++#define AuSi_NO_DREVAL (1 << 2) /* disable all d_revalidate */ ++ ++#ifndef CONFIG_AUFS_FHSM ++#undef AuSi_FHSM ++#define AuSi_FHSM 0 ++#endif ++ ++static inline unsigned char au_do_ftest_si(struct au_sbinfo *sbi, ++ unsigned int flag) ++{ ++ AuRwMustAnyLock(&sbi->si_rwsem); ++ return sbi->au_si_status & flag; ++} ++#define au_ftest_si(sbinfo, name) au_do_ftest_si(sbinfo, AuSi_##name) ++#define au_fset_si(sbinfo, name) do { \ ++ AuRwMustWriteLock(&(sbinfo)->si_rwsem); \ ++ (sbinfo)->au_si_status |= AuSi_##name; \ ++} while (0) ++#define au_fclr_si(sbinfo, name) do { \ ++ AuRwMustWriteLock(&(sbinfo)->si_rwsem); \ ++ (sbinfo)->au_si_status &= ~AuSi_##name; \ ++} while (0) ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* policy to select one among writable branches */ ++#define AuWbrCopyup(sbinfo, ...) \ ++ ((sbinfo)->si_wbr_copyup_ops->copyup(__VA_ARGS__)) ++#define AuWbrCreate(sbinfo, ...) \ ++ ((sbinfo)->si_wbr_create_ops->create(__VA_ARGS__)) ++ ++/* flags for si_read_lock()/aufs_read_lock()/di_read_lock() */ ++#define AuLock_DW 1 /* write-lock dentry */ ++#define AuLock_IR (1 << 1) /* read-lock inode */ ++#define AuLock_IW (1 << 2) /* write-lock inode */ ++#define AuLock_FLUSH (1 << 3) /* wait for 'nowait' tasks */ ++#define AuLock_DIRS (1 << 4) /* target is a pair of dirs */ ++#define AuLock_NOPLM (1 << 5) /* return err in plm mode */ ++#define AuLock_NOPLMW (1 << 6) /* wait for plm mode ends */ ++#define AuLock_GEN (1 << 7) /* test digen/iigen */ ++#define au_ftest_lock(flags, name) ((flags) & AuLock_##name) ++#define au_fset_lock(flags, name) \ ++ do { (flags) |= AuLock_##name; } while (0) ++#define au_fclr_lock(flags, name) \ ++ do { (flags) &= ~AuLock_##name; } while (0) ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* super.c */ ++extern struct file_system_type aufs_fs_type; ++struct inode *au_iget_locked(struct super_block *sb, ino_t ino); ++typedef unsigned long long (*au_arraycb_t)(void *array, unsigned long long max, ++ void *arg); ++void *au_array_alloc(unsigned long long *hint, au_arraycb_t cb, void *arg); ++struct inode **au_iarray_alloc(struct super_block *sb, unsigned long long *max); ++void au_iarray_free(struct inode **a, unsigned long long max); ++ ++/* sbinfo.c */ ++void au_si_free(struct kobject *kobj); ++int au_si_alloc(struct super_block *sb); ++int au_sbr_realloc(struct au_sbinfo *sbinfo, int nbr); ++ ++unsigned int au_sigen_inc(struct super_block *sb); ++aufs_bindex_t au_new_br_id(struct super_block *sb); ++ ++int si_read_lock(struct super_block *sb, int flags); ++int si_write_lock(struct super_block *sb, int flags); ++int aufs_read_lock(struct dentry *dentry, int flags); ++void aufs_read_unlock(struct dentry *dentry, int flags); ++void aufs_write_lock(struct dentry *dentry); ++void aufs_write_unlock(struct dentry *dentry); ++int aufs_read_and_write_lock2(struct dentry *d1, struct dentry *d2, int flags); ++void aufs_read_and_write_unlock2(struct dentry *d1, struct dentry *d2); ++ ++/* wbr_policy.c */ ++extern struct au_wbr_copyup_operations au_wbr_copyup_ops[]; ++extern struct au_wbr_create_operations au_wbr_create_ops[]; ++int au_cpdown_dirs(struct dentry *dentry, aufs_bindex_t bdst); ++int au_wbr_nonopq(struct dentry *dentry, aufs_bindex_t bindex); ++int au_wbr_do_copyup_bu(struct dentry *dentry, aufs_bindex_t bstart); ++ ++/* mvdown.c */ ++int au_mvdown(struct dentry *dentry, struct aufs_mvdown __user *arg); ++ ++#ifdef CONFIG_AUFS_FHSM ++/* fhsm.c */ ++ ++static inline pid_t au_fhsm_pid(struct au_fhsm *fhsm) ++{ ++ pid_t pid; ++ ++ spin_lock(&fhsm->fhsm_spin); ++ pid = fhsm->fhsm_pid; ++ spin_unlock(&fhsm->fhsm_spin); ++ ++ return pid; ++} ++ ++void au_fhsm_wrote(struct super_block *sb, aufs_bindex_t bindex, int force); ++void au_fhsm_wrote_all(struct super_block *sb, int force); ++int au_fhsm_fd(struct super_block *sb, int oflags); ++int au_fhsm_br_alloc(struct au_branch *br); ++void au_fhsm_set_bottom(struct super_block *sb, aufs_bindex_t bindex); ++void au_fhsm_fin(struct super_block *sb); ++void au_fhsm_init(struct au_sbinfo *sbinfo); ++void au_fhsm_set(struct au_sbinfo *sbinfo, unsigned int sec); ++void au_fhsm_show(struct seq_file *seq, struct au_sbinfo *sbinfo); ++#else ++AuStubVoid(au_fhsm_wrote, struct super_block *sb, aufs_bindex_t bindex, ++ int force) ++AuStubVoid(au_fhsm_wrote_all, struct super_block *sb, int force) ++AuStub(int, au_fhsm_fd, return -EOPNOTSUPP, struct super_block *sb, int oflags) ++AuStub(pid_t, au_fhsm_pid, return 0, struct au_fhsm *fhsm) ++AuStubInt0(au_fhsm_br_alloc, struct au_branch *br) ++AuStubVoid(au_fhsm_set_bottom, struct super_block *sb, aufs_bindex_t bindex) ++AuStubVoid(au_fhsm_fin, struct super_block *sb) ++AuStubVoid(au_fhsm_init, struct au_sbinfo *sbinfo) ++AuStubVoid(au_fhsm_set, struct au_sbinfo *sbinfo, unsigned int sec) ++AuStubVoid(au_fhsm_show, struct seq_file *seq, struct au_sbinfo *sbinfo) ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct au_sbinfo *au_sbi(struct super_block *sb) ++{ ++ return sb->s_fs_info; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_EXPORT ++int au_test_nfsd(void); ++void au_export_init(struct super_block *sb); ++void au_xigen_inc(struct inode *inode); ++int au_xigen_new(struct inode *inode); ++int au_xigen_set(struct super_block *sb, struct file *base); ++void au_xigen_clr(struct super_block *sb); ++ ++static inline int au_busy_or_stale(void) ++{ ++ if (!au_test_nfsd()) ++ return -EBUSY; ++ return -ESTALE; ++} ++#else ++AuStubInt0(au_test_nfsd, void) ++AuStubVoid(au_export_init, struct super_block *sb) ++AuStubVoid(au_xigen_inc, struct inode *inode) ++AuStubInt0(au_xigen_new, struct inode *inode) ++AuStubInt0(au_xigen_set, struct super_block *sb, struct file *base) ++AuStubVoid(au_xigen_clr, struct super_block *sb) ++AuStub(int, au_busy_or_stale, return -EBUSY, void) ++#endif /* CONFIG_AUFS_EXPORT */ ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_SBILIST ++/* module.c */ ++extern struct au_sphlhead au_sbilist; ++ ++static inline void au_sbilist_init(void) ++{ ++ au_sphl_init(&au_sbilist); ++} ++ ++static inline void au_sbilist_add(struct super_block *sb) ++{ ++ au_sphl_add(&au_sbi(sb)->si_list, &au_sbilist); ++} ++ ++static inline void au_sbilist_del(struct super_block *sb) ++{ ++ au_sphl_del(&au_sbi(sb)->si_list, &au_sbilist); ++} ++ ++#ifdef CONFIG_AUFS_MAGIC_SYSRQ ++static inline void au_sbilist_lock(void) ++{ ++ spin_lock(&au_sbilist.spin); ++} ++ ++static inline void au_sbilist_unlock(void) ++{ ++ spin_unlock(&au_sbilist.spin); ++} ++#define AuGFP_SBILIST GFP_ATOMIC ++#else ++AuStubVoid(au_sbilist_lock, void) ++AuStubVoid(au_sbilist_unlock, void) ++#define AuGFP_SBILIST GFP_NOFS ++#endif /* CONFIG_AUFS_MAGIC_SYSRQ */ ++#else ++AuStubVoid(au_sbilist_init, void) ++AuStubVoid(au_sbilist_add, struct super_block *sb) ++AuStubVoid(au_sbilist_del, struct super_block *sb) ++AuStubVoid(au_sbilist_lock, void) ++AuStubVoid(au_sbilist_unlock, void) ++#define AuGFP_SBILIST GFP_NOFS ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline void dbgaufs_si_null(struct au_sbinfo *sbinfo) ++{ ++ /* ++ * This function is a dynamic '__init' function actually, ++ * so the tiny check for si_rwsem is unnecessary. ++ */ ++ /* AuRwMustWriteLock(&sbinfo->si_rwsem); */ ++#ifdef CONFIG_DEBUG_FS ++ sbinfo->si_dbgaufs = NULL; ++ sbinfo->si_dbgaufs_plink = NULL; ++ sbinfo->si_dbgaufs_xib = NULL; ++#ifdef CONFIG_AUFS_EXPORT ++ sbinfo->si_dbgaufs_xigen = NULL; ++#endif ++#endif ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline void si_pid_idx_bit(int *idx, pid_t *bit) ++{ ++ /* the origin of pid is 1, but the bitmap's is 0 */ ++ *bit = current->pid - 1; ++ *idx = *bit / AU_PIDSTEP; ++ *bit %= AU_PIDSTEP; ++} ++ ++static inline int si_pid_test(struct super_block *sb) ++{ ++ pid_t bit; ++ int idx; ++ unsigned long *bitmap; ++ ++ si_pid_idx_bit(&idx, &bit); ++ bitmap = au_sbi(sb)->au_si_pid.pid_bitmap[idx]; ++ if (bitmap) ++ return test_bit(bit, bitmap); ++ return 0; ++} ++ ++static inline void si_pid_clr(struct super_block *sb) ++{ ++ pid_t bit; ++ int idx; ++ unsigned long *bitmap; ++ ++ si_pid_idx_bit(&idx, &bit); ++ bitmap = au_sbi(sb)->au_si_pid.pid_bitmap[idx]; ++ BUG_ON(!bitmap); ++ AuDebugOn(!test_bit(bit, bitmap)); ++ clear_bit(bit, bitmap); ++ /* smp_mb(); */ ++} ++ ++void si_pid_set(struct super_block *sb); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* lock superblock. mainly for entry point functions */ ++/* ++ * __si_read_lock, __si_write_lock, ++ * __si_read_unlock, __si_write_unlock, __si_downgrade_lock ++ */ ++AuSimpleRwsemFuncs(__si, struct super_block *sb, &au_sbi(sb)->si_rwsem); ++ ++#define SiMustNoWaiters(sb) AuRwMustNoWaiters(&au_sbi(sb)->si_rwsem) ++#define SiMustAnyLock(sb) AuRwMustAnyLock(&au_sbi(sb)->si_rwsem) ++#define SiMustWriteLock(sb) AuRwMustWriteLock(&au_sbi(sb)->si_rwsem) ++ ++static inline void si_noflush_read_lock(struct super_block *sb) ++{ ++ __si_read_lock(sb); ++ si_pid_set(sb); ++} ++ ++static inline int si_noflush_read_trylock(struct super_block *sb) ++{ ++ int locked; ++ ++ locked = __si_read_trylock(sb); ++ if (locked) ++ si_pid_set(sb); ++ return locked; ++} ++ ++static inline void si_noflush_write_lock(struct super_block *sb) ++{ ++ __si_write_lock(sb); ++ si_pid_set(sb); ++} ++ ++static inline int si_noflush_write_trylock(struct super_block *sb) ++{ ++ int locked; ++ ++ locked = __si_write_trylock(sb); ++ if (locked) ++ si_pid_set(sb); ++ return locked; ++} ++ ++#if 0 /* reserved */ ++static inline int si_read_trylock(struct super_block *sb, int flags) ++{ ++ if (au_ftest_lock(flags, FLUSH)) ++ au_nwt_flush(&au_sbi(sb)->si_nowait); ++ return si_noflush_read_trylock(sb); ++} ++#endif ++ ++static inline void si_read_unlock(struct super_block *sb) ++{ ++ si_pid_clr(sb); ++ __si_read_unlock(sb); ++} ++ ++#if 0 /* reserved */ ++static inline int si_write_trylock(struct super_block *sb, int flags) ++{ ++ if (au_ftest_lock(flags, FLUSH)) ++ au_nwt_flush(&au_sbi(sb)->si_nowait); ++ return si_noflush_write_trylock(sb); ++} ++#endif ++ ++static inline void si_write_unlock(struct super_block *sb) ++{ ++ si_pid_clr(sb); ++ __si_write_unlock(sb); ++} ++ ++#if 0 /* reserved */ ++static inline void si_downgrade_lock(struct super_block *sb) ++{ ++ __si_downgrade_lock(sb); ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline aufs_bindex_t au_sbend(struct super_block *sb) ++{ ++ SiMustAnyLock(sb); ++ return au_sbi(sb)->si_bend; ++} ++ ++static inline unsigned int au_mntflags(struct super_block *sb) ++{ ++ SiMustAnyLock(sb); ++ return au_sbi(sb)->si_mntflags; ++} ++ ++static inline unsigned int au_sigen(struct super_block *sb) ++{ ++ SiMustAnyLock(sb); ++ return au_sbi(sb)->si_generation; ++} ++ ++static inline void au_ninodes_inc(struct super_block *sb) ++{ ++ atomic_long_inc(&au_sbi(sb)->si_ninodes); ++} ++ ++static inline void au_ninodes_dec(struct super_block *sb) ++{ ++ AuDebugOn(!atomic_long_read(&au_sbi(sb)->si_ninodes)); ++ atomic_long_dec(&au_sbi(sb)->si_ninodes); ++} ++ ++static inline void au_nfiles_inc(struct super_block *sb) ++{ ++ atomic_long_inc(&au_sbi(sb)->si_nfiles); ++} ++ ++static inline void au_nfiles_dec(struct super_block *sb) ++{ ++ AuDebugOn(!atomic_long_read(&au_sbi(sb)->si_nfiles)); ++ atomic_long_dec(&au_sbi(sb)->si_nfiles); ++} ++ ++static inline struct au_branch *au_sbr(struct super_block *sb, ++ aufs_bindex_t bindex) ++{ ++ SiMustAnyLock(sb); ++ return au_sbi(sb)->si_branch[0 + bindex]; ++} ++ ++static inline void au_xino_brid_set(struct super_block *sb, aufs_bindex_t brid) ++{ ++ SiMustWriteLock(sb); ++ au_sbi(sb)->si_xino_brid = brid; ++} ++ ++static inline aufs_bindex_t au_xino_brid(struct super_block *sb) ++{ ++ SiMustAnyLock(sb); ++ return au_sbi(sb)->si_xino_brid; ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_SUPER_H__ */ +diff --git a/fs/aufs/sysaufs.c b/fs/aufs/sysaufs.c +new file mode 100644 +index 0000000..75c9c24 +--- /dev/null ++++ b/fs/aufs/sysaufs.c +@@ -0,0 +1,104 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * sysfs interface and lifetime management ++ * they are necessary regardless sysfs is disabled. ++ */ ++ ++#include ++#include "aufs.h" ++ ++unsigned long sysaufs_si_mask; ++struct kset *sysaufs_kset; ++ ++#define AuSiAttr(_name) { \ ++ .attr = { .name = __stringify(_name), .mode = 0444 }, \ ++ .show = sysaufs_si_##_name, \ ++} ++ ++static struct sysaufs_si_attr sysaufs_si_attr_xi_path = AuSiAttr(xi_path); ++struct attribute *sysaufs_si_attrs[] = { ++ &sysaufs_si_attr_xi_path.attr, ++ NULL, ++}; ++ ++static const struct sysfs_ops au_sbi_ops = { ++ .show = sysaufs_si_show ++}; ++ ++static struct kobj_type au_sbi_ktype = { ++ .release = au_si_free, ++ .sysfs_ops = &au_sbi_ops, ++ .default_attrs = sysaufs_si_attrs ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++int sysaufs_si_init(struct au_sbinfo *sbinfo) ++{ ++ int err; ++ ++ sbinfo->si_kobj.kset = sysaufs_kset; ++ /* cf. sysaufs_name() */ ++ err = kobject_init_and_add ++ (&sbinfo->si_kobj, &au_sbi_ktype, /*&sysaufs_kset->kobj*/NULL, ++ SysaufsSiNamePrefix "%lx", sysaufs_si_id(sbinfo)); ++ ++ dbgaufs_si_null(sbinfo); ++ if (!err) { ++ err = dbgaufs_si_init(sbinfo); ++ if (unlikely(err)) ++ kobject_put(&sbinfo->si_kobj); ++ } ++ return err; ++} ++ ++void sysaufs_fin(void) ++{ ++ dbgaufs_fin(); ++ sysfs_remove_group(&sysaufs_kset->kobj, sysaufs_attr_group); ++ kset_unregister(sysaufs_kset); ++} ++ ++int __init sysaufs_init(void) ++{ ++ int err; ++ ++ do { ++ get_random_bytes(&sysaufs_si_mask, sizeof(sysaufs_si_mask)); ++ } while (!sysaufs_si_mask); ++ ++ err = -EINVAL; ++ sysaufs_kset = kset_create_and_add(AUFS_NAME, NULL, fs_kobj); ++ if (unlikely(!sysaufs_kset)) ++ goto out; ++ err = PTR_ERR(sysaufs_kset); ++ if (IS_ERR(sysaufs_kset)) ++ goto out; ++ err = sysfs_create_group(&sysaufs_kset->kobj, sysaufs_attr_group); ++ if (unlikely(err)) { ++ kset_unregister(sysaufs_kset); ++ goto out; ++ } ++ ++ err = dbgaufs_init(); ++ if (unlikely(err)) ++ sysaufs_fin(); ++out: ++ return err; ++} +diff --git a/fs/aufs/sysaufs.h b/fs/aufs/sysaufs.h +new file mode 100644 +index 0000000..14975c9 +--- /dev/null ++++ b/fs/aufs/sysaufs.h +@@ -0,0 +1,101 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * sysfs interface and mount lifetime management ++ */ ++ ++#ifndef __SYSAUFS_H__ ++#define __SYSAUFS_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include "module.h" ++ ++struct super_block; ++struct au_sbinfo; ++ ++struct sysaufs_si_attr { ++ struct attribute attr; ++ int (*show)(struct seq_file *seq, struct super_block *sb); ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* sysaufs.c */ ++extern unsigned long sysaufs_si_mask; ++extern struct kset *sysaufs_kset; ++extern struct attribute *sysaufs_si_attrs[]; ++int sysaufs_si_init(struct au_sbinfo *sbinfo); ++int __init sysaufs_init(void); ++void sysaufs_fin(void); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* some people doesn't like to show a pointer in kernel */ ++static inline unsigned long sysaufs_si_id(struct au_sbinfo *sbinfo) ++{ ++ return sysaufs_si_mask ^ (unsigned long)sbinfo; ++} ++ ++#define SysaufsSiNamePrefix "si_" ++#define SysaufsSiNameLen (sizeof(SysaufsSiNamePrefix) + 16) ++static inline void sysaufs_name(struct au_sbinfo *sbinfo, char *name) ++{ ++ snprintf(name, SysaufsSiNameLen, SysaufsSiNamePrefix "%lx", ++ sysaufs_si_id(sbinfo)); ++} ++ ++struct au_branch; ++#ifdef CONFIG_SYSFS ++/* sysfs.c */ ++extern struct attribute_group *sysaufs_attr_group; ++ ++int sysaufs_si_xi_path(struct seq_file *seq, struct super_block *sb); ++ssize_t sysaufs_si_show(struct kobject *kobj, struct attribute *attr, ++ char *buf); ++long au_brinfo_ioctl(struct file *file, unsigned long arg); ++#ifdef CONFIG_COMPAT ++long au_brinfo_compat_ioctl(struct file *file, unsigned long arg); ++#endif ++ ++void sysaufs_br_init(struct au_branch *br); ++void sysaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex); ++void sysaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex); ++ ++#define sysaufs_brs_init() do {} while (0) ++ ++#else ++#define sysaufs_attr_group NULL ++ ++AuStubInt0(sysaufs_si_xi_path, struct seq_file *seq, struct super_block *sb) ++AuStub(ssize_t, sysaufs_si_show, return 0, struct kobject *kobj, ++ struct attribute *attr, char *buf) ++AuStubVoid(sysaufs_br_init, struct au_branch *br) ++AuStubVoid(sysaufs_brs_add, struct super_block *sb, aufs_bindex_t bindex) ++AuStubVoid(sysaufs_brs_del, struct super_block *sb, aufs_bindex_t bindex) ++ ++static inline void sysaufs_brs_init(void) ++{ ++ sysaufs_brs = 0; ++} ++ ++#endif /* CONFIG_SYSFS */ ++ ++#endif /* __KERNEL__ */ ++#endif /* __SYSAUFS_H__ */ +diff --git a/fs/aufs/sysfs.c b/fs/aufs/sysfs.c +new file mode 100644 +index 0000000..b2d1888 +--- /dev/null ++++ b/fs/aufs/sysfs.c +@@ -0,0 +1,376 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * sysfs interface ++ */ ++ ++#include ++#include ++#include "aufs.h" ++ ++#ifdef CONFIG_AUFS_FS_MODULE ++/* this entry violates the "one line per file" policy of sysfs */ ++static ssize_t config_show(struct kobject *kobj, struct kobj_attribute *attr, ++ char *buf) ++{ ++ ssize_t err; ++ static char *conf = ++/* this file is generated at compiling */ ++#include "conf.str" ++ ; ++ ++ err = snprintf(buf, PAGE_SIZE, conf); ++ if (unlikely(err >= PAGE_SIZE)) ++ err = -EFBIG; ++ return err; ++} ++ ++static struct kobj_attribute au_config_attr = __ATTR_RO(config); ++#endif ++ ++static struct attribute *au_attr[] = { ++#ifdef CONFIG_AUFS_FS_MODULE ++ &au_config_attr.attr, ++#endif ++ NULL, /* need to NULL terminate the list of attributes */ ++}; ++ ++static struct attribute_group sysaufs_attr_group_body = { ++ .attrs = au_attr ++}; ++ ++struct attribute_group *sysaufs_attr_group = &sysaufs_attr_group_body; ++ ++/* ---------------------------------------------------------------------- */ ++ ++int sysaufs_si_xi_path(struct seq_file *seq, struct super_block *sb) ++{ ++ int err; ++ ++ SiMustAnyLock(sb); ++ ++ err = 0; ++ if (au_opt_test(au_mntflags(sb), XINO)) { ++ err = au_xino_path(seq, au_sbi(sb)->si_xib); ++ seq_putc(seq, '\n'); ++ } ++ return err; ++} ++ ++/* ++ * the lifetime of branch is independent from the entry under sysfs. ++ * sysfs handles the lifetime of the entry, and never call ->show() after it is ++ * unlinked. ++ */ ++static int sysaufs_si_br(struct seq_file *seq, struct super_block *sb, ++ aufs_bindex_t bindex, int idx) ++{ ++ int err; ++ struct path path; ++ struct dentry *root; ++ struct au_branch *br; ++ au_br_perm_str_t perm; ++ ++ AuDbg("b%d\n", bindex); ++ ++ err = 0; ++ root = sb->s_root; ++ di_read_lock_parent(root, !AuLock_IR); ++ br = au_sbr(sb, bindex); ++ ++ switch (idx) { ++ case AuBrSysfs_BR: ++ path.mnt = au_br_mnt(br); ++ path.dentry = au_h_dptr(root, bindex); ++ err = au_seq_path(seq, &path); ++ if (!err) { ++ au_optstr_br_perm(&perm, br->br_perm); ++ err = seq_printf(seq, "=%s\n", perm.a); ++ } ++ break; ++ case AuBrSysfs_BRID: ++ err = seq_printf(seq, "%d\n", br->br_id); ++ break; ++ } ++ di_read_unlock(root, !AuLock_IR); ++ if (err == -1) ++ err = -E2BIG; ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct seq_file *au_seq(char *p, ssize_t len) ++{ ++ struct seq_file *seq; ++ ++ seq = kzalloc(sizeof(*seq), GFP_NOFS); ++ if (seq) { ++ /* mutex_init(&seq.lock); */ ++ seq->buf = p; ++ seq->size = len; ++ return seq; /* success */ ++ } ++ ++ seq = ERR_PTR(-ENOMEM); ++ return seq; ++} ++ ++#define SysaufsBr_PREFIX "br" ++#define SysaufsBrid_PREFIX "brid" ++ ++/* todo: file size may exceed PAGE_SIZE */ ++ssize_t sysaufs_si_show(struct kobject *kobj, struct attribute *attr, ++ char *buf) ++{ ++ ssize_t err; ++ int idx; ++ long l; ++ aufs_bindex_t bend; ++ struct au_sbinfo *sbinfo; ++ struct super_block *sb; ++ struct seq_file *seq; ++ char *name; ++ struct attribute **cattr; ++ ++ sbinfo = container_of(kobj, struct au_sbinfo, si_kobj); ++ sb = sbinfo->si_sb; ++ ++ /* ++ * prevent a race condition between sysfs and aufs. ++ * for instance, sysfs_file_read() calls sysfs_get_active_two() which ++ * prohibits maintaining the sysfs entries. ++ * hew we acquire read lock after sysfs_get_active_two(). ++ * on the other hand, the remount process may maintain the sysfs/aufs ++ * entries after acquiring write lock. ++ * it can cause a deadlock. ++ * simply we gave up processing read here. ++ */ ++ err = -EBUSY; ++ if (unlikely(!si_noflush_read_trylock(sb))) ++ goto out; ++ ++ seq = au_seq(buf, PAGE_SIZE); ++ err = PTR_ERR(seq); ++ if (IS_ERR(seq)) ++ goto out_unlock; ++ ++ name = (void *)attr->name; ++ cattr = sysaufs_si_attrs; ++ while (*cattr) { ++ if (!strcmp(name, (*cattr)->name)) { ++ err = container_of(*cattr, struct sysaufs_si_attr, attr) ++ ->show(seq, sb); ++ goto out_seq; ++ } ++ cattr++; ++ } ++ ++ if (!strncmp(name, SysaufsBrid_PREFIX, ++ sizeof(SysaufsBrid_PREFIX) - 1)) { ++ idx = AuBrSysfs_BRID; ++ name += sizeof(SysaufsBrid_PREFIX) - 1; ++ } else if (!strncmp(name, SysaufsBr_PREFIX, ++ sizeof(SysaufsBr_PREFIX) - 1)) { ++ idx = AuBrSysfs_BR; ++ name += sizeof(SysaufsBr_PREFIX) - 1; ++ } else ++ BUG(); ++ ++ err = kstrtol(name, 10, &l); ++ if (!err) { ++ bend = au_sbend(sb); ++ if (l <= bend) ++ err = sysaufs_si_br(seq, sb, (aufs_bindex_t)l, idx); ++ else ++ err = -ENOENT; ++ } ++ ++out_seq: ++ if (!err) { ++ err = seq->count; ++ /* sysfs limit */ ++ if (unlikely(err == PAGE_SIZE)) ++ err = -EFBIG; ++ } ++ kfree(seq); ++out_unlock: ++ si_read_unlock(sb); ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_brinfo(struct super_block *sb, union aufs_brinfo __user *arg) ++{ ++ int err; ++ int16_t brid; ++ aufs_bindex_t bindex, bend; ++ size_t sz; ++ char *buf; ++ struct seq_file *seq; ++ struct au_branch *br; ++ ++ si_read_lock(sb, AuLock_FLUSH); ++ bend = au_sbend(sb); ++ err = bend + 1; ++ if (!arg) ++ goto out; ++ ++ err = -ENOMEM; ++ buf = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!buf)) ++ goto out; ++ ++ seq = au_seq(buf, PAGE_SIZE); ++ err = PTR_ERR(seq); ++ if (IS_ERR(seq)) ++ goto out_buf; ++ ++ sz = sizeof(*arg) - offsetof(union aufs_brinfo, path); ++ for (bindex = 0; bindex <= bend; bindex++, arg++) { ++ err = !access_ok(VERIFY_WRITE, arg, sizeof(*arg)); ++ if (unlikely(err)) ++ break; ++ ++ br = au_sbr(sb, bindex); ++ brid = br->br_id; ++ BUILD_BUG_ON(sizeof(brid) != sizeof(arg->id)); ++ err = __put_user(brid, &arg->id); ++ if (unlikely(err)) ++ break; ++ ++ BUILD_BUG_ON(sizeof(br->br_perm) != sizeof(arg->perm)); ++ err = __put_user(br->br_perm, &arg->perm); ++ if (unlikely(err)) ++ break; ++ ++ err = au_seq_path(seq, &br->br_path); ++ if (unlikely(err)) ++ break; ++ err = seq_putc(seq, '\0'); ++ if (!err && seq->count <= sz) { ++ err = copy_to_user(arg->path, seq->buf, seq->count); ++ seq->count = 0; ++ if (unlikely(err)) ++ break; ++ } else { ++ err = -E2BIG; ++ goto out_seq; ++ } ++ } ++ if (unlikely(err)) ++ err = -EFAULT; ++ ++out_seq: ++ kfree(seq); ++out_buf: ++ free_page((unsigned long)buf); ++out: ++ si_read_unlock(sb); ++ return err; ++} ++ ++long au_brinfo_ioctl(struct file *file, unsigned long arg) ++{ ++ return au_brinfo(file->f_dentry->d_sb, (void __user *)arg); ++} ++ ++#ifdef CONFIG_COMPAT ++long au_brinfo_compat_ioctl(struct file *file, unsigned long arg) ++{ ++ return au_brinfo(file->f_dentry->d_sb, compat_ptr(arg)); ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++void sysaufs_br_init(struct au_branch *br) ++{ ++ int i; ++ struct au_brsysfs *br_sysfs; ++ struct attribute *attr; ++ ++ br_sysfs = br->br_sysfs; ++ for (i = 0; i < ARRAY_SIZE(br->br_sysfs); i++) { ++ attr = &br_sysfs->attr; ++ sysfs_attr_init(attr); ++ attr->name = br_sysfs->name; ++ attr->mode = S_IRUGO; ++ br_sysfs++; ++ } ++} ++ ++void sysaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ struct au_branch *br; ++ struct kobject *kobj; ++ struct au_brsysfs *br_sysfs; ++ int i; ++ aufs_bindex_t bend; ++ ++ dbgaufs_brs_del(sb, bindex); ++ ++ if (!sysaufs_brs) ++ return; ++ ++ kobj = &au_sbi(sb)->si_kobj; ++ bend = au_sbend(sb); ++ for (; bindex <= bend; bindex++) { ++ br = au_sbr(sb, bindex); ++ br_sysfs = br->br_sysfs; ++ for (i = 0; i < ARRAY_SIZE(br->br_sysfs); i++) { ++ sysfs_remove_file(kobj, &br_sysfs->attr); ++ br_sysfs++; ++ } ++ } ++} ++ ++void sysaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ int err, i; ++ aufs_bindex_t bend; ++ struct kobject *kobj; ++ struct au_branch *br; ++ struct au_brsysfs *br_sysfs; ++ ++ dbgaufs_brs_add(sb, bindex); ++ ++ if (!sysaufs_brs) ++ return; ++ ++ kobj = &au_sbi(sb)->si_kobj; ++ bend = au_sbend(sb); ++ for (; bindex <= bend; bindex++) { ++ br = au_sbr(sb, bindex); ++ br_sysfs = br->br_sysfs; ++ snprintf(br_sysfs[AuBrSysfs_BR].name, sizeof(br_sysfs->name), ++ SysaufsBr_PREFIX "%d", bindex); ++ snprintf(br_sysfs[AuBrSysfs_BRID].name, sizeof(br_sysfs->name), ++ SysaufsBrid_PREFIX "%d", bindex); ++ for (i = 0; i < ARRAY_SIZE(br->br_sysfs); i++) { ++ err = sysfs_create_file(kobj, &br_sysfs->attr); ++ if (unlikely(err)) ++ pr_warn("failed %s under sysfs(%d)\n", ++ br_sysfs->name, err); ++ br_sysfs++; ++ } ++ } ++} +diff --git a/fs/aufs/sysrq.c b/fs/aufs/sysrq.c +new file mode 100644 +index 0000000..057c23e +--- /dev/null ++++ b/fs/aufs/sysrq.c +@@ -0,0 +1,157 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * magic sysrq hanlder ++ */ ++ ++/* #include */ ++#include ++#include "aufs.h" ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void sysrq_sb(struct super_block *sb) ++{ ++ char *plevel; ++ struct au_sbinfo *sbinfo; ++ struct file *file; ++ struct au_sphlhead *files; ++ struct au_finfo *finfo; ++ ++ plevel = au_plevel; ++ au_plevel = KERN_WARNING; ++ ++ /* since we define pr_fmt, call printk directly */ ++#define pr(str) printk(KERN_WARNING AUFS_NAME ": " str) ++ ++ sbinfo = au_sbi(sb); ++ printk(KERN_WARNING "si=%lx\n", sysaufs_si_id(sbinfo)); ++ pr("superblock\n"); ++ au_dpri_sb(sb); ++ ++#if 0 ++ pr("root dentry\n"); ++ au_dpri_dentry(sb->s_root); ++ pr("root inode\n"); ++ au_dpri_inode(sb->s_root->d_inode); ++#endif ++ ++#if 0 ++ do { ++ int err, i, j, ndentry; ++ struct au_dcsub_pages dpages; ++ struct au_dpage *dpage; ++ ++ err = au_dpages_init(&dpages, GFP_ATOMIC); ++ if (unlikely(err)) ++ break; ++ err = au_dcsub_pages(&dpages, sb->s_root, NULL, NULL); ++ if (!err) ++ for (i = 0; i < dpages.ndpage; i++) { ++ dpage = dpages.dpages + i; ++ ndentry = dpage->ndentry; ++ for (j = 0; j < ndentry; j++) ++ au_dpri_dentry(dpage->dentries[j]); ++ } ++ au_dpages_free(&dpages); ++ } while (0); ++#endif ++ ++#if 1 ++ { ++ struct inode *i; ++ ++ pr("isolated inode\n"); ++ spin_lock(&inode_sb_list_lock); ++ list_for_each_entry(i, &sb->s_inodes, i_sb_list) { ++ spin_lock(&i->i_lock); ++ if (1 || hlist_empty(&i->i_dentry)) ++ au_dpri_inode(i); ++ spin_unlock(&i->i_lock); ++ } ++ spin_unlock(&inode_sb_list_lock); ++ } ++#endif ++ pr("files\n"); ++ files = &au_sbi(sb)->si_files; ++ spin_lock(&files->spin); ++ hlist_for_each_entry(finfo, &files->head, fi_hlist) { ++ umode_t mode; ++ ++ file = finfo->fi_file; ++ mode = file_inode(file)->i_mode; ++ if (!special_file(mode)) ++ au_dpri_file(file); ++ } ++ spin_unlock(&files->spin); ++ pr("done\n"); ++ ++#undef pr ++ au_plevel = plevel; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* module parameter */ ++static char *aufs_sysrq_key = "a"; ++module_param_named(sysrq, aufs_sysrq_key, charp, S_IRUGO); ++MODULE_PARM_DESC(sysrq, "MagicSysRq key for " AUFS_NAME); ++ ++static void au_sysrq(int key __maybe_unused) ++{ ++ struct au_sbinfo *sbinfo; ++ ++ lockdep_off(); ++ au_sbilist_lock(); ++ hlist_for_each_entry(sbinfo, &au_sbilist.head, si_list) ++ sysrq_sb(sbinfo->si_sb); ++ au_sbilist_unlock(); ++ lockdep_on(); ++} ++ ++static struct sysrq_key_op au_sysrq_op = { ++ .handler = au_sysrq, ++ .help_msg = "Aufs", ++ .action_msg = "Aufs", ++ .enable_mask = SYSRQ_ENABLE_DUMP ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++int __init au_sysrq_init(void) ++{ ++ int err; ++ char key; ++ ++ err = -1; ++ key = *aufs_sysrq_key; ++ if ('a' <= key && key <= 'z') ++ err = register_sysrq_key(key, &au_sysrq_op); ++ if (unlikely(err)) ++ pr_err("err %d, sysrq=%c\n", err, key); ++ return err; ++} ++ ++void au_sysrq_fin(void) ++{ ++ int err; ++ ++ err = unregister_sysrq_key(*aufs_sysrq_key, &au_sysrq_op); ++ if (unlikely(err)) ++ pr_err("err %d (ignored)\n", err); ++} +diff --git a/fs/aufs/vdir.c b/fs/aufs/vdir.c +new file mode 100644 +index 0000000..f942d16 +--- /dev/null ++++ b/fs/aufs/vdir.c +@@ -0,0 +1,888 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * virtual or vertical directory ++ */ ++ ++#include "aufs.h" ++ ++static unsigned int calc_size(int nlen) ++{ ++ return ALIGN(sizeof(struct au_vdir_de) + nlen, sizeof(ino_t)); ++} ++ ++static int set_deblk_end(union au_vdir_deblk_p *p, ++ union au_vdir_deblk_p *deblk_end) ++{ ++ if (calc_size(0) <= deblk_end->deblk - p->deblk) { ++ p->de->de_str.len = 0; ++ /* smp_mb(); */ ++ return 0; ++ } ++ return -1; /* error */ ++} ++ ++/* returns true or false */ ++static int is_deblk_end(union au_vdir_deblk_p *p, ++ union au_vdir_deblk_p *deblk_end) ++{ ++ if (calc_size(0) <= deblk_end->deblk - p->deblk) ++ return !p->de->de_str.len; ++ return 1; ++} ++ ++static unsigned char *last_deblk(struct au_vdir *vdir) ++{ ++ return vdir->vd_deblk[vdir->vd_nblk - 1]; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* estimate the appropriate size for name hash table */ ++unsigned int au_rdhash_est(loff_t sz) ++{ ++ unsigned int n; ++ ++ n = UINT_MAX; ++ sz >>= 10; ++ if (sz < n) ++ n = sz; ++ if (sz < AUFS_RDHASH_DEF) ++ n = AUFS_RDHASH_DEF; ++ /* pr_info("n %u\n", n); */ ++ return n; ++} ++ ++/* ++ * the allocated memory has to be freed by ++ * au_nhash_wh_free() or au_nhash_de_free(). ++ */ ++int au_nhash_alloc(struct au_nhash *nhash, unsigned int num_hash, gfp_t gfp) ++{ ++ struct hlist_head *head; ++ unsigned int u; ++ size_t sz; ++ ++ sz = sizeof(*nhash->nh_head) * num_hash; ++ head = kmalloc(sz, gfp); ++ if (head) { ++ nhash->nh_num = num_hash; ++ nhash->nh_head = head; ++ for (u = 0; u < num_hash; u++) ++ INIT_HLIST_HEAD(head++); ++ return 0; /* success */ ++ } ++ ++ return -ENOMEM; ++} ++ ++static void nhash_count(struct hlist_head *head) ++{ ++#if 0 ++ unsigned long n; ++ struct hlist_node *pos; ++ ++ n = 0; ++ hlist_for_each(pos, head) ++ n++; ++ pr_info("%lu\n", n); ++#endif ++} ++ ++static void au_nhash_wh_do_free(struct hlist_head *head) ++{ ++ struct au_vdir_wh *pos; ++ struct hlist_node *node; ++ ++ hlist_for_each_entry_safe(pos, node, head, wh_hash) ++ kfree(pos); ++} ++ ++static void au_nhash_de_do_free(struct hlist_head *head) ++{ ++ struct au_vdir_dehstr *pos; ++ struct hlist_node *node; ++ ++ hlist_for_each_entry_safe(pos, node, head, hash) ++ au_cache_free_vdir_dehstr(pos); ++} ++ ++static void au_nhash_do_free(struct au_nhash *nhash, ++ void (*free)(struct hlist_head *head)) ++{ ++ unsigned int n; ++ struct hlist_head *head; ++ ++ n = nhash->nh_num; ++ if (!n) ++ return; ++ ++ head = nhash->nh_head; ++ while (n-- > 0) { ++ nhash_count(head); ++ free(head++); ++ } ++ kfree(nhash->nh_head); ++} ++ ++void au_nhash_wh_free(struct au_nhash *whlist) ++{ ++ au_nhash_do_free(whlist, au_nhash_wh_do_free); ++} ++ ++static void au_nhash_de_free(struct au_nhash *delist) ++{ ++ au_nhash_do_free(delist, au_nhash_de_do_free); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_nhash_test_longer_wh(struct au_nhash *whlist, aufs_bindex_t btgt, ++ int limit) ++{ ++ int num; ++ unsigned int u, n; ++ struct hlist_head *head; ++ struct au_vdir_wh *pos; ++ ++ num = 0; ++ n = whlist->nh_num; ++ head = whlist->nh_head; ++ for (u = 0; u < n; u++, head++) ++ hlist_for_each_entry(pos, head, wh_hash) ++ if (pos->wh_bindex == btgt && ++num > limit) ++ return 1; ++ return 0; ++} ++ ++static struct hlist_head *au_name_hash(struct au_nhash *nhash, ++ unsigned char *name, ++ unsigned int len) ++{ ++ unsigned int v; ++ /* const unsigned int magic_bit = 12; */ ++ ++ AuDebugOn(!nhash->nh_num || !nhash->nh_head); ++ ++ v = 0; ++ while (len--) ++ v += *name++; ++ /* v = hash_long(v, magic_bit); */ ++ v %= nhash->nh_num; ++ return nhash->nh_head + v; ++} ++ ++static int au_nhash_test_name(struct au_vdir_destr *str, const char *name, ++ int nlen) ++{ ++ return str->len == nlen && !memcmp(str->name, name, nlen); ++} ++ ++/* returns found or not */ ++int au_nhash_test_known_wh(struct au_nhash *whlist, char *name, int nlen) ++{ ++ struct hlist_head *head; ++ struct au_vdir_wh *pos; ++ struct au_vdir_destr *str; ++ ++ head = au_name_hash(whlist, name, nlen); ++ hlist_for_each_entry(pos, head, wh_hash) { ++ str = &pos->wh_str; ++ AuDbg("%.*s\n", str->len, str->name); ++ if (au_nhash_test_name(str, name, nlen)) ++ return 1; ++ } ++ return 0; ++} ++ ++/* returns found(true) or not */ ++static int test_known(struct au_nhash *delist, char *name, int nlen) ++{ ++ struct hlist_head *head; ++ struct au_vdir_dehstr *pos; ++ struct au_vdir_destr *str; ++ ++ head = au_name_hash(delist, name, nlen); ++ hlist_for_each_entry(pos, head, hash) { ++ str = pos->str; ++ AuDbg("%.*s\n", str->len, str->name); ++ if (au_nhash_test_name(str, name, nlen)) ++ return 1; ++ } ++ return 0; ++} ++ ++static void au_shwh_init_wh(struct au_vdir_wh *wh, ino_t ino, ++ unsigned char d_type) ++{ ++#ifdef CONFIG_AUFS_SHWH ++ wh->wh_ino = ino; ++ wh->wh_type = d_type; ++#endif ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_nhash_append_wh(struct au_nhash *whlist, char *name, int nlen, ino_t ino, ++ unsigned int d_type, aufs_bindex_t bindex, ++ unsigned char shwh) ++{ ++ int err; ++ struct au_vdir_destr *str; ++ struct au_vdir_wh *wh; ++ ++ AuDbg("%.*s\n", nlen, name); ++ AuDebugOn(!whlist->nh_num || !whlist->nh_head); ++ ++ err = -ENOMEM; ++ wh = kmalloc(sizeof(*wh) + nlen, GFP_NOFS); ++ if (unlikely(!wh)) ++ goto out; ++ ++ err = 0; ++ wh->wh_bindex = bindex; ++ if (shwh) ++ au_shwh_init_wh(wh, ino, d_type); ++ str = &wh->wh_str; ++ str->len = nlen; ++ memcpy(str->name, name, nlen); ++ hlist_add_head(&wh->wh_hash, au_name_hash(whlist, name, nlen)); ++ /* smp_mb(); */ ++ ++out: ++ return err; ++} ++ ++static int append_deblk(struct au_vdir *vdir) ++{ ++ int err; ++ unsigned long ul; ++ const unsigned int deblk_sz = vdir->vd_deblk_sz; ++ union au_vdir_deblk_p p, deblk_end; ++ unsigned char **o; ++ ++ err = -ENOMEM; ++ o = krealloc(vdir->vd_deblk, sizeof(*o) * (vdir->vd_nblk + 1), ++ GFP_NOFS); ++ if (unlikely(!o)) ++ goto out; ++ ++ vdir->vd_deblk = o; ++ p.deblk = kmalloc(deblk_sz, GFP_NOFS); ++ if (p.deblk) { ++ ul = vdir->vd_nblk++; ++ vdir->vd_deblk[ul] = p.deblk; ++ vdir->vd_last.ul = ul; ++ vdir->vd_last.p.deblk = p.deblk; ++ deblk_end.deblk = p.deblk + deblk_sz; ++ err = set_deblk_end(&p, &deblk_end); ++ } ++ ++out: ++ return err; ++} ++ ++static int append_de(struct au_vdir *vdir, char *name, int nlen, ino_t ino, ++ unsigned int d_type, struct au_nhash *delist) ++{ ++ int err; ++ unsigned int sz; ++ const unsigned int deblk_sz = vdir->vd_deblk_sz; ++ union au_vdir_deblk_p p, *room, deblk_end; ++ struct au_vdir_dehstr *dehstr; ++ ++ p.deblk = last_deblk(vdir); ++ deblk_end.deblk = p.deblk + deblk_sz; ++ room = &vdir->vd_last.p; ++ AuDebugOn(room->deblk < p.deblk || deblk_end.deblk <= room->deblk ++ || !is_deblk_end(room, &deblk_end)); ++ ++ sz = calc_size(nlen); ++ if (unlikely(sz > deblk_end.deblk - room->deblk)) { ++ err = append_deblk(vdir); ++ if (unlikely(err)) ++ goto out; ++ ++ p.deblk = last_deblk(vdir); ++ deblk_end.deblk = p.deblk + deblk_sz; ++ /* smp_mb(); */ ++ AuDebugOn(room->deblk != p.deblk); ++ } ++ ++ err = -ENOMEM; ++ dehstr = au_cache_alloc_vdir_dehstr(); ++ if (unlikely(!dehstr)) ++ goto out; ++ ++ dehstr->str = &room->de->de_str; ++ hlist_add_head(&dehstr->hash, au_name_hash(delist, name, nlen)); ++ room->de->de_ino = ino; ++ room->de->de_type = d_type; ++ room->de->de_str.len = nlen; ++ memcpy(room->de->de_str.name, name, nlen); ++ ++ err = 0; ++ room->deblk += sz; ++ if (unlikely(set_deblk_end(room, &deblk_end))) ++ err = append_deblk(vdir); ++ /* smp_mb(); */ ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_vdir_free(struct au_vdir *vdir) ++{ ++ unsigned char **deblk; ++ ++ deblk = vdir->vd_deblk; ++ while (vdir->vd_nblk--) ++ kfree(*deblk++); ++ kfree(vdir->vd_deblk); ++ au_cache_free_vdir(vdir); ++} ++ ++static struct au_vdir *alloc_vdir(struct file *file) ++{ ++ struct au_vdir *vdir; ++ struct super_block *sb; ++ int err; ++ ++ sb = file->f_dentry->d_sb; ++ SiMustAnyLock(sb); ++ ++ err = -ENOMEM; ++ vdir = au_cache_alloc_vdir(); ++ if (unlikely(!vdir)) ++ goto out; ++ ++ vdir->vd_deblk = kzalloc(sizeof(*vdir->vd_deblk), GFP_NOFS); ++ if (unlikely(!vdir->vd_deblk)) ++ goto out_free; ++ ++ vdir->vd_deblk_sz = au_sbi(sb)->si_rdblk; ++ if (!vdir->vd_deblk_sz) { ++ /* estimate the appropriate size for deblk */ ++ vdir->vd_deblk_sz = au_dir_size(file, /*dentry*/NULL); ++ /* pr_info("vd_deblk_sz %u\n", vdir->vd_deblk_sz); */ ++ } ++ vdir->vd_nblk = 0; ++ vdir->vd_version = 0; ++ vdir->vd_jiffy = 0; ++ err = append_deblk(vdir); ++ if (!err) ++ return vdir; /* success */ ++ ++ kfree(vdir->vd_deblk); ++ ++out_free: ++ au_cache_free_vdir(vdir); ++out: ++ vdir = ERR_PTR(err); ++ return vdir; ++} ++ ++static int reinit_vdir(struct au_vdir *vdir) ++{ ++ int err; ++ union au_vdir_deblk_p p, deblk_end; ++ ++ while (vdir->vd_nblk > 1) { ++ kfree(vdir->vd_deblk[vdir->vd_nblk - 1]); ++ /* vdir->vd_deblk[vdir->vd_nblk - 1] = NULL; */ ++ vdir->vd_nblk--; ++ } ++ p.deblk = vdir->vd_deblk[0]; ++ deblk_end.deblk = p.deblk + vdir->vd_deblk_sz; ++ err = set_deblk_end(&p, &deblk_end); ++ /* keep vd_dblk_sz */ ++ vdir->vd_last.ul = 0; ++ vdir->vd_last.p.deblk = vdir->vd_deblk[0]; ++ vdir->vd_version = 0; ++ vdir->vd_jiffy = 0; ++ /* smp_mb(); */ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define AuFillVdir_CALLED 1 ++#define AuFillVdir_WHABLE (1 << 1) ++#define AuFillVdir_SHWH (1 << 2) ++#define au_ftest_fillvdir(flags, name) ((flags) & AuFillVdir_##name) ++#define au_fset_fillvdir(flags, name) \ ++ do { (flags) |= AuFillVdir_##name; } while (0) ++#define au_fclr_fillvdir(flags, name) \ ++ do { (flags) &= ~AuFillVdir_##name; } while (0) ++ ++#ifndef CONFIG_AUFS_SHWH ++#undef AuFillVdir_SHWH ++#define AuFillVdir_SHWH 0 ++#endif ++ ++struct fillvdir_arg { ++ struct dir_context ctx; ++ struct file *file; ++ struct au_vdir *vdir; ++ struct au_nhash delist; ++ struct au_nhash whlist; ++ aufs_bindex_t bindex; ++ unsigned int flags; ++ int err; ++}; ++ ++static int fillvdir(struct dir_context *ctx, const char *__name, int nlen, ++ loff_t offset __maybe_unused, u64 h_ino, ++ unsigned int d_type) ++{ ++ struct fillvdir_arg *arg = container_of(ctx, struct fillvdir_arg, ctx); ++ char *name = (void *)__name; ++ struct super_block *sb; ++ ino_t ino; ++ const unsigned char shwh = !!au_ftest_fillvdir(arg->flags, SHWH); ++ ++ arg->err = 0; ++ sb = arg->file->f_dentry->d_sb; ++ au_fset_fillvdir(arg->flags, CALLED); ++ /* smp_mb(); */ ++ if (nlen <= AUFS_WH_PFX_LEN ++ || memcmp(name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) { ++ if (test_known(&arg->delist, name, nlen) ++ || au_nhash_test_known_wh(&arg->whlist, name, nlen)) ++ goto out; /* already exists or whiteouted */ ++ ++ arg->err = au_ino(sb, arg->bindex, h_ino, d_type, &ino); ++ if (!arg->err) { ++ if (unlikely(nlen > AUFS_MAX_NAMELEN)) ++ d_type = DT_UNKNOWN; ++ arg->err = append_de(arg->vdir, name, nlen, ino, ++ d_type, &arg->delist); ++ } ++ } else if (au_ftest_fillvdir(arg->flags, WHABLE)) { ++ name += AUFS_WH_PFX_LEN; ++ nlen -= AUFS_WH_PFX_LEN; ++ if (au_nhash_test_known_wh(&arg->whlist, name, nlen)) ++ goto out; /* already whiteouted */ ++ ++ if (shwh) ++ arg->err = au_wh_ino(sb, arg->bindex, h_ino, d_type, ++ &ino); ++ if (!arg->err) { ++ if (nlen <= AUFS_MAX_NAMELEN + AUFS_WH_PFX_LEN) ++ d_type = DT_UNKNOWN; ++ arg->err = au_nhash_append_wh ++ (&arg->whlist, name, nlen, ino, d_type, ++ arg->bindex, shwh); ++ } ++ } ++ ++out: ++ if (!arg->err) ++ arg->vdir->vd_jiffy = jiffies; ++ /* smp_mb(); */ ++ AuTraceErr(arg->err); ++ return arg->err; ++} ++ ++static int au_handle_shwh(struct super_block *sb, struct au_vdir *vdir, ++ struct au_nhash *whlist, struct au_nhash *delist) ++{ ++#ifdef CONFIG_AUFS_SHWH ++ int err; ++ unsigned int nh, u; ++ struct hlist_head *head; ++ struct au_vdir_wh *pos; ++ struct hlist_node *n; ++ char *p, *o; ++ struct au_vdir_destr *destr; ++ ++ AuDebugOn(!au_opt_test(au_mntflags(sb), SHWH)); ++ ++ err = -ENOMEM; ++ o = p = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!p)) ++ goto out; ++ ++ err = 0; ++ nh = whlist->nh_num; ++ memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN); ++ p += AUFS_WH_PFX_LEN; ++ for (u = 0; u < nh; u++) { ++ head = whlist->nh_head + u; ++ hlist_for_each_entry_safe(pos, n, head, wh_hash) { ++ destr = &pos->wh_str; ++ memcpy(p, destr->name, destr->len); ++ err = append_de(vdir, o, destr->len + AUFS_WH_PFX_LEN, ++ pos->wh_ino, pos->wh_type, delist); ++ if (unlikely(err)) ++ break; ++ } ++ } ++ ++ free_page((unsigned long)o); ++ ++out: ++ AuTraceErr(err); ++ return err; ++#else ++ return 0; ++#endif ++} ++ ++static int au_do_read_vdir(struct fillvdir_arg *arg) ++{ ++ int err; ++ unsigned int rdhash; ++ loff_t offset; ++ aufs_bindex_t bend, bindex, bstart; ++ unsigned char shwh; ++ struct file *hf, *file; ++ struct super_block *sb; ++ ++ file = arg->file; ++ sb = file->f_dentry->d_sb; ++ SiMustAnyLock(sb); ++ ++ rdhash = au_sbi(sb)->si_rdhash; ++ if (!rdhash) ++ rdhash = au_rdhash_est(au_dir_size(file, /*dentry*/NULL)); ++ err = au_nhash_alloc(&arg->delist, rdhash, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ err = au_nhash_alloc(&arg->whlist, rdhash, GFP_NOFS); ++ if (unlikely(err)) ++ goto out_delist; ++ ++ err = 0; ++ arg->flags = 0; ++ shwh = 0; ++ if (au_opt_test(au_mntflags(sb), SHWH)) { ++ shwh = 1; ++ au_fset_fillvdir(arg->flags, SHWH); ++ } ++ bstart = au_fbstart(file); ++ bend = au_fbend_dir(file); ++ for (bindex = bstart; !err && bindex <= bend; bindex++) { ++ hf = au_hf_dir(file, bindex); ++ if (!hf) ++ continue; ++ ++ offset = vfsub_llseek(hf, 0, SEEK_SET); ++ err = offset; ++ if (unlikely(offset)) ++ break; ++ ++ arg->bindex = bindex; ++ au_fclr_fillvdir(arg->flags, WHABLE); ++ if (shwh ++ || (bindex != bend ++ && au_br_whable(au_sbr_perm(sb, bindex)))) ++ au_fset_fillvdir(arg->flags, WHABLE); ++ do { ++ arg->err = 0; ++ au_fclr_fillvdir(arg->flags, CALLED); ++ /* smp_mb(); */ ++ err = vfsub_iterate_dir(hf, &arg->ctx); ++ if (err >= 0) ++ err = arg->err; ++ } while (!err && au_ftest_fillvdir(arg->flags, CALLED)); ++ ++ /* ++ * dir_relax() may be good for concurrency, but aufs should not ++ * use it since it will cause a lockdep problem. ++ */ ++ } ++ ++ if (!err && shwh) ++ err = au_handle_shwh(sb, arg->vdir, &arg->whlist, &arg->delist); ++ ++ au_nhash_wh_free(&arg->whlist); ++ ++out_delist: ++ au_nhash_de_free(&arg->delist); ++out: ++ return err; ++} ++ ++static int read_vdir(struct file *file, int may_read) ++{ ++ int err; ++ unsigned long expire; ++ unsigned char do_read; ++ struct fillvdir_arg arg = { ++ .ctx = { ++ .actor = au_diractor(fillvdir) ++ } ++ }; ++ struct inode *inode; ++ struct au_vdir *vdir, *allocated; ++ ++ err = 0; ++ inode = file_inode(file); ++ IMustLock(inode); ++ SiMustAnyLock(inode->i_sb); ++ ++ allocated = NULL; ++ do_read = 0; ++ expire = au_sbi(inode->i_sb)->si_rdcache; ++ vdir = au_ivdir(inode); ++ if (!vdir) { ++ do_read = 1; ++ vdir = alloc_vdir(file); ++ err = PTR_ERR(vdir); ++ if (IS_ERR(vdir)) ++ goto out; ++ err = 0; ++ allocated = vdir; ++ } else if (may_read ++ && (inode->i_version != vdir->vd_version ++ || time_after(jiffies, vdir->vd_jiffy + expire))) { ++ do_read = 1; ++ err = reinit_vdir(vdir); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++ if (!do_read) ++ return 0; /* success */ ++ ++ arg.file = file; ++ arg.vdir = vdir; ++ err = au_do_read_vdir(&arg); ++ if (!err) { ++ /* file->f_pos = 0; */ /* todo: ctx->pos? */ ++ vdir->vd_version = inode->i_version; ++ vdir->vd_last.ul = 0; ++ vdir->vd_last.p.deblk = vdir->vd_deblk[0]; ++ if (allocated) ++ au_set_ivdir(inode, allocated); ++ } else if (allocated) ++ au_vdir_free(allocated); ++ ++out: ++ return err; ++} ++ ++static int copy_vdir(struct au_vdir *tgt, struct au_vdir *src) ++{ ++ int err, rerr; ++ unsigned long ul, n; ++ const unsigned int deblk_sz = src->vd_deblk_sz; ++ ++ AuDebugOn(tgt->vd_nblk != 1); ++ ++ err = -ENOMEM; ++ if (tgt->vd_nblk < src->vd_nblk) { ++ unsigned char **p; ++ ++ p = krealloc(tgt->vd_deblk, sizeof(*p) * src->vd_nblk, ++ GFP_NOFS); ++ if (unlikely(!p)) ++ goto out; ++ tgt->vd_deblk = p; ++ } ++ ++ if (tgt->vd_deblk_sz != deblk_sz) { ++ unsigned char *p; ++ ++ tgt->vd_deblk_sz = deblk_sz; ++ p = krealloc(tgt->vd_deblk[0], deblk_sz, GFP_NOFS); ++ if (unlikely(!p)) ++ goto out; ++ tgt->vd_deblk[0] = p; ++ } ++ memcpy(tgt->vd_deblk[0], src->vd_deblk[0], deblk_sz); ++ tgt->vd_version = src->vd_version; ++ tgt->vd_jiffy = src->vd_jiffy; ++ ++ n = src->vd_nblk; ++ for (ul = 1; ul < n; ul++) { ++ tgt->vd_deblk[ul] = kmemdup(src->vd_deblk[ul], deblk_sz, ++ GFP_NOFS); ++ if (unlikely(!tgt->vd_deblk[ul])) ++ goto out; ++ tgt->vd_nblk++; ++ } ++ tgt->vd_nblk = n; ++ tgt->vd_last.ul = tgt->vd_last.ul; ++ tgt->vd_last.p.deblk = tgt->vd_deblk[tgt->vd_last.ul]; ++ tgt->vd_last.p.deblk += src->vd_last.p.deblk ++ - src->vd_deblk[src->vd_last.ul]; ++ /* smp_mb(); */ ++ return 0; /* success */ ++ ++out: ++ rerr = reinit_vdir(tgt); ++ BUG_ON(rerr); ++ return err; ++} ++ ++int au_vdir_init(struct file *file) ++{ ++ int err; ++ struct inode *inode; ++ struct au_vdir *vdir_cache, *allocated; ++ ++ /* test file->f_pos here instead of ctx->pos */ ++ err = read_vdir(file, !file->f_pos); ++ if (unlikely(err)) ++ goto out; ++ ++ allocated = NULL; ++ vdir_cache = au_fvdir_cache(file); ++ if (!vdir_cache) { ++ vdir_cache = alloc_vdir(file); ++ err = PTR_ERR(vdir_cache); ++ if (IS_ERR(vdir_cache)) ++ goto out; ++ allocated = vdir_cache; ++ } else if (!file->f_pos && vdir_cache->vd_version != file->f_version) { ++ /* test file->f_pos here instead of ctx->pos */ ++ err = reinit_vdir(vdir_cache); ++ if (unlikely(err)) ++ goto out; ++ } else ++ return 0; /* success */ ++ ++ inode = file_inode(file); ++ err = copy_vdir(vdir_cache, au_ivdir(inode)); ++ if (!err) { ++ file->f_version = inode->i_version; ++ if (allocated) ++ au_set_fvdir_cache(file, allocated); ++ } else if (allocated) ++ au_vdir_free(allocated); ++ ++out: ++ return err; ++} ++ ++static loff_t calc_offset(struct au_vdir *vdir) ++{ ++ loff_t offset; ++ union au_vdir_deblk_p p; ++ ++ p.deblk = vdir->vd_deblk[vdir->vd_last.ul]; ++ offset = vdir->vd_last.p.deblk - p.deblk; ++ offset += vdir->vd_deblk_sz * vdir->vd_last.ul; ++ return offset; ++} ++ ++/* returns true or false */ ++static int seek_vdir(struct file *file, struct dir_context *ctx) ++{ ++ int valid; ++ unsigned int deblk_sz; ++ unsigned long ul, n; ++ loff_t offset; ++ union au_vdir_deblk_p p, deblk_end; ++ struct au_vdir *vdir_cache; ++ ++ valid = 1; ++ vdir_cache = au_fvdir_cache(file); ++ offset = calc_offset(vdir_cache); ++ AuDbg("offset %lld\n", offset); ++ if (ctx->pos == offset) ++ goto out; ++ ++ vdir_cache->vd_last.ul = 0; ++ vdir_cache->vd_last.p.deblk = vdir_cache->vd_deblk[0]; ++ if (!ctx->pos) ++ goto out; ++ ++ valid = 0; ++ deblk_sz = vdir_cache->vd_deblk_sz; ++ ul = div64_u64(ctx->pos, deblk_sz); ++ AuDbg("ul %lu\n", ul); ++ if (ul >= vdir_cache->vd_nblk) ++ goto out; ++ ++ n = vdir_cache->vd_nblk; ++ for (; ul < n; ul++) { ++ p.deblk = vdir_cache->vd_deblk[ul]; ++ deblk_end.deblk = p.deblk + deblk_sz; ++ offset = ul; ++ offset *= deblk_sz; ++ while (!is_deblk_end(&p, &deblk_end) && offset < ctx->pos) { ++ unsigned int l; ++ ++ l = calc_size(p.de->de_str.len); ++ offset += l; ++ p.deblk += l; ++ } ++ if (!is_deblk_end(&p, &deblk_end)) { ++ valid = 1; ++ vdir_cache->vd_last.ul = ul; ++ vdir_cache->vd_last.p = p; ++ break; ++ } ++ } ++ ++out: ++ /* smp_mb(); */ ++ AuTraceErr(!valid); ++ return valid; ++} ++ ++int au_vdir_fill_de(struct file *file, struct dir_context *ctx) ++{ ++ unsigned int l, deblk_sz; ++ union au_vdir_deblk_p deblk_end; ++ struct au_vdir *vdir_cache; ++ struct au_vdir_de *de; ++ ++ vdir_cache = au_fvdir_cache(file); ++ if (!seek_vdir(file, ctx)) ++ return 0; ++ ++ deblk_sz = vdir_cache->vd_deblk_sz; ++ while (1) { ++ deblk_end.deblk = vdir_cache->vd_deblk[vdir_cache->vd_last.ul]; ++ deblk_end.deblk += deblk_sz; ++ while (!is_deblk_end(&vdir_cache->vd_last.p, &deblk_end)) { ++ de = vdir_cache->vd_last.p.de; ++ AuDbg("%.*s, off%lld, i%lu, dt%d\n", ++ de->de_str.len, de->de_str.name, ctx->pos, ++ (unsigned long)de->de_ino, de->de_type); ++ if (unlikely(!dir_emit(ctx, de->de_str.name, ++ de->de_str.len, de->de_ino, ++ de->de_type))) { ++ /* todo: ignore the error caused by udba? */ ++ /* return err; */ ++ return 0; ++ } ++ ++ l = calc_size(de->de_str.len); ++ vdir_cache->vd_last.p.deblk += l; ++ ctx->pos += l; ++ } ++ if (vdir_cache->vd_last.ul < vdir_cache->vd_nblk - 1) { ++ vdir_cache->vd_last.ul++; ++ vdir_cache->vd_last.p.deblk ++ = vdir_cache->vd_deblk[vdir_cache->vd_last.ul]; ++ ctx->pos = deblk_sz * vdir_cache->vd_last.ul; ++ continue; ++ } ++ break; ++ } ++ ++ /* smp_mb(); */ ++ return 0; ++} +diff --git a/fs/aufs/vfsub.c b/fs/aufs/vfsub.c +new file mode 100644 +index 0000000..5fd008c +--- /dev/null ++++ b/fs/aufs/vfsub.c +@@ -0,0 +1,864 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * sub-routines for VFS ++ */ ++ ++#include ++#include ++#include ++#include ++#include "../fs/mount.h" ++#include "aufs.h" ++ ++#ifdef CONFIG_AUFS_BR_FUSE ++int vfsub_test_mntns(struct vfsmount *mnt, struct super_block *h_sb) ++{ ++ struct nsproxy *ns; ++ ++ if (!au_test_fuse(h_sb) || !au_userns) ++ return 0; ++ ++ ns = current->nsproxy; ++ /* no {get,put}_nsproxy(ns) */ ++ return real_mount(mnt)->mnt_ns == ns->mnt_ns ? 0 : -EACCES; ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++int vfsub_update_h_iattr(struct path *h_path, int *did) ++{ ++ int err; ++ struct kstat st; ++ struct super_block *h_sb; ++ ++ /* for remote fs, leave work for its getattr or d_revalidate */ ++ /* for bad i_attr fs, handle them in aufs_getattr() */ ++ /* still some fs may acquire i_mutex. we need to skip them */ ++ err = 0; ++ if (!did) ++ did = &err; ++ h_sb = h_path->dentry->d_sb; ++ *did = (!au_test_fs_remote(h_sb) && au_test_fs_refresh_iattr(h_sb)); ++ if (*did) ++ err = vfs_getattr(h_path, &st); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct file *vfsub_dentry_open(struct path *path, int flags) ++{ ++ struct file *file; ++ ++ file = dentry_open(path, flags /* | __FMODE_NONOTIFY */, ++ current_cred()); ++ if (!IS_ERR_OR_NULL(file) ++ && (file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) ++ i_readcount_inc(path->dentry->d_inode); ++ ++ return file; ++} ++ ++struct file *vfsub_filp_open(const char *path, int oflags, int mode) ++{ ++ struct file *file; ++ ++ lockdep_off(); ++ file = filp_open(path, ++ oflags /* | __FMODE_NONOTIFY */, ++ mode); ++ lockdep_on(); ++ if (IS_ERR(file)) ++ goto out; ++ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/ ++ ++out: ++ return file; ++} ++ ++/* ++ * Ideally this function should call VFS:do_last() in order to keep all its ++ * checkings. But it is very hard for aufs to regenerate several VFS internal ++ * structure such as nameidata. This is a second (or third) best approach. ++ * cf. linux/fs/namei.c:do_last(), lookup_open() and atomic_open(). ++ */ ++int vfsub_atomic_open(struct inode *dir, struct dentry *dentry, ++ struct vfsub_aopen_args *args, struct au_branch *br) ++{ ++ int err; ++ struct file *file = args->file; ++ /* copied from linux/fs/namei.c:atomic_open() */ ++ struct dentry *const DENTRY_NOT_SET = (void *)-1UL; ++ ++ IMustLock(dir); ++ AuDebugOn(!dir->i_op->atomic_open); ++ ++ err = au_br_test_oflag(args->open_flag, br); ++ if (unlikely(err)) ++ goto out; ++ ++ args->file->f_path.dentry = DENTRY_NOT_SET; ++ args->file->f_path.mnt = au_br_mnt(br); ++ err = dir->i_op->atomic_open(dir, dentry, file, args->open_flag, ++ args->create_mode, args->opened); ++ if (err >= 0) { ++ /* some filesystems don't set FILE_CREATED while succeeded? */ ++ if (*args->opened & FILE_CREATED) ++ fsnotify_create(dir, dentry); ++ } else ++ goto out; ++ ++ ++ if (!err) { ++ /* todo: call VFS:may_open() here */ ++ err = open_check_o_direct(file); ++ /* todo: ima_file_check() too? */ ++ if (!err && (args->open_flag & __FMODE_EXEC)) ++ err = deny_write_access(file); ++ if (unlikely(err)) ++ /* note that the file is created and still opened */ ++ goto out; ++ } ++ ++ atomic_inc(&br->br_count); ++ fsnotify_open(file); ++ ++out: ++ return err; ++} ++ ++int vfsub_kern_path(const char *name, unsigned int flags, struct path *path) ++{ ++ int err; ++ ++ err = kern_path(name, flags, path); ++ if (!err && path->dentry->d_inode) ++ vfsub_update_h_iattr(path, /*did*/NULL); /*ignore*/ ++ return err; ++} ++ ++struct dentry *vfsub_lookup_one_len(const char *name, struct dentry *parent, ++ int len) ++{ ++ struct path path = { ++ .mnt = NULL ++ }; ++ ++ /* VFS checks it too, but by WARN_ON_ONCE() */ ++ IMustLock(parent->d_inode); ++ ++ path.dentry = lookup_one_len(name, parent, len); ++ if (IS_ERR(path.dentry)) ++ goto out; ++ if (path.dentry->d_inode) ++ vfsub_update_h_iattr(&path, /*did*/NULL); /*ignore*/ ++ ++out: ++ AuTraceErrPtr(path.dentry); ++ return path.dentry; ++} ++ ++void vfsub_call_lkup_one(void *args) ++{ ++ struct vfsub_lkup_one_args *a = args; ++ *a->errp = vfsub_lkup_one(a->name, a->parent); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct dentry *vfsub_lock_rename(struct dentry *d1, struct au_hinode *hdir1, ++ struct dentry *d2, struct au_hinode *hdir2) ++{ ++ struct dentry *d; ++ ++ lockdep_off(); ++ d = lock_rename(d1, d2); ++ lockdep_on(); ++ au_hn_suspend(hdir1); ++ if (hdir1 != hdir2) ++ au_hn_suspend(hdir2); ++ ++ return d; ++} ++ ++void vfsub_unlock_rename(struct dentry *d1, struct au_hinode *hdir1, ++ struct dentry *d2, struct au_hinode *hdir2) ++{ ++ au_hn_resume(hdir1); ++ if (hdir1 != hdir2) ++ au_hn_resume(hdir2); ++ lockdep_off(); ++ unlock_rename(d1, d2); ++ lockdep_on(); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int vfsub_create(struct inode *dir, struct path *path, int mode, bool want_excl) ++{ ++ int err; ++ struct dentry *d; ++ ++ IMustLock(dir); ++ ++ d = path->dentry; ++ path->dentry = d->d_parent; ++ err = security_path_mknod(path, d, mode, 0); ++ path->dentry = d; ++ if (unlikely(err)) ++ goto out; ++ ++ lockdep_off(); ++ err = vfs_create(dir, path->dentry, mode, want_excl); ++ lockdep_on(); ++ if (!err) { ++ struct path tmp = *path; ++ int did; ++ ++ vfsub_update_h_iattr(&tmp, &did); ++ if (did) { ++ tmp.dentry = path->dentry->d_parent; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); ++ } ++ /*ignore*/ ++ } ++ ++out: ++ return err; ++} ++ ++int vfsub_symlink(struct inode *dir, struct path *path, const char *symname) ++{ ++ int err; ++ struct dentry *d; ++ ++ IMustLock(dir); ++ ++ d = path->dentry; ++ path->dentry = d->d_parent; ++ err = security_path_symlink(path, d, symname); ++ path->dentry = d; ++ if (unlikely(err)) ++ goto out; ++ ++ lockdep_off(); ++ err = vfs_symlink(dir, path->dentry, symname); ++ lockdep_on(); ++ if (!err) { ++ struct path tmp = *path; ++ int did; ++ ++ vfsub_update_h_iattr(&tmp, &did); ++ if (did) { ++ tmp.dentry = path->dentry->d_parent; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); ++ } ++ /*ignore*/ ++ } ++ ++out: ++ return err; ++} ++ ++int vfsub_mknod(struct inode *dir, struct path *path, int mode, dev_t dev) ++{ ++ int err; ++ struct dentry *d; ++ ++ IMustLock(dir); ++ ++ d = path->dentry; ++ path->dentry = d->d_parent; ++ err = security_path_mknod(path, d, mode, new_encode_dev(dev)); ++ path->dentry = d; ++ if (unlikely(err)) ++ goto out; ++ ++ lockdep_off(); ++ err = vfs_mknod(dir, path->dentry, mode, dev); ++ lockdep_on(); ++ if (!err) { ++ struct path tmp = *path; ++ int did; ++ ++ vfsub_update_h_iattr(&tmp, &did); ++ if (did) { ++ tmp.dentry = path->dentry->d_parent; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); ++ } ++ /*ignore*/ ++ } ++ ++out: ++ return err; ++} ++ ++static int au_test_nlink(struct inode *inode) ++{ ++ const unsigned int link_max = UINT_MAX >> 1; /* rough margin */ ++ ++ if (!au_test_fs_no_limit_nlink(inode->i_sb) ++ || inode->i_nlink < link_max) ++ return 0; ++ return -EMLINK; ++} ++ ++int vfsub_link(struct dentry *src_dentry, struct inode *dir, struct path *path, ++ struct inode **delegated_inode) ++{ ++ int err; ++ struct dentry *d; ++ ++ IMustLock(dir); ++ ++ err = au_test_nlink(src_dentry->d_inode); ++ if (unlikely(err)) ++ return err; ++ ++ /* we don't call may_linkat() */ ++ d = path->dentry; ++ path->dentry = d->d_parent; ++ err = security_path_link(src_dentry, path, d); ++ path->dentry = d; ++ if (unlikely(err)) ++ goto out; ++ ++ lockdep_off(); ++ err = vfs_link(src_dentry, dir, path->dentry, delegated_inode); ++ lockdep_on(); ++ if (!err) { ++ struct path tmp = *path; ++ int did; ++ ++ /* fuse has different memory inode for the same inumber */ ++ vfsub_update_h_iattr(&tmp, &did); ++ if (did) { ++ tmp.dentry = path->dentry->d_parent; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); ++ tmp.dentry = src_dentry; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); ++ } ++ /*ignore*/ ++ } ++ ++out: ++ return err; ++} ++ ++int vfsub_rename(struct inode *src_dir, struct dentry *src_dentry, ++ struct inode *dir, struct path *path, ++ struct inode **delegated_inode) ++{ ++ int err; ++ struct path tmp = { ++ .mnt = path->mnt ++ }; ++ struct dentry *d; ++ ++ IMustLock(dir); ++ IMustLock(src_dir); ++ ++ d = path->dentry; ++ path->dentry = d->d_parent; ++ tmp.dentry = src_dentry->d_parent; ++ err = security_path_rename(&tmp, src_dentry, path, d, /*flags*/0); ++ path->dentry = d; ++ if (unlikely(err)) ++ goto out; ++ ++ lockdep_off(); ++ err = vfs_rename(src_dir, src_dentry, dir, path->dentry, ++ delegated_inode, /*flags*/0); ++ lockdep_on(); ++ if (!err) { ++ int did; ++ ++ tmp.dentry = d->d_parent; ++ vfsub_update_h_iattr(&tmp, &did); ++ if (did) { ++ tmp.dentry = src_dentry; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); ++ tmp.dentry = src_dentry->d_parent; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); ++ } ++ /*ignore*/ ++ } ++ ++out: ++ return err; ++} ++ ++int vfsub_mkdir(struct inode *dir, struct path *path, int mode) ++{ ++ int err; ++ struct dentry *d; ++ ++ IMustLock(dir); ++ ++ d = path->dentry; ++ path->dentry = d->d_parent; ++ err = security_path_mkdir(path, d, mode); ++ path->dentry = d; ++ if (unlikely(err)) ++ goto out; ++ ++ lockdep_off(); ++ err = vfs_mkdir(dir, path->dentry, mode); ++ lockdep_on(); ++ if (!err) { ++ struct path tmp = *path; ++ int did; ++ ++ vfsub_update_h_iattr(&tmp, &did); ++ if (did) { ++ tmp.dentry = path->dentry->d_parent; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); ++ } ++ /*ignore*/ ++ } ++ ++out: ++ return err; ++} ++ ++int vfsub_rmdir(struct inode *dir, struct path *path) ++{ ++ int err; ++ struct dentry *d; ++ ++ IMustLock(dir); ++ ++ d = path->dentry; ++ path->dentry = d->d_parent; ++ err = security_path_rmdir(path, d); ++ path->dentry = d; ++ if (unlikely(err)) ++ goto out; ++ ++ lockdep_off(); ++ err = vfs_rmdir(dir, path->dentry); ++ lockdep_on(); ++ if (!err) { ++ struct path tmp = { ++ .dentry = path->dentry->d_parent, ++ .mnt = path->mnt ++ }; ++ ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); /*ignore*/ ++ } ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* todo: support mmap_sem? */ ++ssize_t vfsub_read_u(struct file *file, char __user *ubuf, size_t count, ++ loff_t *ppos) ++{ ++ ssize_t err; ++ ++ lockdep_off(); ++ err = vfs_read(file, ubuf, count, ppos); ++ lockdep_on(); ++ if (err >= 0) ++ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/ ++ return err; ++} ++ ++/* todo: kernel_read()? */ ++ssize_t vfsub_read_k(struct file *file, void *kbuf, size_t count, ++ loff_t *ppos) ++{ ++ ssize_t err; ++ mm_segment_t oldfs; ++ union { ++ void *k; ++ char __user *u; ++ } buf; ++ ++ buf.k = kbuf; ++ oldfs = get_fs(); ++ set_fs(KERNEL_DS); ++ err = vfsub_read_u(file, buf.u, count, ppos); ++ set_fs(oldfs); ++ return err; ++} ++ ++ssize_t vfsub_write_u(struct file *file, const char __user *ubuf, size_t count, ++ loff_t *ppos) ++{ ++ ssize_t err; ++ ++ lockdep_off(); ++ err = vfs_write(file, ubuf, count, ppos); ++ lockdep_on(); ++ if (err >= 0) ++ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/ ++ return err; ++} ++ ++ssize_t vfsub_write_k(struct file *file, void *kbuf, size_t count, loff_t *ppos) ++{ ++ ssize_t err; ++ mm_segment_t oldfs; ++ union { ++ void *k; ++ const char __user *u; ++ } buf; ++ ++ buf.k = kbuf; ++ oldfs = get_fs(); ++ set_fs(KERNEL_DS); ++ err = vfsub_write_u(file, buf.u, count, ppos); ++ set_fs(oldfs); ++ return err; ++} ++ ++int vfsub_flush(struct file *file, fl_owner_t id) ++{ ++ int err; ++ ++ err = 0; ++ if (file->f_op->flush) { ++ if (!au_test_nfs(file->f_dentry->d_sb)) ++ err = file->f_op->flush(file, id); ++ else { ++ lockdep_off(); ++ err = file->f_op->flush(file, id); ++ lockdep_on(); ++ } ++ if (!err) ++ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); ++ /*ignore*/ ++ } ++ return err; ++} ++ ++int vfsub_iterate_dir(struct file *file, struct dir_context *ctx) ++{ ++ int err; ++ ++ AuDbg("%pD, ctx{%pf, %llu}\n", file, ctx->actor, ctx->pos); ++ ++ lockdep_off(); ++ err = iterate_dir(file, ctx); ++ lockdep_on(); ++ if (err >= 0) ++ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/ ++ return err; ++} ++ ++long vfsub_splice_to(struct file *in, loff_t *ppos, ++ struct pipe_inode_info *pipe, size_t len, ++ unsigned int flags) ++{ ++ long err; ++ ++ lockdep_off(); ++ err = do_splice_to(in, ppos, pipe, len, flags); ++ lockdep_on(); ++ file_accessed(in); ++ if (err >= 0) ++ vfsub_update_h_iattr(&in->f_path, /*did*/NULL); /*ignore*/ ++ return err; ++} ++ ++long vfsub_splice_from(struct pipe_inode_info *pipe, struct file *out, ++ loff_t *ppos, size_t len, unsigned int flags) ++{ ++ long err; ++ ++ lockdep_off(); ++ err = do_splice_from(pipe, out, ppos, len, flags); ++ lockdep_on(); ++ if (err >= 0) ++ vfsub_update_h_iattr(&out->f_path, /*did*/NULL); /*ignore*/ ++ return err; ++} ++ ++int vfsub_fsync(struct file *file, struct path *path, int datasync) ++{ ++ int err; ++ ++ /* file can be NULL */ ++ lockdep_off(); ++ err = vfs_fsync(file, datasync); ++ lockdep_on(); ++ if (!err) { ++ if (!path) { ++ AuDebugOn(!file); ++ path = &file->f_path; ++ } ++ vfsub_update_h_iattr(path, /*did*/NULL); /*ignore*/ ++ } ++ return err; ++} ++ ++/* cf. open.c:do_sys_truncate() and do_sys_ftruncate() */ ++int vfsub_trunc(struct path *h_path, loff_t length, unsigned int attr, ++ struct file *h_file) ++{ ++ int err; ++ struct inode *h_inode; ++ struct super_block *h_sb; ++ ++ if (!h_file) { ++ err = vfsub_truncate(h_path, length); ++ goto out; ++ } ++ ++ h_inode = h_path->dentry->d_inode; ++ h_sb = h_inode->i_sb; ++ lockdep_off(); ++ sb_start_write(h_sb); ++ lockdep_on(); ++ err = locks_verify_truncate(h_inode, h_file, length); ++ if (!err) ++ err = security_path_truncate(h_path); ++ if (!err) { ++ lockdep_off(); ++ err = do_truncate(h_path->dentry, length, attr, h_file); ++ lockdep_on(); ++ } ++ lockdep_off(); ++ sb_end_write(h_sb); ++ lockdep_on(); ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_vfsub_mkdir_args { ++ int *errp; ++ struct inode *dir; ++ struct path *path; ++ int mode; ++}; ++ ++static void au_call_vfsub_mkdir(void *args) ++{ ++ struct au_vfsub_mkdir_args *a = args; ++ *a->errp = vfsub_mkdir(a->dir, a->path, a->mode); ++} ++ ++int vfsub_sio_mkdir(struct inode *dir, struct path *path, int mode) ++{ ++ int err, do_sio, wkq_err; ++ ++ do_sio = au_test_h_perm_sio(dir, MAY_EXEC | MAY_WRITE); ++ if (!do_sio) { ++ lockdep_off(); ++ err = vfsub_mkdir(dir, path, mode); ++ lockdep_on(); ++ } else { ++ struct au_vfsub_mkdir_args args = { ++ .errp = &err, ++ .dir = dir, ++ .path = path, ++ .mode = mode ++ }; ++ wkq_err = au_wkq_wait(au_call_vfsub_mkdir, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ ++ return err; ++} ++ ++struct au_vfsub_rmdir_args { ++ int *errp; ++ struct inode *dir; ++ struct path *path; ++}; ++ ++static void au_call_vfsub_rmdir(void *args) ++{ ++ struct au_vfsub_rmdir_args *a = args; ++ *a->errp = vfsub_rmdir(a->dir, a->path); ++} ++ ++int vfsub_sio_rmdir(struct inode *dir, struct path *path) ++{ ++ int err, do_sio, wkq_err; ++ ++ do_sio = au_test_h_perm_sio(dir, MAY_EXEC | MAY_WRITE); ++ if (!do_sio) { ++ lockdep_off(); ++ err = vfsub_rmdir(dir, path); ++ lockdep_on(); ++ } else { ++ struct au_vfsub_rmdir_args args = { ++ .errp = &err, ++ .dir = dir, ++ .path = path ++ }; ++ wkq_err = au_wkq_wait(au_call_vfsub_rmdir, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct notify_change_args { ++ int *errp; ++ struct path *path; ++ struct iattr *ia; ++ struct inode **delegated_inode; ++}; ++ ++static void call_notify_change(void *args) ++{ ++ struct notify_change_args *a = args; ++ struct inode *h_inode; ++ ++ h_inode = a->path->dentry->d_inode; ++ IMustLock(h_inode); ++ ++ *a->errp = -EPERM; ++ if (!IS_IMMUTABLE(h_inode) && !IS_APPEND(h_inode)) { ++ lockdep_off(); ++ *a->errp = notify_change(a->path->dentry, a->ia, ++ a->delegated_inode); ++ lockdep_on(); ++ if (!*a->errp) ++ vfsub_update_h_iattr(a->path, /*did*/NULL); /*ignore*/ ++ } ++ AuTraceErr(*a->errp); ++} ++ ++int vfsub_notify_change(struct path *path, struct iattr *ia, ++ struct inode **delegated_inode) ++{ ++ int err; ++ struct notify_change_args args = { ++ .errp = &err, ++ .path = path, ++ .ia = ia, ++ .delegated_inode = delegated_inode ++ }; ++ ++ call_notify_change(&args); ++ ++ return err; ++} ++ ++int vfsub_sio_notify_change(struct path *path, struct iattr *ia, ++ struct inode **delegated_inode) ++{ ++ int err, wkq_err; ++ struct notify_change_args args = { ++ .errp = &err, ++ .path = path, ++ .ia = ia, ++ .delegated_inode = delegated_inode ++ }; ++ ++ wkq_err = au_wkq_wait(call_notify_change, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct unlink_args { ++ int *errp; ++ struct inode *dir; ++ struct path *path; ++ struct inode **delegated_inode; ++}; ++ ++static void call_unlink(void *args) ++{ ++ struct unlink_args *a = args; ++ struct dentry *d = a->path->dentry; ++ struct inode *h_inode; ++ const int stop_sillyrename = (au_test_nfs(d->d_sb) ++ && au_dcount(d) == 1); ++ ++ IMustLock(a->dir); ++ ++ a->path->dentry = d->d_parent; ++ *a->errp = security_path_unlink(a->path, d); ++ a->path->dentry = d; ++ if (unlikely(*a->errp)) ++ return; ++ ++ if (!stop_sillyrename) ++ dget(d); ++ h_inode = d->d_inode; ++ if (h_inode) ++ ihold(h_inode); ++ ++ lockdep_off(); ++ *a->errp = vfs_unlink(a->dir, d, a->delegated_inode); ++ lockdep_on(); ++ if (!*a->errp) { ++ struct path tmp = { ++ .dentry = d->d_parent, ++ .mnt = a->path->mnt ++ }; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); /*ignore*/ ++ } ++ ++ if (!stop_sillyrename) ++ dput(d); ++ if (h_inode) ++ iput(h_inode); ++ ++ AuTraceErr(*a->errp); ++} ++ ++/* ++ * @dir: must be locked. ++ * @dentry: target dentry. ++ */ ++int vfsub_unlink(struct inode *dir, struct path *path, ++ struct inode **delegated_inode, int force) ++{ ++ int err; ++ struct unlink_args args = { ++ .errp = &err, ++ .dir = dir, ++ .path = path, ++ .delegated_inode = delegated_inode ++ }; ++ ++ if (!force) ++ call_unlink(&args); ++ else { ++ int wkq_err; ++ ++ wkq_err = au_wkq_wait(call_unlink, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ ++ return err; ++} +diff --git a/fs/aufs/vfsub.h b/fs/aufs/vfsub.h +new file mode 100644 +index 0000000..2c33298 +--- /dev/null ++++ b/fs/aufs/vfsub.h +@@ -0,0 +1,315 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * sub-routines for VFS ++ */ ++ ++#ifndef __AUFS_VFSUB_H__ ++#define __AUFS_VFSUB_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++#include ++#include "debug.h" ++ ++/* copied from linux/fs/internal.h */ ++/* todo: BAD approach!! */ ++extern void __mnt_drop_write(struct vfsmount *); ++extern spinlock_t inode_sb_list_lock; ++extern int open_check_o_direct(struct file *f); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* lock subclass for lower inode */ ++/* default MAX_LOCKDEP_SUBCLASSES(8) is not enough */ ++/* reduce? gave up. */ ++enum { ++ AuLsc_I_Begin = I_MUTEX_PARENT2, /* 5 */ ++ AuLsc_I_PARENT, /* lower inode, parent first */ ++ AuLsc_I_PARENT2, /* copyup dirs */ ++ AuLsc_I_PARENT3, /* copyup wh */ ++ AuLsc_I_CHILD, ++ AuLsc_I_CHILD2, ++ AuLsc_I_End ++}; ++ ++/* to debug easier, do not make them inlined functions */ ++#define MtxMustLock(mtx) AuDebugOn(!mutex_is_locked(mtx)) ++#define IMustLock(i) MtxMustLock(&(i)->i_mutex) ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline void vfsub_drop_nlink(struct inode *inode) ++{ ++ AuDebugOn(!inode->i_nlink); ++ drop_nlink(inode); ++} ++ ++static inline void vfsub_dead_dir(struct inode *inode) ++{ ++ AuDebugOn(!S_ISDIR(inode->i_mode)); ++ inode->i_flags |= S_DEAD; ++ clear_nlink(inode); ++} ++ ++static inline int vfsub_native_ro(struct inode *inode) ++{ ++ return (inode->i_sb->s_flags & MS_RDONLY) ++ || IS_RDONLY(inode) ++ /* || IS_APPEND(inode) */ ++ || IS_IMMUTABLE(inode); ++} ++ ++#ifdef CONFIG_AUFS_BR_FUSE ++int vfsub_test_mntns(struct vfsmount *mnt, struct super_block *h_sb); ++#else ++AuStubInt0(vfsub_test_mntns, struct vfsmount *mnt, struct super_block *h_sb); ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++int vfsub_update_h_iattr(struct path *h_path, int *did); ++struct file *vfsub_dentry_open(struct path *path, int flags); ++struct file *vfsub_filp_open(const char *path, int oflags, int mode); ++struct vfsub_aopen_args { ++ struct file *file; ++ unsigned int open_flag; ++ umode_t create_mode; ++ int *opened; ++}; ++struct au_branch; ++int vfsub_atomic_open(struct inode *dir, struct dentry *dentry, ++ struct vfsub_aopen_args *args, struct au_branch *br); ++int vfsub_kern_path(const char *name, unsigned int flags, struct path *path); ++ ++struct dentry *vfsub_lookup_one_len(const char *name, struct dentry *parent, ++ int len); ++ ++struct vfsub_lkup_one_args { ++ struct dentry **errp; ++ struct qstr *name; ++ struct dentry *parent; ++}; ++ ++static inline struct dentry *vfsub_lkup_one(struct qstr *name, ++ struct dentry *parent) ++{ ++ return vfsub_lookup_one_len(name->name, parent, name->len); ++} ++ ++void vfsub_call_lkup_one(void *args); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline int vfsub_mnt_want_write(struct vfsmount *mnt) ++{ ++ int err; ++ ++ lockdep_off(); ++ err = mnt_want_write(mnt); ++ lockdep_on(); ++ return err; ++} ++ ++static inline void vfsub_mnt_drop_write(struct vfsmount *mnt) ++{ ++ lockdep_off(); ++ mnt_drop_write(mnt); ++ lockdep_on(); ++} ++ ++#if 0 /* reserved */ ++static inline void vfsub_mnt_drop_write_file(struct file *file) ++{ ++ lockdep_off(); ++ mnt_drop_write_file(file); ++ lockdep_on(); ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_hinode; ++struct dentry *vfsub_lock_rename(struct dentry *d1, struct au_hinode *hdir1, ++ struct dentry *d2, struct au_hinode *hdir2); ++void vfsub_unlock_rename(struct dentry *d1, struct au_hinode *hdir1, ++ struct dentry *d2, struct au_hinode *hdir2); ++ ++int vfsub_create(struct inode *dir, struct path *path, int mode, ++ bool want_excl); ++int vfsub_symlink(struct inode *dir, struct path *path, ++ const char *symname); ++int vfsub_mknod(struct inode *dir, struct path *path, int mode, dev_t dev); ++int vfsub_link(struct dentry *src_dentry, struct inode *dir, ++ struct path *path, struct inode **delegated_inode); ++int vfsub_rename(struct inode *src_hdir, struct dentry *src_dentry, ++ struct inode *hdir, struct path *path, ++ struct inode **delegated_inode); ++int vfsub_mkdir(struct inode *dir, struct path *path, int mode); ++int vfsub_rmdir(struct inode *dir, struct path *path); ++ ++/* ---------------------------------------------------------------------- */ ++ ++ssize_t vfsub_read_u(struct file *file, char __user *ubuf, size_t count, ++ loff_t *ppos); ++ssize_t vfsub_read_k(struct file *file, void *kbuf, size_t count, ++ loff_t *ppos); ++ssize_t vfsub_write_u(struct file *file, const char __user *ubuf, size_t count, ++ loff_t *ppos); ++ssize_t vfsub_write_k(struct file *file, void *kbuf, size_t count, ++ loff_t *ppos); ++int vfsub_flush(struct file *file, fl_owner_t id); ++int vfsub_iterate_dir(struct file *file, struct dir_context *ctx); ++ ++/* just for type-check */ ++static inline filldir_t au_diractor(int (*func)(struct dir_context *, ++ const char *, int, loff_t, u64, ++ unsigned)) ++{ ++ return (filldir_t)func; ++} ++ ++static inline loff_t vfsub_f_size_read(struct file *file) ++{ ++ return i_size_read(file_inode(file)); ++} ++ ++static inline unsigned int vfsub_file_flags(struct file *file) ++{ ++ unsigned int flags; ++ ++ spin_lock(&file->f_lock); ++ flags = file->f_flags; ++ spin_unlock(&file->f_lock); ++ ++ return flags; ++} ++ ++#if 0 /* reserved */ ++static inline void vfsub_file_accessed(struct file *h_file) ++{ ++ file_accessed(h_file); ++ vfsub_update_h_iattr(&h_file->f_path, /*did*/NULL); /*ignore*/ ++} ++#endif ++ ++static inline void vfsub_touch_atime(struct vfsmount *h_mnt, ++ struct dentry *h_dentry) ++{ ++ struct path h_path = { ++ .dentry = h_dentry, ++ .mnt = h_mnt ++ }; ++ touch_atime(&h_path); ++ vfsub_update_h_iattr(&h_path, /*did*/NULL); /*ignore*/ ++} ++ ++static inline int vfsub_update_time(struct inode *h_inode, struct timespec *ts, ++ int flags) ++{ ++ return update_time(h_inode, ts, flags); ++ /* no vfsub_update_h_iattr() since we don't have struct path */ ++} ++ ++#ifdef CONFIG_FS_POSIX_ACL ++static inline int vfsub_acl_chmod(struct inode *h_inode, umode_t h_mode) ++{ ++ int err; ++ ++ err = posix_acl_chmod(h_inode, h_mode); ++ if (err == -EOPNOTSUPP) ++ err = 0; ++ return err; ++} ++#else ++AuStubInt0(vfsub_acl_chmod, struct inode *h_inode, umode_t h_mode); ++#endif ++ ++long vfsub_splice_to(struct file *in, loff_t *ppos, ++ struct pipe_inode_info *pipe, size_t len, ++ unsigned int flags); ++long vfsub_splice_from(struct pipe_inode_info *pipe, struct file *out, ++ loff_t *ppos, size_t len, unsigned int flags); ++ ++static inline long vfsub_truncate(struct path *path, loff_t length) ++{ ++ long err; ++ ++ lockdep_off(); ++ err = vfs_truncate(path, length); ++ lockdep_on(); ++ return err; ++} ++ ++int vfsub_trunc(struct path *h_path, loff_t length, unsigned int attr, ++ struct file *h_file); ++int vfsub_fsync(struct file *file, struct path *path, int datasync); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline loff_t vfsub_llseek(struct file *file, loff_t offset, int origin) ++{ ++ loff_t err; ++ ++ lockdep_off(); ++ err = vfs_llseek(file, offset, origin); ++ lockdep_on(); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int vfsub_sio_mkdir(struct inode *dir, struct path *path, int mode); ++int vfsub_sio_rmdir(struct inode *dir, struct path *path); ++int vfsub_sio_notify_change(struct path *path, struct iattr *ia, ++ struct inode **delegated_inode); ++int vfsub_notify_change(struct path *path, struct iattr *ia, ++ struct inode **delegated_inode); ++int vfsub_unlink(struct inode *dir, struct path *path, ++ struct inode **delegated_inode, int force); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline int vfsub_setxattr(struct dentry *dentry, const char *name, ++ const void *value, size_t size, int flags) ++{ ++ int err; ++ ++ lockdep_off(); ++ err = vfs_setxattr(dentry, name, value, size, flags); ++ lockdep_on(); ++ ++ return err; ++} ++ ++static inline int vfsub_removexattr(struct dentry *dentry, const char *name) ++{ ++ int err; ++ ++ lockdep_off(); ++ err = vfs_removexattr(dentry, name); ++ lockdep_on(); ++ ++ return err; ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_VFSUB_H__ */ +diff --git a/fs/aufs/wbr_policy.c b/fs/aufs/wbr_policy.c +new file mode 100644 +index 0000000..64cd9fe +--- /dev/null ++++ b/fs/aufs/wbr_policy.c +@@ -0,0 +1,765 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * policies for selecting one among multiple writable branches ++ */ ++ ++#include ++#include "aufs.h" ++ ++/* subset of cpup_attr() */ ++static noinline_for_stack ++int au_cpdown_attr(struct path *h_path, struct dentry *h_src) ++{ ++ int err, sbits; ++ struct iattr ia; ++ struct inode *h_isrc; ++ ++ h_isrc = h_src->d_inode; ++ ia.ia_valid = ATTR_FORCE | ATTR_MODE | ATTR_UID | ATTR_GID; ++ ia.ia_mode = h_isrc->i_mode; ++ ia.ia_uid = h_isrc->i_uid; ++ ia.ia_gid = h_isrc->i_gid; ++ sbits = !!(ia.ia_mode & (S_ISUID | S_ISGID)); ++ au_cpup_attr_flags(h_path->dentry->d_inode, h_isrc->i_flags); ++ /* no delegation since it is just created */ ++ err = vfsub_sio_notify_change(h_path, &ia, /*delegated*/NULL); ++ ++ /* is this nfs only? */ ++ if (!err && sbits && au_test_nfs(h_path->dentry->d_sb)) { ++ ia.ia_valid = ATTR_FORCE | ATTR_MODE; ++ ia.ia_mode = h_isrc->i_mode; ++ err = vfsub_sio_notify_change(h_path, &ia, /*delegated*/NULL); ++ } ++ ++ return err; ++} ++ ++#define AuCpdown_PARENT_OPQ 1 ++#define AuCpdown_WHED (1 << 1) ++#define AuCpdown_MADE_DIR (1 << 2) ++#define AuCpdown_DIROPQ (1 << 3) ++#define au_ftest_cpdown(flags, name) ((flags) & AuCpdown_##name) ++#define au_fset_cpdown(flags, name) \ ++ do { (flags) |= AuCpdown_##name; } while (0) ++#define au_fclr_cpdown(flags, name) \ ++ do { (flags) &= ~AuCpdown_##name; } while (0) ++ ++static int au_cpdown_dir_opq(struct dentry *dentry, aufs_bindex_t bdst, ++ unsigned int *flags) ++{ ++ int err; ++ struct dentry *opq_dentry; ++ ++ opq_dentry = au_diropq_create(dentry, bdst); ++ err = PTR_ERR(opq_dentry); ++ if (IS_ERR(opq_dentry)) ++ goto out; ++ dput(opq_dentry); ++ au_fset_cpdown(*flags, DIROPQ); ++ ++out: ++ return err; ++} ++ ++static int au_cpdown_dir_wh(struct dentry *dentry, struct dentry *h_parent, ++ struct inode *dir, aufs_bindex_t bdst) ++{ ++ int err; ++ struct path h_path; ++ struct au_branch *br; ++ ++ br = au_sbr(dentry->d_sb, bdst); ++ h_path.dentry = au_wh_lkup(h_parent, &dentry->d_name, br); ++ err = PTR_ERR(h_path.dentry); ++ if (IS_ERR(h_path.dentry)) ++ goto out; ++ ++ err = 0; ++ if (h_path.dentry->d_inode) { ++ h_path.mnt = au_br_mnt(br); ++ err = au_wh_unlink_dentry(au_h_iptr(dir, bdst), &h_path, ++ dentry); ++ } ++ dput(h_path.dentry); ++ ++out: ++ return err; ++} ++ ++static int au_cpdown_dir(struct dentry *dentry, aufs_bindex_t bdst, ++ struct au_pin *pin, ++ struct dentry *h_parent, void *arg) ++{ ++ int err, rerr; ++ aufs_bindex_t bopq, bstart; ++ struct path h_path; ++ struct dentry *parent; ++ struct inode *h_dir, *h_inode, *inode, *dir; ++ unsigned int *flags = arg; ++ ++ bstart = au_dbstart(dentry); ++ /* dentry is di-locked */ ++ parent = dget_parent(dentry); ++ dir = parent->d_inode; ++ h_dir = h_parent->d_inode; ++ AuDebugOn(h_dir != au_h_iptr(dir, bdst)); ++ IMustLock(h_dir); ++ ++ err = au_lkup_neg(dentry, bdst, /*wh*/0); ++ if (unlikely(err < 0)) ++ goto out; ++ h_path.dentry = au_h_dptr(dentry, bdst); ++ h_path.mnt = au_sbr_mnt(dentry->d_sb, bdst); ++ err = vfsub_sio_mkdir(au_h_iptr(dir, bdst), &h_path, ++ S_IRWXU | S_IRUGO | S_IXUGO); ++ if (unlikely(err)) ++ goto out_put; ++ au_fset_cpdown(*flags, MADE_DIR); ++ ++ bopq = au_dbdiropq(dentry); ++ au_fclr_cpdown(*flags, WHED); ++ au_fclr_cpdown(*flags, DIROPQ); ++ if (au_dbwh(dentry) == bdst) ++ au_fset_cpdown(*flags, WHED); ++ if (!au_ftest_cpdown(*flags, PARENT_OPQ) && bopq <= bdst) ++ au_fset_cpdown(*flags, PARENT_OPQ); ++ h_inode = h_path.dentry->d_inode; ++ mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD); ++ if (au_ftest_cpdown(*flags, WHED)) { ++ err = au_cpdown_dir_opq(dentry, bdst, flags); ++ if (unlikely(err)) { ++ mutex_unlock(&h_inode->i_mutex); ++ goto out_dir; ++ } ++ } ++ ++ err = au_cpdown_attr(&h_path, au_h_dptr(dentry, bstart)); ++ mutex_unlock(&h_inode->i_mutex); ++ if (unlikely(err)) ++ goto out_opq; ++ ++ if (au_ftest_cpdown(*flags, WHED)) { ++ err = au_cpdown_dir_wh(dentry, h_parent, dir, bdst); ++ if (unlikely(err)) ++ goto out_opq; ++ } ++ ++ inode = dentry->d_inode; ++ if (au_ibend(inode) < bdst) ++ au_set_ibend(inode, bdst); ++ au_set_h_iptr(inode, bdst, au_igrab(h_inode), ++ au_hi_flags(inode, /*isdir*/1)); ++ au_fhsm_wrote(dentry->d_sb, bdst, /*force*/0); ++ goto out; /* success */ ++ ++ /* revert */ ++out_opq: ++ if (au_ftest_cpdown(*flags, DIROPQ)) { ++ mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD); ++ rerr = au_diropq_remove(dentry, bdst); ++ mutex_unlock(&h_inode->i_mutex); ++ if (unlikely(rerr)) { ++ AuIOErr("failed removing diropq for %pd b%d (%d)\n", ++ dentry, bdst, rerr); ++ err = -EIO; ++ goto out; ++ } ++ } ++out_dir: ++ if (au_ftest_cpdown(*flags, MADE_DIR)) { ++ rerr = vfsub_sio_rmdir(au_h_iptr(dir, bdst), &h_path); ++ if (unlikely(rerr)) { ++ AuIOErr("failed removing %pd b%d (%d)\n", ++ dentry, bdst, rerr); ++ err = -EIO; ++ } ++ } ++out_put: ++ au_set_h_dptr(dentry, bdst, NULL); ++ if (au_dbend(dentry) == bdst) ++ au_update_dbend(dentry); ++out: ++ dput(parent); ++ return err; ++} ++ ++int au_cpdown_dirs(struct dentry *dentry, aufs_bindex_t bdst) ++{ ++ int err; ++ unsigned int flags; ++ ++ flags = 0; ++ err = au_cp_dirs(dentry, bdst, au_cpdown_dir, &flags); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* policies for create */ ++ ++int au_wbr_nonopq(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ int err, i, j, ndentry; ++ aufs_bindex_t bopq; ++ struct au_dcsub_pages dpages; ++ struct au_dpage *dpage; ++ struct dentry **dentries, *parent, *d; ++ ++ err = au_dpages_init(&dpages, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ parent = dget_parent(dentry); ++ err = au_dcsub_pages_rev_aufs(&dpages, parent, /*do_include*/0); ++ if (unlikely(err)) ++ goto out_free; ++ ++ err = bindex; ++ for (i = 0; i < dpages.ndpage; i++) { ++ dpage = dpages.dpages + i; ++ dentries = dpage->dentries; ++ ndentry = dpage->ndentry; ++ for (j = 0; j < ndentry; j++) { ++ d = dentries[j]; ++ di_read_lock_parent2(d, !AuLock_IR); ++ bopq = au_dbdiropq(d); ++ di_read_unlock(d, !AuLock_IR); ++ if (bopq >= 0 && bopq < err) ++ err = bopq; ++ } ++ } ++ ++out_free: ++ dput(parent); ++ au_dpages_free(&dpages); ++out: ++ return err; ++} ++ ++static int au_wbr_bu(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ for (; bindex >= 0; bindex--) ++ if (!au_br_rdonly(au_sbr(sb, bindex))) ++ return bindex; ++ return -EROFS; ++} ++ ++/* top down parent */ ++static int au_wbr_create_tdp(struct dentry *dentry, ++ unsigned int flags __maybe_unused) ++{ ++ int err; ++ aufs_bindex_t bstart, bindex; ++ struct super_block *sb; ++ struct dentry *parent, *h_parent; ++ ++ sb = dentry->d_sb; ++ bstart = au_dbstart(dentry); ++ err = bstart; ++ if (!au_br_rdonly(au_sbr(sb, bstart))) ++ goto out; ++ ++ err = -EROFS; ++ parent = dget_parent(dentry); ++ for (bindex = au_dbstart(parent); bindex < bstart; bindex++) { ++ h_parent = au_h_dptr(parent, bindex); ++ if (!h_parent || !h_parent->d_inode) ++ continue; ++ ++ if (!au_br_rdonly(au_sbr(sb, bindex))) { ++ err = bindex; ++ break; ++ } ++ } ++ dput(parent); ++ ++ /* bottom up here */ ++ if (unlikely(err < 0)) { ++ err = au_wbr_bu(sb, bstart - 1); ++ if (err >= 0) ++ err = au_wbr_nonopq(dentry, err); ++ } ++ ++out: ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* an exception for the policy other than tdp */ ++static int au_wbr_create_exp(struct dentry *dentry) ++{ ++ int err; ++ aufs_bindex_t bwh, bdiropq; ++ struct dentry *parent; ++ ++ err = -1; ++ bwh = au_dbwh(dentry); ++ parent = dget_parent(dentry); ++ bdiropq = au_dbdiropq(parent); ++ if (bwh >= 0) { ++ if (bdiropq >= 0) ++ err = min(bdiropq, bwh); ++ else ++ err = bwh; ++ AuDbg("%d\n", err); ++ } else if (bdiropq >= 0) { ++ err = bdiropq; ++ AuDbg("%d\n", err); ++ } ++ dput(parent); ++ ++ if (err >= 0) ++ err = au_wbr_nonopq(dentry, err); ++ ++ if (err >= 0 && au_br_rdonly(au_sbr(dentry->d_sb, err))) ++ err = -1; ++ ++ AuDbg("%d\n", err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* round robin */ ++static int au_wbr_create_init_rr(struct super_block *sb) ++{ ++ int err; ++ ++ err = au_wbr_bu(sb, au_sbend(sb)); ++ atomic_set(&au_sbi(sb)->si_wbr_rr_next, -err); /* less important */ ++ /* smp_mb(); */ ++ ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++static int au_wbr_create_rr(struct dentry *dentry, unsigned int flags) ++{ ++ int err, nbr; ++ unsigned int u; ++ aufs_bindex_t bindex, bend; ++ struct super_block *sb; ++ atomic_t *next; ++ ++ err = au_wbr_create_exp(dentry); ++ if (err >= 0) ++ goto out; ++ ++ sb = dentry->d_sb; ++ next = &au_sbi(sb)->si_wbr_rr_next; ++ bend = au_sbend(sb); ++ nbr = bend + 1; ++ for (bindex = 0; bindex <= bend; bindex++) { ++ if (!au_ftest_wbr(flags, DIR)) { ++ err = atomic_dec_return(next) + 1; ++ /* modulo for 0 is meaningless */ ++ if (unlikely(!err)) ++ err = atomic_dec_return(next) + 1; ++ } else ++ err = atomic_read(next); ++ AuDbg("%d\n", err); ++ u = err; ++ err = u % nbr; ++ AuDbg("%d\n", err); ++ if (!au_br_rdonly(au_sbr(sb, err))) ++ break; ++ err = -EROFS; ++ } ++ ++ if (err >= 0) ++ err = au_wbr_nonopq(dentry, err); ++ ++out: ++ AuDbg("%d\n", err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* most free space */ ++static void au_mfs(struct dentry *dentry, struct dentry *parent) ++{ ++ struct super_block *sb; ++ struct au_branch *br; ++ struct au_wbr_mfs *mfs; ++ struct dentry *h_parent; ++ aufs_bindex_t bindex, bend; ++ int err; ++ unsigned long long b, bavail; ++ struct path h_path; ++ /* reduce the stack usage */ ++ struct kstatfs *st; ++ ++ st = kmalloc(sizeof(*st), GFP_NOFS); ++ if (unlikely(!st)) { ++ AuWarn1("failed updating mfs(%d), ignored\n", -ENOMEM); ++ return; ++ } ++ ++ bavail = 0; ++ sb = dentry->d_sb; ++ mfs = &au_sbi(sb)->si_wbr_mfs; ++ MtxMustLock(&mfs->mfs_lock); ++ mfs->mfs_bindex = -EROFS; ++ mfs->mfsrr_bytes = 0; ++ if (!parent) { ++ bindex = 0; ++ bend = au_sbend(sb); ++ } else { ++ bindex = au_dbstart(parent); ++ bend = au_dbtaildir(parent); ++ } ++ ++ for (; bindex <= bend; bindex++) { ++ if (parent) { ++ h_parent = au_h_dptr(parent, bindex); ++ if (!h_parent || !h_parent->d_inode) ++ continue; ++ } ++ br = au_sbr(sb, bindex); ++ if (au_br_rdonly(br)) ++ continue; ++ ++ /* sb->s_root for NFS is unreliable */ ++ h_path.mnt = au_br_mnt(br); ++ h_path.dentry = h_path.mnt->mnt_root; ++ err = vfs_statfs(&h_path, st); ++ if (unlikely(err)) { ++ AuWarn1("failed statfs, b%d, %d\n", bindex, err); ++ continue; ++ } ++ ++ /* when the available size is equal, select the lower one */ ++ BUILD_BUG_ON(sizeof(b) < sizeof(st->f_bavail) ++ || sizeof(b) < sizeof(st->f_bsize)); ++ b = st->f_bavail * st->f_bsize; ++ br->br_wbr->wbr_bytes = b; ++ if (b >= bavail) { ++ bavail = b; ++ mfs->mfs_bindex = bindex; ++ mfs->mfs_jiffy = jiffies; ++ } ++ } ++ ++ mfs->mfsrr_bytes = bavail; ++ AuDbg("b%d\n", mfs->mfs_bindex); ++ kfree(st); ++} ++ ++static int au_wbr_create_mfs(struct dentry *dentry, unsigned int flags) ++{ ++ int err; ++ struct dentry *parent; ++ struct super_block *sb; ++ struct au_wbr_mfs *mfs; ++ ++ err = au_wbr_create_exp(dentry); ++ if (err >= 0) ++ goto out; ++ ++ sb = dentry->d_sb; ++ parent = NULL; ++ if (au_ftest_wbr(flags, PARENT)) ++ parent = dget_parent(dentry); ++ mfs = &au_sbi(sb)->si_wbr_mfs; ++ mutex_lock(&mfs->mfs_lock); ++ if (time_after(jiffies, mfs->mfs_jiffy + mfs->mfs_expire) ++ || mfs->mfs_bindex < 0 ++ || au_br_rdonly(au_sbr(sb, mfs->mfs_bindex))) ++ au_mfs(dentry, parent); ++ mutex_unlock(&mfs->mfs_lock); ++ err = mfs->mfs_bindex; ++ dput(parent); ++ ++ if (err >= 0) ++ err = au_wbr_nonopq(dentry, err); ++ ++out: ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++static int au_wbr_create_init_mfs(struct super_block *sb) ++{ ++ struct au_wbr_mfs *mfs; ++ ++ mfs = &au_sbi(sb)->si_wbr_mfs; ++ mutex_init(&mfs->mfs_lock); ++ mfs->mfs_jiffy = 0; ++ mfs->mfs_bindex = -EROFS; ++ ++ return 0; ++} ++ ++static int au_wbr_create_fin_mfs(struct super_block *sb __maybe_unused) ++{ ++ mutex_destroy(&au_sbi(sb)->si_wbr_mfs.mfs_lock); ++ return 0; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* most free space and then round robin */ ++static int au_wbr_create_mfsrr(struct dentry *dentry, unsigned int flags) ++{ ++ int err; ++ struct au_wbr_mfs *mfs; ++ ++ err = au_wbr_create_mfs(dentry, flags); ++ if (err >= 0) { ++ mfs = &au_sbi(dentry->d_sb)->si_wbr_mfs; ++ mutex_lock(&mfs->mfs_lock); ++ if (mfs->mfsrr_bytes < mfs->mfsrr_watermark) ++ err = au_wbr_create_rr(dentry, flags); ++ mutex_unlock(&mfs->mfs_lock); ++ } ++ ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++static int au_wbr_create_init_mfsrr(struct super_block *sb) ++{ ++ int err; ++ ++ au_wbr_create_init_mfs(sb); /* ignore */ ++ err = au_wbr_create_init_rr(sb); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* top down parent and most free space */ ++static int au_wbr_create_pmfs(struct dentry *dentry, unsigned int flags) ++{ ++ int err, e2; ++ unsigned long long b; ++ aufs_bindex_t bindex, bstart, bend; ++ struct super_block *sb; ++ struct dentry *parent, *h_parent; ++ struct au_branch *br; ++ ++ err = au_wbr_create_tdp(dentry, flags); ++ if (unlikely(err < 0)) ++ goto out; ++ parent = dget_parent(dentry); ++ bstart = au_dbstart(parent); ++ bend = au_dbtaildir(parent); ++ if (bstart == bend) ++ goto out_parent; /* success */ ++ ++ e2 = au_wbr_create_mfs(dentry, flags); ++ if (e2 < 0) ++ goto out_parent; /* success */ ++ ++ /* when the available size is equal, select upper one */ ++ sb = dentry->d_sb; ++ br = au_sbr(sb, err); ++ b = br->br_wbr->wbr_bytes; ++ AuDbg("b%d, %llu\n", err, b); ++ ++ for (bindex = bstart; bindex <= bend; bindex++) { ++ h_parent = au_h_dptr(parent, bindex); ++ if (!h_parent || !h_parent->d_inode) ++ continue; ++ ++ br = au_sbr(sb, bindex); ++ if (!au_br_rdonly(br) && br->br_wbr->wbr_bytes > b) { ++ b = br->br_wbr->wbr_bytes; ++ err = bindex; ++ AuDbg("b%d, %llu\n", err, b); ++ } ++ } ++ ++ if (err >= 0) ++ err = au_wbr_nonopq(dentry, err); ++ ++out_parent: ++ dput(parent); ++out: ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * - top down parent ++ * - most free space with parent ++ * - most free space round-robin regardless parent ++ */ ++static int au_wbr_create_pmfsrr(struct dentry *dentry, unsigned int flags) ++{ ++ int err; ++ unsigned long long watermark; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct au_wbr_mfs *mfs; ++ ++ err = au_wbr_create_pmfs(dentry, flags | AuWbr_PARENT); ++ if (unlikely(err < 0)) ++ goto out; ++ ++ sb = dentry->d_sb; ++ br = au_sbr(sb, err); ++ mfs = &au_sbi(sb)->si_wbr_mfs; ++ mutex_lock(&mfs->mfs_lock); ++ watermark = mfs->mfsrr_watermark; ++ mutex_unlock(&mfs->mfs_lock); ++ if (br->br_wbr->wbr_bytes < watermark) ++ /* regardless the parent dir */ ++ err = au_wbr_create_mfsrr(dentry, flags); ++ ++out: ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* policies for copyup */ ++ ++/* top down parent */ ++static int au_wbr_copyup_tdp(struct dentry *dentry) ++{ ++ return au_wbr_create_tdp(dentry, /*flags, anything is ok*/0); ++} ++ ++/* bottom up parent */ ++static int au_wbr_copyup_bup(struct dentry *dentry) ++{ ++ int err; ++ aufs_bindex_t bindex, bstart; ++ struct dentry *parent, *h_parent; ++ struct super_block *sb; ++ ++ err = -EROFS; ++ sb = dentry->d_sb; ++ parent = dget_parent(dentry); ++ bstart = au_dbstart(parent); ++ for (bindex = au_dbstart(dentry); bindex >= bstart; bindex--) { ++ h_parent = au_h_dptr(parent, bindex); ++ if (!h_parent || !h_parent->d_inode) ++ continue; ++ ++ if (!au_br_rdonly(au_sbr(sb, bindex))) { ++ err = bindex; ++ break; ++ } ++ } ++ dput(parent); ++ ++ /* bottom up here */ ++ if (unlikely(err < 0)) ++ err = au_wbr_bu(sb, bstart - 1); ++ ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++/* bottom up */ ++int au_wbr_do_copyup_bu(struct dentry *dentry, aufs_bindex_t bstart) ++{ ++ int err; ++ ++ err = au_wbr_bu(dentry->d_sb, bstart); ++ AuDbg("b%d\n", err); ++ if (err > bstart) ++ err = au_wbr_nonopq(dentry, err); ++ ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++static int au_wbr_copyup_bu(struct dentry *dentry) ++{ ++ int err; ++ aufs_bindex_t bstart; ++ ++ bstart = au_dbstart(dentry); ++ err = au_wbr_do_copyup_bu(dentry, bstart); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_wbr_copyup_operations au_wbr_copyup_ops[] = { ++ [AuWbrCopyup_TDP] = { ++ .copyup = au_wbr_copyup_tdp ++ }, ++ [AuWbrCopyup_BUP] = { ++ .copyup = au_wbr_copyup_bup ++ }, ++ [AuWbrCopyup_BU] = { ++ .copyup = au_wbr_copyup_bu ++ } ++}; ++ ++struct au_wbr_create_operations au_wbr_create_ops[] = { ++ [AuWbrCreate_TDP] = { ++ .create = au_wbr_create_tdp ++ }, ++ [AuWbrCreate_RR] = { ++ .create = au_wbr_create_rr, ++ .init = au_wbr_create_init_rr ++ }, ++ [AuWbrCreate_MFS] = { ++ .create = au_wbr_create_mfs, ++ .init = au_wbr_create_init_mfs, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_MFSV] = { ++ .create = au_wbr_create_mfs, ++ .init = au_wbr_create_init_mfs, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_MFSRR] = { ++ .create = au_wbr_create_mfsrr, ++ .init = au_wbr_create_init_mfsrr, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_MFSRRV] = { ++ .create = au_wbr_create_mfsrr, ++ .init = au_wbr_create_init_mfsrr, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_PMFS] = { ++ .create = au_wbr_create_pmfs, ++ .init = au_wbr_create_init_mfs, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_PMFSV] = { ++ .create = au_wbr_create_pmfs, ++ .init = au_wbr_create_init_mfs, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_PMFSRR] = { ++ .create = au_wbr_create_pmfsrr, ++ .init = au_wbr_create_init_mfsrr, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_PMFSRRV] = { ++ .create = au_wbr_create_pmfsrr, ++ .init = au_wbr_create_init_mfsrr, ++ .fin = au_wbr_create_fin_mfs ++ } ++}; +diff --git a/fs/aufs/whout.c b/fs/aufs/whout.c +new file mode 100644 +index 0000000..fb667ee +--- /dev/null ++++ b/fs/aufs/whout.c +@@ -0,0 +1,1061 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * whiteout for logical deletion and opaque directory ++ */ ++ ++#include "aufs.h" ++ ++#define WH_MASK S_IRUGO ++ ++/* ++ * If a directory contains this file, then it is opaque. We start with the ++ * .wh. flag so that it is blocked by lookup. ++ */ ++static struct qstr diropq_name = QSTR_INIT(AUFS_WH_DIROPQ, ++ sizeof(AUFS_WH_DIROPQ) - 1); ++ ++/* ++ * generate whiteout name, which is NOT terminated by NULL. ++ * @name: original d_name.name ++ * @len: original d_name.len ++ * @wh: whiteout qstr ++ * returns zero when succeeds, otherwise error. ++ * succeeded value as wh->name should be freed by kfree(). ++ */ ++int au_wh_name_alloc(struct qstr *wh, const struct qstr *name) ++{ ++ char *p; ++ ++ if (unlikely(name->len > PATH_MAX - AUFS_WH_PFX_LEN)) ++ return -ENAMETOOLONG; ++ ++ wh->len = name->len + AUFS_WH_PFX_LEN; ++ p = kmalloc(wh->len, GFP_NOFS); ++ wh->name = p; ++ if (p) { ++ memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN); ++ memcpy(p + AUFS_WH_PFX_LEN, name->name, name->len); ++ /* smp_mb(); */ ++ return 0; ++ } ++ return -ENOMEM; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * test if the @wh_name exists under @h_parent. ++ * @try_sio specifies the necessary of super-io. ++ */ ++int au_wh_test(struct dentry *h_parent, struct qstr *wh_name, int try_sio) ++{ ++ int err; ++ struct dentry *wh_dentry; ++ ++ if (!try_sio) ++ wh_dentry = vfsub_lkup_one(wh_name, h_parent); ++ else ++ wh_dentry = au_sio_lkup_one(wh_name, h_parent); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) { ++ if (err == -ENAMETOOLONG) ++ err = 0; ++ goto out; ++ } ++ ++ err = 0; ++ if (!wh_dentry->d_inode) ++ goto out_wh; /* success */ ++ ++ err = 1; ++ if (S_ISREG(wh_dentry->d_inode->i_mode)) ++ goto out_wh; /* success */ ++ ++ err = -EIO; ++ AuIOErr("%pd Invalid whiteout entry type 0%o.\n", ++ wh_dentry, wh_dentry->d_inode->i_mode); ++ ++out_wh: ++ dput(wh_dentry); ++out: ++ return err; ++} ++ ++/* ++ * test if the @h_dentry sets opaque or not. ++ */ ++int au_diropq_test(struct dentry *h_dentry) ++{ ++ int err; ++ struct inode *h_dir; ++ ++ h_dir = h_dentry->d_inode; ++ err = au_wh_test(h_dentry, &diropq_name, ++ au_test_h_perm_sio(h_dir, MAY_EXEC)); ++ return err; ++} ++ ++/* ++ * returns a negative dentry whose name is unique and temporary. ++ */ ++struct dentry *au_whtmp_lkup(struct dentry *h_parent, struct au_branch *br, ++ struct qstr *prefix) ++{ ++ struct dentry *dentry; ++ int i; ++ char defname[NAME_MAX - AUFS_MAX_NAMELEN + DNAME_INLINE_LEN + 1], ++ *name, *p; ++ /* strict atomic_t is unnecessary here */ ++ static unsigned short cnt; ++ struct qstr qs; ++ ++ BUILD_BUG_ON(sizeof(cnt) * 2 > AUFS_WH_TMP_LEN); ++ ++ name = defname; ++ qs.len = sizeof(defname) - DNAME_INLINE_LEN + prefix->len - 1; ++ if (unlikely(prefix->len > DNAME_INLINE_LEN)) { ++ dentry = ERR_PTR(-ENAMETOOLONG); ++ if (unlikely(qs.len > NAME_MAX)) ++ goto out; ++ dentry = ERR_PTR(-ENOMEM); ++ name = kmalloc(qs.len + 1, GFP_NOFS); ++ if (unlikely(!name)) ++ goto out; ++ } ++ ++ /* doubly whiteout-ed */ ++ memcpy(name, AUFS_WH_PFX AUFS_WH_PFX, AUFS_WH_PFX_LEN * 2); ++ p = name + AUFS_WH_PFX_LEN * 2; ++ memcpy(p, prefix->name, prefix->len); ++ p += prefix->len; ++ *p++ = '.'; ++ AuDebugOn(name + qs.len + 1 - p <= AUFS_WH_TMP_LEN); ++ ++ qs.name = name; ++ for (i = 0; i < 3; i++) { ++ sprintf(p, "%.*x", AUFS_WH_TMP_LEN, cnt++); ++ dentry = au_sio_lkup_one(&qs, h_parent); ++ if (IS_ERR(dentry) || !dentry->d_inode) ++ goto out_name; ++ dput(dentry); ++ } ++ /* pr_warn("could not get random name\n"); */ ++ dentry = ERR_PTR(-EEXIST); ++ AuDbg("%.*s\n", AuLNPair(&qs)); ++ BUG(); ++ ++out_name: ++ if (name != defname) ++ kfree(name); ++out: ++ AuTraceErrPtr(dentry); ++ return dentry; ++} ++ ++/* ++ * rename the @h_dentry on @br to the whiteouted temporary name. ++ */ ++int au_whtmp_ren(struct dentry *h_dentry, struct au_branch *br) ++{ ++ int err; ++ struct path h_path = { ++ .mnt = au_br_mnt(br) ++ }; ++ struct inode *h_dir, *delegated; ++ struct dentry *h_parent; ++ ++ h_parent = h_dentry->d_parent; /* dir inode is locked */ ++ h_dir = h_parent->d_inode; ++ IMustLock(h_dir); ++ ++ h_path.dentry = au_whtmp_lkup(h_parent, br, &h_dentry->d_name); ++ err = PTR_ERR(h_path.dentry); ++ if (IS_ERR(h_path.dentry)) ++ goto out; ++ ++ /* under the same dir, no need to lock_rename() */ ++ delegated = NULL; ++ err = vfsub_rename(h_dir, h_dentry, h_dir, &h_path, &delegated); ++ AuTraceErr(err); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal rename\n"); ++ iput(delegated); ++ } ++ dput(h_path.dentry); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++/* ++ * functions for removing a whiteout ++ */ ++ ++static int do_unlink_wh(struct inode *h_dir, struct path *h_path) ++{ ++ int err, force; ++ struct inode *delegated; ++ ++ /* ++ * forces superio when the dir has a sticky bit. ++ * this may be a violation of unix fs semantics. ++ */ ++ force = (h_dir->i_mode & S_ISVTX) ++ && !uid_eq(current_fsuid(), h_path->dentry->d_inode->i_uid); ++ delegated = NULL; ++ err = vfsub_unlink(h_dir, h_path, &delegated, force); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ return err; ++} ++ ++int au_wh_unlink_dentry(struct inode *h_dir, struct path *h_path, ++ struct dentry *dentry) ++{ ++ int err; ++ ++ err = do_unlink_wh(h_dir, h_path); ++ if (!err && dentry) ++ au_set_dbwh(dentry, -1); ++ ++ return err; ++} ++ ++static int unlink_wh_name(struct dentry *h_parent, struct qstr *wh, ++ struct au_branch *br) ++{ ++ int err; ++ struct path h_path = { ++ .mnt = au_br_mnt(br) ++ }; ++ ++ err = 0; ++ h_path.dentry = vfsub_lkup_one(wh, h_parent); ++ if (IS_ERR(h_path.dentry)) ++ err = PTR_ERR(h_path.dentry); ++ else { ++ if (h_path.dentry->d_inode ++ && S_ISREG(h_path.dentry->d_inode->i_mode)) ++ err = do_unlink_wh(h_parent->d_inode, &h_path); ++ dput(h_path.dentry); ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++/* ++ * initialize/clean whiteout for a branch ++ */ ++ ++static void au_wh_clean(struct inode *h_dir, struct path *whpath, ++ const int isdir) ++{ ++ int err; ++ struct inode *delegated; ++ ++ if (!whpath->dentry->d_inode) ++ return; ++ ++ if (isdir) ++ err = vfsub_rmdir(h_dir, whpath); ++ else { ++ delegated = NULL; ++ err = vfsub_unlink(h_dir, whpath, &delegated, /*force*/0); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ } ++ if (unlikely(err)) ++ pr_warn("failed removing %pd (%d), ignored.\n", ++ whpath->dentry, err); ++} ++ ++static int test_linkable(struct dentry *h_root) ++{ ++ struct inode *h_dir = h_root->d_inode; ++ ++ if (h_dir->i_op->link) ++ return 0; ++ ++ pr_err("%pd (%s) doesn't support link(2), use noplink and rw+nolwh\n", ++ h_root, au_sbtype(h_root->d_sb)); ++ return -ENOSYS; ++} ++ ++/* todo: should this mkdir be done in /sbin/mount.aufs helper? */ ++static int au_whdir(struct inode *h_dir, struct path *path) ++{ ++ int err; ++ ++ err = -EEXIST; ++ if (!path->dentry->d_inode) { ++ int mode = S_IRWXU; ++ ++ if (au_test_nfs(path->dentry->d_sb)) ++ mode |= S_IXUGO; ++ err = vfsub_mkdir(h_dir, path, mode); ++ } else if (d_is_dir(path->dentry)) ++ err = 0; ++ else ++ pr_err("unknown %pd exists\n", path->dentry); ++ ++ return err; ++} ++ ++struct au_wh_base { ++ const struct qstr *name; ++ struct dentry *dentry; ++}; ++ ++static void au_wh_init_ro(struct inode *h_dir, struct au_wh_base base[], ++ struct path *h_path) ++{ ++ h_path->dentry = base[AuBrWh_BASE].dentry; ++ au_wh_clean(h_dir, h_path, /*isdir*/0); ++ h_path->dentry = base[AuBrWh_PLINK].dentry; ++ au_wh_clean(h_dir, h_path, /*isdir*/1); ++ h_path->dentry = base[AuBrWh_ORPH].dentry; ++ au_wh_clean(h_dir, h_path, /*isdir*/1); ++} ++ ++/* ++ * returns tri-state, ++ * minus: error, caller should print the message ++ * zero: succuess ++ * plus: error, caller should NOT print the message ++ */ ++static int au_wh_init_rw_nolink(struct dentry *h_root, struct au_wbr *wbr, ++ int do_plink, struct au_wh_base base[], ++ struct path *h_path) ++{ ++ int err; ++ struct inode *h_dir; ++ ++ h_dir = h_root->d_inode; ++ h_path->dentry = base[AuBrWh_BASE].dentry; ++ au_wh_clean(h_dir, h_path, /*isdir*/0); ++ h_path->dentry = base[AuBrWh_PLINK].dentry; ++ if (do_plink) { ++ err = test_linkable(h_root); ++ if (unlikely(err)) { ++ err = 1; ++ goto out; ++ } ++ ++ err = au_whdir(h_dir, h_path); ++ if (unlikely(err)) ++ goto out; ++ wbr->wbr_plink = dget(base[AuBrWh_PLINK].dentry); ++ } else ++ au_wh_clean(h_dir, h_path, /*isdir*/1); ++ h_path->dentry = base[AuBrWh_ORPH].dentry; ++ err = au_whdir(h_dir, h_path); ++ if (unlikely(err)) ++ goto out; ++ wbr->wbr_orph = dget(base[AuBrWh_ORPH].dentry); ++ ++out: ++ return err; ++} ++ ++/* ++ * for the moment, aufs supports the branch filesystem which does not support ++ * link(2). testing on FAT which does not support i_op->setattr() fully either, ++ * copyup failed. finally, such filesystem will not be used as the writable ++ * branch. ++ * ++ * returns tri-state, see above. ++ */ ++static int au_wh_init_rw(struct dentry *h_root, struct au_wbr *wbr, ++ int do_plink, struct au_wh_base base[], ++ struct path *h_path) ++{ ++ int err; ++ struct inode *h_dir; ++ ++ WbrWhMustWriteLock(wbr); ++ ++ err = test_linkable(h_root); ++ if (unlikely(err)) { ++ err = 1; ++ goto out; ++ } ++ ++ /* ++ * todo: should this create be done in /sbin/mount.aufs helper? ++ */ ++ err = -EEXIST; ++ h_dir = h_root->d_inode; ++ if (!base[AuBrWh_BASE].dentry->d_inode) { ++ h_path->dentry = base[AuBrWh_BASE].dentry; ++ err = vfsub_create(h_dir, h_path, WH_MASK, /*want_excl*/true); ++ } else if (S_ISREG(base[AuBrWh_BASE].dentry->d_inode->i_mode)) ++ err = 0; ++ else ++ pr_err("unknown %pd2 exists\n", base[AuBrWh_BASE].dentry); ++ if (unlikely(err)) ++ goto out; ++ ++ h_path->dentry = base[AuBrWh_PLINK].dentry; ++ if (do_plink) { ++ err = au_whdir(h_dir, h_path); ++ if (unlikely(err)) ++ goto out; ++ wbr->wbr_plink = dget(base[AuBrWh_PLINK].dentry); ++ } else ++ au_wh_clean(h_dir, h_path, /*isdir*/1); ++ wbr->wbr_whbase = dget(base[AuBrWh_BASE].dentry); ++ ++ h_path->dentry = base[AuBrWh_ORPH].dentry; ++ err = au_whdir(h_dir, h_path); ++ if (unlikely(err)) ++ goto out; ++ wbr->wbr_orph = dget(base[AuBrWh_ORPH].dentry); ++ ++out: ++ return err; ++} ++ ++/* ++ * initialize the whiteout base file/dir for @br. ++ */ ++int au_wh_init(struct au_branch *br, struct super_block *sb) ++{ ++ int err, i; ++ const unsigned char do_plink ++ = !!au_opt_test(au_mntflags(sb), PLINK); ++ struct inode *h_dir; ++ struct path path = br->br_path; ++ struct dentry *h_root = path.dentry; ++ struct au_wbr *wbr = br->br_wbr; ++ static const struct qstr base_name[] = { ++ [AuBrWh_BASE] = QSTR_INIT(AUFS_BASE_NAME, ++ sizeof(AUFS_BASE_NAME) - 1), ++ [AuBrWh_PLINK] = QSTR_INIT(AUFS_PLINKDIR_NAME, ++ sizeof(AUFS_PLINKDIR_NAME) - 1), ++ [AuBrWh_ORPH] = QSTR_INIT(AUFS_ORPHDIR_NAME, ++ sizeof(AUFS_ORPHDIR_NAME) - 1) ++ }; ++ struct au_wh_base base[] = { ++ [AuBrWh_BASE] = { ++ .name = base_name + AuBrWh_BASE, ++ .dentry = NULL ++ }, ++ [AuBrWh_PLINK] = { ++ .name = base_name + AuBrWh_PLINK, ++ .dentry = NULL ++ }, ++ [AuBrWh_ORPH] = { ++ .name = base_name + AuBrWh_ORPH, ++ .dentry = NULL ++ } ++ }; ++ ++ if (wbr) ++ WbrWhMustWriteLock(wbr); ++ ++ for (i = 0; i < AuBrWh_Last; i++) { ++ /* doubly whiteouted */ ++ struct dentry *d; ++ ++ d = au_wh_lkup(h_root, (void *)base[i].name, br); ++ err = PTR_ERR(d); ++ if (IS_ERR(d)) ++ goto out; ++ ++ base[i].dentry = d; ++ AuDebugOn(wbr ++ && wbr->wbr_wh[i] ++ && wbr->wbr_wh[i] != base[i].dentry); ++ } ++ ++ if (wbr) ++ for (i = 0; i < AuBrWh_Last; i++) { ++ dput(wbr->wbr_wh[i]); ++ wbr->wbr_wh[i] = NULL; ++ } ++ ++ err = 0; ++ if (!au_br_writable(br->br_perm)) { ++ h_dir = h_root->d_inode; ++ au_wh_init_ro(h_dir, base, &path); ++ } else if (!au_br_wh_linkable(br->br_perm)) { ++ err = au_wh_init_rw_nolink(h_root, wbr, do_plink, base, &path); ++ if (err > 0) ++ goto out; ++ else if (err) ++ goto out_err; ++ } else { ++ err = au_wh_init_rw(h_root, wbr, do_plink, base, &path); ++ if (err > 0) ++ goto out; ++ else if (err) ++ goto out_err; ++ } ++ goto out; /* success */ ++ ++out_err: ++ pr_err("an error(%d) on the writable branch %pd(%s)\n", ++ err, h_root, au_sbtype(h_root->d_sb)); ++out: ++ for (i = 0; i < AuBrWh_Last; i++) ++ dput(base[i].dentry); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++/* ++ * whiteouts are all hard-linked usually. ++ * when its link count reaches a ceiling, we create a new whiteout base ++ * asynchronously. ++ */ ++ ++struct reinit_br_wh { ++ struct super_block *sb; ++ struct au_branch *br; ++}; ++ ++static void reinit_br_wh(void *arg) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ struct path h_path; ++ struct reinit_br_wh *a = arg; ++ struct au_wbr *wbr; ++ struct inode *dir, *delegated; ++ struct dentry *h_root; ++ struct au_hinode *hdir; ++ ++ err = 0; ++ wbr = a->br->br_wbr; ++ /* big aufs lock */ ++ si_noflush_write_lock(a->sb); ++ if (!au_br_writable(a->br->br_perm)) ++ goto out; ++ bindex = au_br_index(a->sb, a->br->br_id); ++ if (unlikely(bindex < 0)) ++ goto out; ++ ++ di_read_lock_parent(a->sb->s_root, AuLock_IR); ++ dir = a->sb->s_root->d_inode; ++ hdir = au_hi(dir, bindex); ++ h_root = au_h_dptr(a->sb->s_root, bindex); ++ AuDebugOn(h_root != au_br_dentry(a->br)); ++ ++ au_hn_imtx_lock_nested(hdir, AuLsc_I_PARENT); ++ wbr_wh_write_lock(wbr); ++ err = au_h_verify(wbr->wbr_whbase, au_opt_udba(a->sb), hdir->hi_inode, ++ h_root, a->br); ++ if (!err) { ++ h_path.dentry = wbr->wbr_whbase; ++ h_path.mnt = au_br_mnt(a->br); ++ delegated = NULL; ++ err = vfsub_unlink(hdir->hi_inode, &h_path, &delegated, ++ /*force*/0); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ } else { ++ pr_warn("%pd is moved, ignored\n", wbr->wbr_whbase); ++ err = 0; ++ } ++ dput(wbr->wbr_whbase); ++ wbr->wbr_whbase = NULL; ++ if (!err) ++ err = au_wh_init(a->br, a->sb); ++ wbr_wh_write_unlock(wbr); ++ au_hn_imtx_unlock(hdir); ++ di_read_unlock(a->sb->s_root, AuLock_IR); ++ if (!err) ++ au_fhsm_wrote(a->sb, bindex, /*force*/0); ++ ++out: ++ if (wbr) ++ atomic_dec(&wbr->wbr_wh_running); ++ atomic_dec(&a->br->br_count); ++ si_write_unlock(a->sb); ++ au_nwt_done(&au_sbi(a->sb)->si_nowait); ++ kfree(arg); ++ if (unlikely(err)) ++ AuIOErr("err %d\n", err); ++} ++ ++static void kick_reinit_br_wh(struct super_block *sb, struct au_branch *br) ++{ ++ int do_dec, wkq_err; ++ struct reinit_br_wh *arg; ++ ++ do_dec = 1; ++ if (atomic_inc_return(&br->br_wbr->wbr_wh_running) != 1) ++ goto out; ++ ++ /* ignore ENOMEM */ ++ arg = kmalloc(sizeof(*arg), GFP_NOFS); ++ if (arg) { ++ /* ++ * dec(wh_running), kfree(arg) and dec(br_count) ++ * in reinit function ++ */ ++ arg->sb = sb; ++ arg->br = br; ++ atomic_inc(&br->br_count); ++ wkq_err = au_wkq_nowait(reinit_br_wh, arg, sb, /*flags*/0); ++ if (unlikely(wkq_err)) { ++ atomic_dec(&br->br_wbr->wbr_wh_running); ++ atomic_dec(&br->br_count); ++ kfree(arg); ++ } ++ do_dec = 0; ++ } ++ ++out: ++ if (do_dec) ++ atomic_dec(&br->br_wbr->wbr_wh_running); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * create the whiteout @wh. ++ */ ++static int link_or_create_wh(struct super_block *sb, aufs_bindex_t bindex, ++ struct dentry *wh) ++{ ++ int err; ++ struct path h_path = { ++ .dentry = wh ++ }; ++ struct au_branch *br; ++ struct au_wbr *wbr; ++ struct dentry *h_parent; ++ struct inode *h_dir, *delegated; ++ ++ h_parent = wh->d_parent; /* dir inode is locked */ ++ h_dir = h_parent->d_inode; ++ IMustLock(h_dir); ++ ++ br = au_sbr(sb, bindex); ++ h_path.mnt = au_br_mnt(br); ++ wbr = br->br_wbr; ++ wbr_wh_read_lock(wbr); ++ if (wbr->wbr_whbase) { ++ delegated = NULL; ++ err = vfsub_link(wbr->wbr_whbase, h_dir, &h_path, &delegated); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal link\n"); ++ iput(delegated); ++ } ++ if (!err || err != -EMLINK) ++ goto out; ++ ++ /* link count full. re-initialize br_whbase. */ ++ kick_reinit_br_wh(sb, br); ++ } ++ ++ /* return this error in this context */ ++ err = vfsub_create(h_dir, &h_path, WH_MASK, /*want_excl*/true); ++ if (!err) ++ au_fhsm_wrote(sb, bindex, /*force*/0); ++ ++out: ++ wbr_wh_read_unlock(wbr); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * create or remove the diropq. ++ */ ++static struct dentry *do_diropq(struct dentry *dentry, aufs_bindex_t bindex, ++ unsigned int flags) ++{ ++ struct dentry *opq_dentry, *h_dentry; ++ struct super_block *sb; ++ struct au_branch *br; ++ int err; ++ ++ sb = dentry->d_sb; ++ br = au_sbr(sb, bindex); ++ h_dentry = au_h_dptr(dentry, bindex); ++ opq_dentry = vfsub_lkup_one(&diropq_name, h_dentry); ++ if (IS_ERR(opq_dentry)) ++ goto out; ++ ++ if (au_ftest_diropq(flags, CREATE)) { ++ err = link_or_create_wh(sb, bindex, opq_dentry); ++ if (!err) { ++ au_set_dbdiropq(dentry, bindex); ++ goto out; /* success */ ++ } ++ } else { ++ struct path tmp = { ++ .dentry = opq_dentry, ++ .mnt = au_br_mnt(br) ++ }; ++ err = do_unlink_wh(au_h_iptr(dentry->d_inode, bindex), &tmp); ++ if (!err) ++ au_set_dbdiropq(dentry, -1); ++ } ++ dput(opq_dentry); ++ opq_dentry = ERR_PTR(err); ++ ++out: ++ return opq_dentry; ++} ++ ++struct do_diropq_args { ++ struct dentry **errp; ++ struct dentry *dentry; ++ aufs_bindex_t bindex; ++ unsigned int flags; ++}; ++ ++static void call_do_diropq(void *args) ++{ ++ struct do_diropq_args *a = args; ++ *a->errp = do_diropq(a->dentry, a->bindex, a->flags); ++} ++ ++struct dentry *au_diropq_sio(struct dentry *dentry, aufs_bindex_t bindex, ++ unsigned int flags) ++{ ++ struct dentry *diropq, *h_dentry; ++ ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!au_test_h_perm_sio(h_dentry->d_inode, MAY_EXEC | MAY_WRITE)) ++ diropq = do_diropq(dentry, bindex, flags); ++ else { ++ int wkq_err; ++ struct do_diropq_args args = { ++ .errp = &diropq, ++ .dentry = dentry, ++ .bindex = bindex, ++ .flags = flags ++ }; ++ ++ wkq_err = au_wkq_wait(call_do_diropq, &args); ++ if (unlikely(wkq_err)) ++ diropq = ERR_PTR(wkq_err); ++ } ++ ++ return diropq; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * lookup whiteout dentry. ++ * @h_parent: lower parent dentry which must exist and be locked ++ * @base_name: name of dentry which will be whiteouted ++ * returns dentry for whiteout. ++ */ ++struct dentry *au_wh_lkup(struct dentry *h_parent, struct qstr *base_name, ++ struct au_branch *br) ++{ ++ int err; ++ struct qstr wh_name; ++ struct dentry *wh_dentry; ++ ++ err = au_wh_name_alloc(&wh_name, base_name); ++ wh_dentry = ERR_PTR(err); ++ if (!err) { ++ wh_dentry = vfsub_lkup_one(&wh_name, h_parent); ++ kfree(wh_name.name); ++ } ++ return wh_dentry; ++} ++ ++/* ++ * link/create a whiteout for @dentry on @bindex. ++ */ ++struct dentry *au_wh_create(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_parent) ++{ ++ struct dentry *wh_dentry; ++ struct super_block *sb; ++ int err; ++ ++ sb = dentry->d_sb; ++ wh_dentry = au_wh_lkup(h_parent, &dentry->d_name, au_sbr(sb, bindex)); ++ if (!IS_ERR(wh_dentry) && !wh_dentry->d_inode) { ++ err = link_or_create_wh(sb, bindex, wh_dentry); ++ if (!err) { ++ au_set_dbwh(dentry, bindex); ++ au_fhsm_wrote(sb, bindex, /*force*/0); ++ } else { ++ dput(wh_dentry); ++ wh_dentry = ERR_PTR(err); ++ } ++ } ++ ++ return wh_dentry; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* Delete all whiteouts in this directory on branch bindex. */ ++static int del_wh_children(struct dentry *h_dentry, struct au_nhash *whlist, ++ aufs_bindex_t bindex, struct au_branch *br) ++{ ++ int err; ++ unsigned long ul, n; ++ struct qstr wh_name; ++ char *p; ++ struct hlist_head *head; ++ struct au_vdir_wh *pos; ++ struct au_vdir_destr *str; ++ ++ err = -ENOMEM; ++ p = (void *)__get_free_page(GFP_NOFS); ++ wh_name.name = p; ++ if (unlikely(!wh_name.name)) ++ goto out; ++ ++ err = 0; ++ memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN); ++ p += AUFS_WH_PFX_LEN; ++ n = whlist->nh_num; ++ head = whlist->nh_head; ++ for (ul = 0; !err && ul < n; ul++, head++) { ++ hlist_for_each_entry(pos, head, wh_hash) { ++ if (pos->wh_bindex != bindex) ++ continue; ++ ++ str = &pos->wh_str; ++ if (str->len + AUFS_WH_PFX_LEN <= PATH_MAX) { ++ memcpy(p, str->name, str->len); ++ wh_name.len = AUFS_WH_PFX_LEN + str->len; ++ err = unlink_wh_name(h_dentry, &wh_name, br); ++ if (!err) ++ continue; ++ break; ++ } ++ AuIOErr("whiteout name too long %.*s\n", ++ str->len, str->name); ++ err = -EIO; ++ break; ++ } ++ } ++ free_page((unsigned long)wh_name.name); ++ ++out: ++ return err; ++} ++ ++struct del_wh_children_args { ++ int *errp; ++ struct dentry *h_dentry; ++ struct au_nhash *whlist; ++ aufs_bindex_t bindex; ++ struct au_branch *br; ++}; ++ ++static void call_del_wh_children(void *args) ++{ ++ struct del_wh_children_args *a = args; ++ *a->errp = del_wh_children(a->h_dentry, a->whlist, a->bindex, a->br); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_whtmp_rmdir *au_whtmp_rmdir_alloc(struct super_block *sb, gfp_t gfp) ++{ ++ struct au_whtmp_rmdir *whtmp; ++ int err; ++ unsigned int rdhash; ++ ++ SiMustAnyLock(sb); ++ ++ whtmp = kzalloc(sizeof(*whtmp), gfp); ++ if (unlikely(!whtmp)) { ++ whtmp = ERR_PTR(-ENOMEM); ++ goto out; ++ } ++ ++ /* no estimation for dir size */ ++ rdhash = au_sbi(sb)->si_rdhash; ++ if (!rdhash) ++ rdhash = AUFS_RDHASH_DEF; ++ err = au_nhash_alloc(&whtmp->whlist, rdhash, gfp); ++ if (unlikely(err)) { ++ kfree(whtmp); ++ whtmp = ERR_PTR(err); ++ } ++ ++out: ++ return whtmp; ++} ++ ++void au_whtmp_rmdir_free(struct au_whtmp_rmdir *whtmp) ++{ ++ if (whtmp->br) ++ atomic_dec(&whtmp->br->br_count); ++ dput(whtmp->wh_dentry); ++ iput(whtmp->dir); ++ au_nhash_wh_free(&whtmp->whlist); ++ kfree(whtmp); ++} ++ ++/* ++ * rmdir the whiteouted temporary named dir @h_dentry. ++ * @whlist: whiteouted children. ++ */ ++int au_whtmp_rmdir(struct inode *dir, aufs_bindex_t bindex, ++ struct dentry *wh_dentry, struct au_nhash *whlist) ++{ ++ int err; ++ unsigned int h_nlink; ++ struct path h_tmp; ++ struct inode *wh_inode, *h_dir; ++ struct au_branch *br; ++ ++ h_dir = wh_dentry->d_parent->d_inode; /* dir inode is locked */ ++ IMustLock(h_dir); ++ ++ br = au_sbr(dir->i_sb, bindex); ++ wh_inode = wh_dentry->d_inode; ++ mutex_lock_nested(&wh_inode->i_mutex, AuLsc_I_CHILD); ++ ++ /* ++ * someone else might change some whiteouts while we were sleeping. ++ * it means this whlist may have an obsoleted entry. ++ */ ++ if (!au_test_h_perm_sio(wh_inode, MAY_EXEC | MAY_WRITE)) ++ err = del_wh_children(wh_dentry, whlist, bindex, br); ++ else { ++ int wkq_err; ++ struct del_wh_children_args args = { ++ .errp = &err, ++ .h_dentry = wh_dentry, ++ .whlist = whlist, ++ .bindex = bindex, ++ .br = br ++ }; ++ ++ wkq_err = au_wkq_wait(call_del_wh_children, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ mutex_unlock(&wh_inode->i_mutex); ++ ++ if (!err) { ++ h_tmp.dentry = wh_dentry; ++ h_tmp.mnt = au_br_mnt(br); ++ h_nlink = h_dir->i_nlink; ++ err = vfsub_rmdir(h_dir, &h_tmp); ++ /* some fs doesn't change the parent nlink in some cases */ ++ h_nlink -= h_dir->i_nlink; ++ } ++ ++ if (!err) { ++ if (au_ibstart(dir) == bindex) { ++ /* todo: dir->i_mutex is necessary */ ++ au_cpup_attr_timesizes(dir); ++ if (h_nlink) ++ vfsub_drop_nlink(dir); ++ } ++ return 0; /* success */ ++ } ++ ++ pr_warn("failed removing %pd(%d), ignored\n", wh_dentry, err); ++ return err; ++} ++ ++static void call_rmdir_whtmp(void *args) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ struct au_whtmp_rmdir *a = args; ++ struct super_block *sb; ++ struct dentry *h_parent; ++ struct inode *h_dir; ++ struct au_hinode *hdir; ++ ++ /* rmdir by nfsd may cause deadlock with this i_mutex */ ++ /* mutex_lock(&a->dir->i_mutex); */ ++ err = -EROFS; ++ sb = a->dir->i_sb; ++ si_read_lock(sb, !AuLock_FLUSH); ++ if (!au_br_writable(a->br->br_perm)) ++ goto out; ++ bindex = au_br_index(sb, a->br->br_id); ++ if (unlikely(bindex < 0)) ++ goto out; ++ ++ err = -EIO; ++ ii_write_lock_parent(a->dir); ++ h_parent = dget_parent(a->wh_dentry); ++ h_dir = h_parent->d_inode; ++ hdir = au_hi(a->dir, bindex); ++ err = vfsub_mnt_want_write(au_br_mnt(a->br)); ++ if (unlikely(err)) ++ goto out_mnt; ++ au_hn_imtx_lock_nested(hdir, AuLsc_I_PARENT); ++ err = au_h_verify(a->wh_dentry, au_opt_udba(sb), h_dir, h_parent, ++ a->br); ++ if (!err) ++ err = au_whtmp_rmdir(a->dir, bindex, a->wh_dentry, &a->whlist); ++ au_hn_imtx_unlock(hdir); ++ vfsub_mnt_drop_write(au_br_mnt(a->br)); ++ ++out_mnt: ++ dput(h_parent); ++ ii_write_unlock(a->dir); ++out: ++ /* mutex_unlock(&a->dir->i_mutex); */ ++ au_whtmp_rmdir_free(a); ++ si_read_unlock(sb); ++ au_nwt_done(&au_sbi(sb)->si_nowait); ++ if (unlikely(err)) ++ AuIOErr("err %d\n", err); ++} ++ ++void au_whtmp_kick_rmdir(struct inode *dir, aufs_bindex_t bindex, ++ struct dentry *wh_dentry, struct au_whtmp_rmdir *args) ++{ ++ int wkq_err; ++ struct super_block *sb; ++ ++ IMustLock(dir); ++ ++ /* all post-process will be done in do_rmdir_whtmp(). */ ++ sb = dir->i_sb; ++ args->dir = au_igrab(dir); ++ args->br = au_sbr(sb, bindex); ++ atomic_inc(&args->br->br_count); ++ args->wh_dentry = dget(wh_dentry); ++ wkq_err = au_wkq_nowait(call_rmdir_whtmp, args, sb, /*flags*/0); ++ if (unlikely(wkq_err)) { ++ pr_warn("rmdir error %pd (%d), ignored\n", wh_dentry, wkq_err); ++ au_whtmp_rmdir_free(args); ++ } ++} +diff --git a/fs/aufs/whout.h b/fs/aufs/whout.h +new file mode 100644 +index 0000000..5a5c378 +--- /dev/null ++++ b/fs/aufs/whout.h +@@ -0,0 +1,85 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * whiteout for logical deletion and opaque directory ++ */ ++ ++#ifndef __AUFS_WHOUT_H__ ++#define __AUFS_WHOUT_H__ ++ ++#ifdef __KERNEL__ ++ ++#include "dir.h" ++ ++/* whout.c */ ++int au_wh_name_alloc(struct qstr *wh, const struct qstr *name); ++int au_wh_test(struct dentry *h_parent, struct qstr *wh_name, int try_sio); ++int au_diropq_test(struct dentry *h_dentry); ++struct au_branch; ++struct dentry *au_whtmp_lkup(struct dentry *h_parent, struct au_branch *br, ++ struct qstr *prefix); ++int au_whtmp_ren(struct dentry *h_dentry, struct au_branch *br); ++int au_wh_unlink_dentry(struct inode *h_dir, struct path *h_path, ++ struct dentry *dentry); ++int au_wh_init(struct au_branch *br, struct super_block *sb); ++ ++/* diropq flags */ ++#define AuDiropq_CREATE 1 ++#define au_ftest_diropq(flags, name) ((flags) & AuDiropq_##name) ++#define au_fset_diropq(flags, name) \ ++ do { (flags) |= AuDiropq_##name; } while (0) ++#define au_fclr_diropq(flags, name) \ ++ do { (flags) &= ~AuDiropq_##name; } while (0) ++ ++struct dentry *au_diropq_sio(struct dentry *dentry, aufs_bindex_t bindex, ++ unsigned int flags); ++struct dentry *au_wh_lkup(struct dentry *h_parent, struct qstr *base_name, ++ struct au_branch *br); ++struct dentry *au_wh_create(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_parent); ++ ++/* real rmdir for the whiteout-ed dir */ ++struct au_whtmp_rmdir { ++ struct inode *dir; ++ struct au_branch *br; ++ struct dentry *wh_dentry; ++ struct au_nhash whlist; ++}; ++ ++struct au_whtmp_rmdir *au_whtmp_rmdir_alloc(struct super_block *sb, gfp_t gfp); ++void au_whtmp_rmdir_free(struct au_whtmp_rmdir *whtmp); ++int au_whtmp_rmdir(struct inode *dir, aufs_bindex_t bindex, ++ struct dentry *wh_dentry, struct au_nhash *whlist); ++void au_whtmp_kick_rmdir(struct inode *dir, aufs_bindex_t bindex, ++ struct dentry *wh_dentry, struct au_whtmp_rmdir *args); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct dentry *au_diropq_create(struct dentry *dentry, ++ aufs_bindex_t bindex) ++{ ++ return au_diropq_sio(dentry, bindex, AuDiropq_CREATE); ++} ++ ++static inline int au_diropq_remove(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ return PTR_ERR(au_diropq_sio(dentry, bindex, !AuDiropq_CREATE)); ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_WHOUT_H__ */ +diff --git a/fs/aufs/wkq.c b/fs/aufs/wkq.c +new file mode 100644 +index 0000000..a4e1b92 +--- /dev/null ++++ b/fs/aufs/wkq.c +@@ -0,0 +1,213 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * workqueue for asynchronous/super-io operations ++ * todo: try new dredential scheme ++ */ ++ ++#include ++#include "aufs.h" ++ ++/* internal workqueue named AUFS_WKQ_NAME */ ++ ++static struct workqueue_struct *au_wkq; ++ ++struct au_wkinfo { ++ struct work_struct wk; ++ struct kobject *kobj; ++ ++ unsigned int flags; /* see wkq.h */ ++ ++ au_wkq_func_t func; ++ void *args; ++ ++ struct completion *comp; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void wkq_func(struct work_struct *wk) ++{ ++ struct au_wkinfo *wkinfo = container_of(wk, struct au_wkinfo, wk); ++ ++ AuDebugOn(!uid_eq(current_fsuid(), GLOBAL_ROOT_UID)); ++ AuDebugOn(rlimit(RLIMIT_FSIZE) != RLIM_INFINITY); ++ ++ wkinfo->func(wkinfo->args); ++ if (au_ftest_wkq(wkinfo->flags, WAIT)) ++ complete(wkinfo->comp); ++ else { ++ kobject_put(wkinfo->kobj); ++ module_put(THIS_MODULE); /* todo: ?? */ ++ kfree(wkinfo); ++ } ++} ++ ++/* ++ * Since struct completion is large, try allocating it dynamically. ++ */ ++#if 1 /* defined(CONFIG_4KSTACKS) || defined(AuTest4KSTACKS) */ ++#define AuWkqCompDeclare(name) struct completion *comp = NULL ++ ++static int au_wkq_comp_alloc(struct au_wkinfo *wkinfo, struct completion **comp) ++{ ++ *comp = kmalloc(sizeof(**comp), GFP_NOFS); ++ if (*comp) { ++ init_completion(*comp); ++ wkinfo->comp = *comp; ++ return 0; ++ } ++ return -ENOMEM; ++} ++ ++static void au_wkq_comp_free(struct completion *comp) ++{ ++ kfree(comp); ++} ++ ++#else ++ ++/* no braces */ ++#define AuWkqCompDeclare(name) \ ++ DECLARE_COMPLETION_ONSTACK(_ ## name); \ ++ struct completion *comp = &_ ## name ++ ++static int au_wkq_comp_alloc(struct au_wkinfo *wkinfo, struct completion **comp) ++{ ++ wkinfo->comp = *comp; ++ return 0; ++} ++ ++static void au_wkq_comp_free(struct completion *comp __maybe_unused) ++{ ++ /* empty */ ++} ++#endif /* 4KSTACKS */ ++ ++static void au_wkq_run(struct au_wkinfo *wkinfo) ++{ ++ if (au_ftest_wkq(wkinfo->flags, NEST)) { ++ if (au_wkq_test()) { ++ AuWarn1("wkq from wkq, unless silly-rename on NFS," ++ " due to a dead dir by UDBA?\n"); ++ AuDebugOn(au_ftest_wkq(wkinfo->flags, WAIT)); ++ } ++ } else ++ au_dbg_verify_kthread(); ++ ++ if (au_ftest_wkq(wkinfo->flags, WAIT)) { ++ INIT_WORK_ONSTACK(&wkinfo->wk, wkq_func); ++ queue_work(au_wkq, &wkinfo->wk); ++ } else { ++ INIT_WORK(&wkinfo->wk, wkq_func); ++ schedule_work(&wkinfo->wk); ++ } ++} ++ ++/* ++ * Be careful. It is easy to make deadlock happen. ++ * processA: lock, wkq and wait ++ * processB: wkq and wait, lock in wkq ++ * --> deadlock ++ */ ++int au_wkq_do_wait(unsigned int flags, au_wkq_func_t func, void *args) ++{ ++ int err; ++ AuWkqCompDeclare(comp); ++ struct au_wkinfo wkinfo = { ++ .flags = flags, ++ .func = func, ++ .args = args ++ }; ++ ++ err = au_wkq_comp_alloc(&wkinfo, &comp); ++ if (!err) { ++ au_wkq_run(&wkinfo); ++ /* no timeout, no interrupt */ ++ wait_for_completion(wkinfo.comp); ++ au_wkq_comp_free(comp); ++ destroy_work_on_stack(&wkinfo.wk); ++ } ++ ++ return err; ++ ++} ++ ++/* ++ * Note: dget/dput() in func for aufs dentries are not supported. It will be a ++ * problem in a concurrent umounting. ++ */ ++int au_wkq_nowait(au_wkq_func_t func, void *args, struct super_block *sb, ++ unsigned int flags) ++{ ++ int err; ++ struct au_wkinfo *wkinfo; ++ ++ atomic_inc(&au_sbi(sb)->si_nowait.nw_len); ++ ++ /* ++ * wkq_func() must free this wkinfo. ++ * it highly depends upon the implementation of workqueue. ++ */ ++ err = 0; ++ wkinfo = kmalloc(sizeof(*wkinfo), GFP_NOFS); ++ if (wkinfo) { ++ wkinfo->kobj = &au_sbi(sb)->si_kobj; ++ wkinfo->flags = flags & ~AuWkq_WAIT; ++ wkinfo->func = func; ++ wkinfo->args = args; ++ wkinfo->comp = NULL; ++ kobject_get(wkinfo->kobj); ++ __module_get(THIS_MODULE); /* todo: ?? */ ++ ++ au_wkq_run(wkinfo); ++ } else { ++ err = -ENOMEM; ++ au_nwt_done(&au_sbi(sb)->si_nowait); ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_nwt_init(struct au_nowait_tasks *nwt) ++{ ++ atomic_set(&nwt->nw_len, 0); ++ /* smp_mb(); */ /* atomic_set */ ++ init_waitqueue_head(&nwt->nw_wq); ++} ++ ++void au_wkq_fin(void) ++{ ++ destroy_workqueue(au_wkq); ++} ++ ++int __init au_wkq_init(void) ++{ ++ int err; ++ ++ err = 0; ++ au_wkq = alloc_workqueue(AUFS_WKQ_NAME, 0, WQ_DFL_ACTIVE); ++ if (IS_ERR(au_wkq)) ++ err = PTR_ERR(au_wkq); ++ else if (!au_wkq) ++ err = -ENOMEM; ++ ++ return err; ++} +diff --git a/fs/aufs/wkq.h b/fs/aufs/wkq.h +new file mode 100644 +index 0000000..830123c +--- /dev/null ++++ b/fs/aufs/wkq.h +@@ -0,0 +1,91 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * workqueue for asynchronous/super-io operations ++ * todo: try new credentials management scheme ++ */ ++ ++#ifndef __AUFS_WKQ_H__ ++#define __AUFS_WKQ_H__ ++ ++#ifdef __KERNEL__ ++ ++struct super_block; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * in the next operation, wait for the 'nowait' tasks in system-wide workqueue ++ */ ++struct au_nowait_tasks { ++ atomic_t nw_len; ++ wait_queue_head_t nw_wq; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++typedef void (*au_wkq_func_t)(void *args); ++ ++/* wkq flags */ ++#define AuWkq_WAIT 1 ++#define AuWkq_NEST (1 << 1) ++#define au_ftest_wkq(flags, name) ((flags) & AuWkq_##name) ++#define au_fset_wkq(flags, name) \ ++ do { (flags) |= AuWkq_##name; } while (0) ++#define au_fclr_wkq(flags, name) \ ++ do { (flags) &= ~AuWkq_##name; } while (0) ++ ++#ifndef CONFIG_AUFS_HNOTIFY ++#undef AuWkq_NEST ++#define AuWkq_NEST 0 ++#endif ++ ++/* wkq.c */ ++int au_wkq_do_wait(unsigned int flags, au_wkq_func_t func, void *args); ++int au_wkq_nowait(au_wkq_func_t func, void *args, struct super_block *sb, ++ unsigned int flags); ++void au_nwt_init(struct au_nowait_tasks *nwt); ++int __init au_wkq_init(void); ++void au_wkq_fin(void); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline int au_wkq_test(void) ++{ ++ return current->flags & PF_WQ_WORKER; ++} ++ ++static inline int au_wkq_wait(au_wkq_func_t func, void *args) ++{ ++ return au_wkq_do_wait(AuWkq_WAIT, func, args); ++} ++ ++static inline void au_nwt_done(struct au_nowait_tasks *nwt) ++{ ++ if (atomic_dec_and_test(&nwt->nw_len)) ++ wake_up_all(&nwt->nw_wq); ++} ++ ++static inline int au_nwt_flush(struct au_nowait_tasks *nwt) ++{ ++ wait_event(nwt->nw_wq, !atomic_read(&nwt->nw_len)); ++ return 0; ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_WKQ_H__ */ +diff --git a/fs/aufs/xattr.c b/fs/aufs/xattr.c +new file mode 100644 +index 0000000..e16beea +--- /dev/null ++++ b/fs/aufs/xattr.c +@@ -0,0 +1,344 @@ ++/* ++ * Copyright (C) 2014-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * handling xattr functions ++ */ ++ ++#include ++#include "aufs.h" ++ ++static int au_xattr_ignore(int err, char *name, unsigned int ignore_flags) ++{ ++ if (!ignore_flags) ++ goto out; ++ switch (err) { ++ case -ENOMEM: ++ case -EDQUOT: ++ goto out; ++ } ++ ++ if ((ignore_flags & AuBrAttr_ICEX) == AuBrAttr_ICEX) { ++ err = 0; ++ goto out; ++ } ++ ++#define cmp(brattr, prefix) do { \ ++ if (!strncmp(name, XATTR_##prefix##_PREFIX, \ ++ XATTR_##prefix##_PREFIX_LEN)) { \ ++ if (ignore_flags & AuBrAttr_ICEX_##brattr) \ ++ err = 0; \ ++ goto out; \ ++ } \ ++ } while (0) ++ ++ cmp(SEC, SECURITY); ++ cmp(SYS, SYSTEM); ++ cmp(TR, TRUSTED); ++ cmp(USR, USER); ++#undef cmp ++ ++ if (ignore_flags & AuBrAttr_ICEX_OTH) ++ err = 0; ++ ++out: ++ return err; ++} ++ ++static const int au_xattr_out_of_list = AuBrAttr_ICEX_OTH << 1; ++ ++static int au_do_cpup_xattr(struct dentry *h_dst, struct dentry *h_src, ++ char *name, char **buf, unsigned int ignore_flags, ++ unsigned int verbose) ++{ ++ int err; ++ ssize_t ssz; ++ struct inode *h_idst; ++ ++ ssz = vfs_getxattr_alloc(h_src, name, buf, 0, GFP_NOFS); ++ err = ssz; ++ if (unlikely(err <= 0)) { ++ if (err == -ENODATA ++ || (err == -EOPNOTSUPP ++ && ((ignore_flags & au_xattr_out_of_list) ++ || (au_test_nfs_noacl(h_src->d_inode) ++ && (!strcmp(name, XATTR_NAME_POSIX_ACL_ACCESS) ++ || !strcmp(name, ++ XATTR_NAME_POSIX_ACL_DEFAULT)))) ++ )) ++ err = 0; ++ if (err && (verbose || au_debug_test())) ++ pr_err("%s, err %d\n", name, err); ++ goto out; ++ } ++ ++ /* unlock it temporary */ ++ h_idst = h_dst->d_inode; ++ mutex_unlock(&h_idst->i_mutex); ++ err = vfsub_setxattr(h_dst, name, *buf, ssz, /*flags*/0); ++ mutex_lock_nested(&h_idst->i_mutex, AuLsc_I_CHILD2); ++ if (unlikely(err)) { ++ if (verbose || au_debug_test()) ++ pr_err("%s, err %d\n", name, err); ++ err = au_xattr_ignore(err, name, ignore_flags); ++ } ++ ++out: ++ return err; ++} ++ ++int au_cpup_xattr(struct dentry *h_dst, struct dentry *h_src, int ignore_flags, ++ unsigned int verbose) ++{ ++ int err, unlocked, acl_access, acl_default; ++ ssize_t ssz; ++ struct inode *h_isrc, *h_idst; ++ char *value, *p, *o, *e; ++ ++ /* try stopping to update the source inode while we are referencing */ ++ /* there should not be the parent-child relationship between them */ ++ h_isrc = h_src->d_inode; ++ h_idst = h_dst->d_inode; ++ mutex_unlock(&h_idst->i_mutex); ++ mutex_lock_nested(&h_isrc->i_mutex, AuLsc_I_CHILD); ++ mutex_lock_nested(&h_idst->i_mutex, AuLsc_I_CHILD2); ++ unlocked = 0; ++ ++ /* some filesystems don't list POSIX ACL, for example tmpfs */ ++ ssz = vfs_listxattr(h_src, NULL, 0); ++ err = ssz; ++ if (unlikely(err < 0)) { ++ AuTraceErr(err); ++ if (err == -ENODATA ++ || err == -EOPNOTSUPP) ++ err = 0; /* ignore */ ++ goto out; ++ } ++ ++ err = 0; ++ p = NULL; ++ o = NULL; ++ if (ssz) { ++ err = -ENOMEM; ++ p = kmalloc(ssz, GFP_NOFS); ++ o = p; ++ if (unlikely(!p)) ++ goto out; ++ err = vfs_listxattr(h_src, p, ssz); ++ } ++ mutex_unlock(&h_isrc->i_mutex); ++ unlocked = 1; ++ AuDbg("err %d, ssz %zd\n", err, ssz); ++ if (unlikely(err < 0)) ++ goto out_free; ++ ++ err = 0; ++ e = p + ssz; ++ value = NULL; ++ acl_access = 0; ++ acl_default = 0; ++ while (!err && p < e) { ++ acl_access |= !strncmp(p, XATTR_NAME_POSIX_ACL_ACCESS, ++ sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1); ++ acl_default |= !strncmp(p, XATTR_NAME_POSIX_ACL_DEFAULT, ++ sizeof(XATTR_NAME_POSIX_ACL_DEFAULT) ++ - 1); ++ err = au_do_cpup_xattr(h_dst, h_src, p, &value, ignore_flags, ++ verbose); ++ p += strlen(p) + 1; ++ } ++ AuTraceErr(err); ++ ignore_flags |= au_xattr_out_of_list; ++ if (!err && !acl_access) { ++ err = au_do_cpup_xattr(h_dst, h_src, ++ XATTR_NAME_POSIX_ACL_ACCESS, &value, ++ ignore_flags, verbose); ++ AuTraceErr(err); ++ } ++ if (!err && !acl_default) { ++ err = au_do_cpup_xattr(h_dst, h_src, ++ XATTR_NAME_POSIX_ACL_DEFAULT, &value, ++ ignore_flags, verbose); ++ AuTraceErr(err); ++ } ++ ++ kfree(value); ++ ++out_free: ++ kfree(o); ++out: ++ if (!unlocked) ++ mutex_unlock(&h_isrc->i_mutex); ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++enum { ++ AU_XATTR_LIST, ++ AU_XATTR_GET ++}; ++ ++struct au_lgxattr { ++ int type; ++ union { ++ struct { ++ char *list; ++ size_t size; ++ } list; ++ struct { ++ const char *name; ++ void *value; ++ size_t size; ++ } get; ++ } u; ++}; ++ ++static ssize_t au_lgxattr(struct dentry *dentry, struct au_lgxattr *arg) ++{ ++ ssize_t err; ++ struct path h_path; ++ struct super_block *sb; ++ ++ sb = dentry->d_sb; ++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (unlikely(err)) ++ goto out; ++ err = au_h_path_getattr(dentry, /*force*/1, &h_path); ++ if (unlikely(err)) ++ goto out_si; ++ if (unlikely(!h_path.dentry)) ++ /* illegally overlapped or something */ ++ goto out_di; /* pretending success */ ++ ++ /* always topmost entry only */ ++ switch (arg->type) { ++ case AU_XATTR_LIST: ++ err = vfs_listxattr(h_path.dentry, ++ arg->u.list.list, arg->u.list.size); ++ break; ++ case AU_XATTR_GET: ++ err = vfs_getxattr(h_path.dentry, ++ arg->u.get.name, arg->u.get.value, ++ arg->u.get.size); ++ break; ++ } ++ ++out_di: ++ di_read_unlock(dentry, AuLock_IR); ++out_si: ++ si_read_unlock(sb); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++ssize_t aufs_listxattr(struct dentry *dentry, char *list, size_t size) ++{ ++ struct au_lgxattr arg = { ++ .type = AU_XATTR_LIST, ++ .u.list = { ++ .list = list, ++ .size = size ++ }, ++ }; ++ ++ return au_lgxattr(dentry, &arg); ++} ++ ++ssize_t aufs_getxattr(struct dentry *dentry, const char *name, void *value, ++ size_t size) ++{ ++ struct au_lgxattr arg = { ++ .type = AU_XATTR_GET, ++ .u.get = { ++ .name = name, ++ .value = value, ++ .size = size ++ }, ++ }; ++ ++ return au_lgxattr(dentry, &arg); ++} ++ ++int aufs_setxattr(struct dentry *dentry, const char *name, const void *value, ++ size_t size, int flags) ++{ ++ struct au_srxattr arg = { ++ .type = AU_XATTR_SET, ++ .u.set = { ++ .name = name, ++ .value = value, ++ .size = size, ++ .flags = flags ++ }, ++ }; ++ ++ return au_srxattr(dentry, &arg); ++} ++ ++int aufs_removexattr(struct dentry *dentry, const char *name) ++{ ++ struct au_srxattr arg = { ++ .type = AU_XATTR_REMOVE, ++ .u.remove = { ++ .name = name ++ }, ++ }; ++ ++ return au_srxattr(dentry, &arg); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#if 0 ++static size_t au_xattr_list(struct dentry *dentry, char *list, size_t list_size, ++ const char *name, size_t name_len, int type) ++{ ++ return aufs_listxattr(dentry, list, list_size); ++} ++ ++static int au_xattr_get(struct dentry *dentry, const char *name, void *buffer, ++ size_t size, int type) ++{ ++ return aufs_getxattr(dentry, name, buffer, size); ++} ++ ++static int au_xattr_set(struct dentry *dentry, const char *name, ++ const void *value, size_t size, int flags, int type) ++{ ++ return aufs_setxattr(dentry, name, value, size, flags); ++} ++ ++static const struct xattr_handler au_xattr_handler = { ++ /* no prefix, no flags */ ++ .list = au_xattr_list, ++ .get = au_xattr_get, ++ .set = au_xattr_set ++ /* why no remove? */ ++}; ++ ++static const struct xattr_handler *au_xattr_handlers[] = { ++ &au_xattr_handler ++}; ++ ++void au_xattr_init(struct super_block *sb) ++{ ++ /* sb->s_xattr = au_xattr_handlers; */ ++} ++#endif +diff --git a/fs/aufs/xino.c b/fs/aufs/xino.c +new file mode 100644 +index 0000000..50ab4ca +--- /dev/null ++++ b/fs/aufs/xino.c +@@ -0,0 +1,1343 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++/* ++ * external inode number translation table and bitmap ++ */ ++ ++#include ++#include ++#include "aufs.h" ++ ++/* todo: unnecessary to support mmap_sem since kernel-space? */ ++ssize_t xino_fread(au_readf_t func, struct file *file, void *kbuf, size_t size, ++ loff_t *pos) ++{ ++ ssize_t err; ++ mm_segment_t oldfs; ++ union { ++ void *k; ++ char __user *u; ++ } buf; ++ ++ buf.k = kbuf; ++ oldfs = get_fs(); ++ set_fs(KERNEL_DS); ++ do { ++ /* todo: signal_pending? */ ++ err = func(file, buf.u, size, pos); ++ } while (err == -EAGAIN || err == -EINTR); ++ set_fs(oldfs); ++ ++#if 0 /* reserved for future use */ ++ if (err > 0) ++ fsnotify_access(file->f_dentry); ++#endif ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static ssize_t xino_fwrite_wkq(au_writef_t func, struct file *file, void *buf, ++ size_t size, loff_t *pos); ++ ++static ssize_t do_xino_fwrite(au_writef_t func, struct file *file, void *kbuf, ++ size_t size, loff_t *pos) ++{ ++ ssize_t err; ++ mm_segment_t oldfs; ++ union { ++ void *k; ++ const char __user *u; ++ } buf; ++ int i; ++ const int prevent_endless = 10; ++ ++ i = 0; ++ buf.k = kbuf; ++ oldfs = get_fs(); ++ set_fs(KERNEL_DS); ++ do { ++ err = func(file, buf.u, size, pos); ++ if (err == -EINTR ++ && !au_wkq_test() ++ && fatal_signal_pending(current)) { ++ set_fs(oldfs); ++ err = xino_fwrite_wkq(func, file, kbuf, size, pos); ++ BUG_ON(err == -EINTR); ++ oldfs = get_fs(); ++ set_fs(KERNEL_DS); ++ } ++ } while (i++ < prevent_endless ++ && (err == -EAGAIN || err == -EINTR)); ++ set_fs(oldfs); ++ ++#if 0 /* reserved for future use */ ++ if (err > 0) ++ fsnotify_modify(file->f_dentry); ++#endif ++ ++ return err; ++} ++ ++struct do_xino_fwrite_args { ++ ssize_t *errp; ++ au_writef_t func; ++ struct file *file; ++ void *buf; ++ size_t size; ++ loff_t *pos; ++}; ++ ++static void call_do_xino_fwrite(void *args) ++{ ++ struct do_xino_fwrite_args *a = args; ++ *a->errp = do_xino_fwrite(a->func, a->file, a->buf, a->size, a->pos); ++} ++ ++static ssize_t xino_fwrite_wkq(au_writef_t func, struct file *file, void *buf, ++ size_t size, loff_t *pos) ++{ ++ ssize_t err; ++ int wkq_err; ++ struct do_xino_fwrite_args args = { ++ .errp = &err, ++ .func = func, ++ .file = file, ++ .buf = buf, ++ .size = size, ++ .pos = pos ++ }; ++ ++ /* ++ * it breaks RLIMIT_FSIZE and normal user's limit, ++ * users should care about quota and real 'filesystem full.' ++ */ ++ wkq_err = au_wkq_wait(call_do_xino_fwrite, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ ++ return err; ++} ++ ++ssize_t xino_fwrite(au_writef_t func, struct file *file, void *buf, size_t size, ++ loff_t *pos) ++{ ++ ssize_t err; ++ ++ if (rlimit(RLIMIT_FSIZE) == RLIM_INFINITY) { ++ lockdep_off(); ++ err = do_xino_fwrite(func, file, buf, size, pos); ++ lockdep_on(); ++ } else ++ err = xino_fwrite_wkq(func, file, buf, size, pos); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * create a new xinofile at the same place/path as @base_file. ++ */ ++struct file *au_xino_create2(struct file *base_file, struct file *copy_src) ++{ ++ struct file *file; ++ struct dentry *base, *parent; ++ struct inode *dir, *delegated; ++ struct qstr *name; ++ struct path path; ++ int err; ++ ++ base = base_file->f_dentry; ++ parent = base->d_parent; /* dir inode is locked */ ++ dir = parent->d_inode; ++ IMustLock(dir); ++ ++ file = ERR_PTR(-EINVAL); ++ name = &base->d_name; ++ path.dentry = vfsub_lookup_one_len(name->name, parent, name->len); ++ if (IS_ERR(path.dentry)) { ++ file = (void *)path.dentry; ++ pr_err("%pd lookup err %ld\n", ++ base, PTR_ERR(path.dentry)); ++ goto out; ++ } ++ ++ /* no need to mnt_want_write() since we call dentry_open() later */ ++ err = vfs_create(dir, path.dentry, S_IRUGO | S_IWUGO, NULL); ++ if (unlikely(err)) { ++ file = ERR_PTR(err); ++ pr_err("%pd create err %d\n", base, err); ++ goto out_dput; ++ } ++ ++ path.mnt = base_file->f_path.mnt; ++ file = vfsub_dentry_open(&path, ++ O_RDWR | O_CREAT | O_EXCL | O_LARGEFILE ++ /* | __FMODE_NONOTIFY */); ++ if (IS_ERR(file)) { ++ pr_err("%pd open err %ld\n", base, PTR_ERR(file)); ++ goto out_dput; ++ } ++ ++ delegated = NULL; ++ err = vfsub_unlink(dir, &file->f_path, &delegated, /*force*/0); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ if (unlikely(err)) { ++ pr_err("%pd unlink err %d\n", base, err); ++ goto out_fput; ++ } ++ ++ if (copy_src) { ++ /* no one can touch copy_src xino */ ++ err = au_copy_file(file, copy_src, vfsub_f_size_read(copy_src)); ++ if (unlikely(err)) { ++ pr_err("%pd copy err %d\n", base, err); ++ goto out_fput; ++ } ++ } ++ goto out_dput; /* success */ ++ ++out_fput: ++ fput(file); ++ file = ERR_PTR(err); ++out_dput: ++ dput(path.dentry); ++out: ++ return file; ++} ++ ++struct au_xino_lock_dir { ++ struct au_hinode *hdir; ++ struct dentry *parent; ++ struct mutex *mtx; ++}; ++ ++static void au_xino_lock_dir(struct super_block *sb, struct file *xino, ++ struct au_xino_lock_dir *ldir) ++{ ++ aufs_bindex_t brid, bindex; ++ ++ ldir->hdir = NULL; ++ bindex = -1; ++ brid = au_xino_brid(sb); ++ if (brid >= 0) ++ bindex = au_br_index(sb, brid); ++ if (bindex >= 0) { ++ ldir->hdir = au_hi(sb->s_root->d_inode, bindex); ++ au_hn_imtx_lock_nested(ldir->hdir, AuLsc_I_PARENT); ++ } else { ++ ldir->parent = dget_parent(xino->f_dentry); ++ ldir->mtx = &ldir->parent->d_inode->i_mutex; ++ mutex_lock_nested(ldir->mtx, AuLsc_I_PARENT); ++ } ++} ++ ++static void au_xino_unlock_dir(struct au_xino_lock_dir *ldir) ++{ ++ if (ldir->hdir) ++ au_hn_imtx_unlock(ldir->hdir); ++ else { ++ mutex_unlock(ldir->mtx); ++ dput(ldir->parent); ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* trucate xino files asynchronously */ ++ ++int au_xino_trunc(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ int err; ++ unsigned long jiffy; ++ blkcnt_t blocks; ++ aufs_bindex_t bi, bend; ++ struct kstatfs *st; ++ struct au_branch *br; ++ struct file *new_xino, *file; ++ struct super_block *h_sb; ++ struct au_xino_lock_dir ldir; ++ ++ err = -ENOMEM; ++ st = kmalloc(sizeof(*st), GFP_NOFS); ++ if (unlikely(!st)) ++ goto out; ++ ++ err = -EINVAL; ++ bend = au_sbend(sb); ++ if (unlikely(bindex < 0 || bend < bindex)) ++ goto out_st; ++ br = au_sbr(sb, bindex); ++ file = br->br_xino.xi_file; ++ if (!file) ++ goto out_st; ++ ++ err = vfs_statfs(&file->f_path, st); ++ if (unlikely(err)) ++ AuErr1("statfs err %d, ignored\n", err); ++ jiffy = jiffies; ++ blocks = file_inode(file)->i_blocks; ++ pr_info("begin truncating xino(b%d), ib%llu, %llu/%llu free blks\n", ++ bindex, (u64)blocks, st->f_bfree, st->f_blocks); ++ ++ au_xino_lock_dir(sb, file, &ldir); ++ /* mnt_want_write() is unnecessary here */ ++ new_xino = au_xino_create2(file, file); ++ au_xino_unlock_dir(&ldir); ++ err = PTR_ERR(new_xino); ++ if (IS_ERR(new_xino)) { ++ pr_err("err %d, ignored\n", err); ++ goto out_st; ++ } ++ err = 0; ++ fput(file); ++ br->br_xino.xi_file = new_xino; ++ ++ h_sb = au_br_sb(br); ++ for (bi = 0; bi <= bend; bi++) { ++ if (unlikely(bi == bindex)) ++ continue; ++ br = au_sbr(sb, bi); ++ if (au_br_sb(br) != h_sb) ++ continue; ++ ++ fput(br->br_xino.xi_file); ++ br->br_xino.xi_file = new_xino; ++ get_file(new_xino); ++ } ++ ++ err = vfs_statfs(&new_xino->f_path, st); ++ if (!err) { ++ pr_info("end truncating xino(b%d), ib%llu, %llu/%llu free blks\n", ++ bindex, (u64)file_inode(new_xino)->i_blocks, ++ st->f_bfree, st->f_blocks); ++ if (file_inode(new_xino)->i_blocks < blocks) ++ au_sbi(sb)->si_xino_jiffy = jiffy; ++ } else ++ AuErr1("statfs err %d, ignored\n", err); ++ ++out_st: ++ kfree(st); ++out: ++ return err; ++} ++ ++struct xino_do_trunc_args { ++ struct super_block *sb; ++ struct au_branch *br; ++}; ++ ++static void xino_do_trunc(void *_args) ++{ ++ struct xino_do_trunc_args *args = _args; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct inode *dir; ++ int err; ++ aufs_bindex_t bindex; ++ ++ err = 0; ++ sb = args->sb; ++ dir = sb->s_root->d_inode; ++ br = args->br; ++ ++ si_noflush_write_lock(sb); ++ ii_read_lock_parent(dir); ++ bindex = au_br_index(sb, br->br_id); ++ err = au_xino_trunc(sb, bindex); ++ ii_read_unlock(dir); ++ if (unlikely(err)) ++ pr_warn("err b%d, (%d)\n", bindex, err); ++ atomic_dec(&br->br_xino_running); ++ atomic_dec(&br->br_count); ++ si_write_unlock(sb); ++ au_nwt_done(&au_sbi(sb)->si_nowait); ++ kfree(args); ++} ++ ++static int xino_trunc_test(struct super_block *sb, struct au_branch *br) ++{ ++ int err; ++ struct kstatfs st; ++ struct au_sbinfo *sbinfo; ++ ++ /* todo: si_xino_expire and the ratio should be customizable */ ++ sbinfo = au_sbi(sb); ++ if (time_before(jiffies, ++ sbinfo->si_xino_jiffy + sbinfo->si_xino_expire)) ++ return 0; ++ ++ /* truncation border */ ++ err = vfs_statfs(&br->br_xino.xi_file->f_path, &st); ++ if (unlikely(err)) { ++ AuErr1("statfs err %d, ignored\n", err); ++ return 0; ++ } ++ if (div64_u64(st.f_bfree * 100, st.f_blocks) >= AUFS_XINO_DEF_TRUNC) ++ return 0; ++ ++ return 1; ++} ++ ++static void xino_try_trunc(struct super_block *sb, struct au_branch *br) ++{ ++ struct xino_do_trunc_args *args; ++ int wkq_err; ++ ++ if (!xino_trunc_test(sb, br)) ++ return; ++ ++ if (atomic_inc_return(&br->br_xino_running) > 1) ++ goto out; ++ ++ /* lock and kfree() will be called in trunc_xino() */ ++ args = kmalloc(sizeof(*args), GFP_NOFS); ++ if (unlikely(!args)) { ++ AuErr1("no memory\n"); ++ goto out_args; ++ } ++ ++ atomic_inc(&br->br_count); ++ args->sb = sb; ++ args->br = br; ++ wkq_err = au_wkq_nowait(xino_do_trunc, args, sb, /*flags*/0); ++ if (!wkq_err) ++ return; /* success */ ++ ++ pr_err("wkq %d\n", wkq_err); ++ atomic_dec(&br->br_count); ++ ++out_args: ++ kfree(args); ++out: ++ atomic_dec(&br->br_xino_running); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_xino_do_write(au_writef_t write, struct file *file, ++ ino_t h_ino, ino_t ino) ++{ ++ loff_t pos; ++ ssize_t sz; ++ ++ pos = h_ino; ++ if (unlikely(au_loff_max / sizeof(ino) - 1 < pos)) { ++ AuIOErr1("too large hi%lu\n", (unsigned long)h_ino); ++ return -EFBIG; ++ } ++ pos *= sizeof(ino); ++ sz = xino_fwrite(write, file, &ino, sizeof(ino), &pos); ++ if (sz == sizeof(ino)) ++ return 0; /* success */ ++ ++ AuIOErr("write failed (%zd)\n", sz); ++ return -EIO; ++} ++ ++/* ++ * write @ino to the xinofile for the specified branch{@sb, @bindex} ++ * at the position of @h_ino. ++ * even if @ino is zero, it is written to the xinofile and means no entry. ++ * if the size of the xino file on a specific filesystem exceeds the watermark, ++ * try truncating it. ++ */ ++int au_xino_write(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ ino_t ino) ++{ ++ int err; ++ unsigned int mnt_flags; ++ struct au_branch *br; ++ ++ BUILD_BUG_ON(sizeof(long long) != sizeof(au_loff_max) ++ || ((loff_t)-1) > 0); ++ SiMustAnyLock(sb); ++ ++ mnt_flags = au_mntflags(sb); ++ if (!au_opt_test(mnt_flags, XINO)) ++ return 0; ++ ++ br = au_sbr(sb, bindex); ++ err = au_xino_do_write(au_sbi(sb)->si_xwrite, br->br_xino.xi_file, ++ h_ino, ino); ++ if (!err) { ++ if (au_opt_test(mnt_flags, TRUNC_XINO) ++ && au_test_fs_trunc_xino(au_br_sb(br))) ++ xino_try_trunc(sb, br); ++ return 0; /* success */ ++ } ++ ++ AuIOErr("write failed (%d)\n", err); ++ return -EIO; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* aufs inode number bitmap */ ++ ++static const int page_bits = (int)PAGE_SIZE * BITS_PER_BYTE; ++static ino_t xib_calc_ino(unsigned long pindex, int bit) ++{ ++ ino_t ino; ++ ++ AuDebugOn(bit < 0 || page_bits <= bit); ++ ino = AUFS_FIRST_INO + pindex * page_bits + bit; ++ return ino; ++} ++ ++static void xib_calc_bit(ino_t ino, unsigned long *pindex, int *bit) ++{ ++ AuDebugOn(ino < AUFS_FIRST_INO); ++ ino -= AUFS_FIRST_INO; ++ *pindex = ino / page_bits; ++ *bit = ino % page_bits; ++} ++ ++static int xib_pindex(struct super_block *sb, unsigned long pindex) ++{ ++ int err; ++ loff_t pos; ++ ssize_t sz; ++ struct au_sbinfo *sbinfo; ++ struct file *xib; ++ unsigned long *p; ++ ++ sbinfo = au_sbi(sb); ++ MtxMustLock(&sbinfo->si_xib_mtx); ++ AuDebugOn(pindex > ULONG_MAX / PAGE_SIZE ++ || !au_opt_test(sbinfo->si_mntflags, XINO)); ++ ++ if (pindex == sbinfo->si_xib_last_pindex) ++ return 0; ++ ++ xib = sbinfo->si_xib; ++ p = sbinfo->si_xib_buf; ++ pos = sbinfo->si_xib_last_pindex; ++ pos *= PAGE_SIZE; ++ sz = xino_fwrite(sbinfo->si_xwrite, xib, p, PAGE_SIZE, &pos); ++ if (unlikely(sz != PAGE_SIZE)) ++ goto out; ++ ++ pos = pindex; ++ pos *= PAGE_SIZE; ++ if (vfsub_f_size_read(xib) >= pos + PAGE_SIZE) ++ sz = xino_fread(sbinfo->si_xread, xib, p, PAGE_SIZE, &pos); ++ else { ++ memset(p, 0, PAGE_SIZE); ++ sz = xino_fwrite(sbinfo->si_xwrite, xib, p, PAGE_SIZE, &pos); ++ } ++ if (sz == PAGE_SIZE) { ++ sbinfo->si_xib_last_pindex = pindex; ++ return 0; /* success */ ++ } ++ ++out: ++ AuIOErr1("write failed (%zd)\n", sz); ++ err = sz; ++ if (sz >= 0) ++ err = -EIO; ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_xib_clear_bit(struct inode *inode) ++{ ++ int err, bit; ++ unsigned long pindex; ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ ++ AuDebugOn(inode->i_nlink); ++ ++ sb = inode->i_sb; ++ xib_calc_bit(inode->i_ino, &pindex, &bit); ++ AuDebugOn(page_bits <= bit); ++ sbinfo = au_sbi(sb); ++ mutex_lock(&sbinfo->si_xib_mtx); ++ err = xib_pindex(sb, pindex); ++ if (!err) { ++ clear_bit(bit, sbinfo->si_xib_buf); ++ sbinfo->si_xib_next_bit = bit; ++ } ++ mutex_unlock(&sbinfo->si_xib_mtx); ++} ++ ++/* for s_op->delete_inode() */ ++void au_xino_delete_inode(struct inode *inode, const int unlinked) ++{ ++ int err; ++ unsigned int mnt_flags; ++ aufs_bindex_t bindex, bend, bi; ++ unsigned char try_trunc; ++ struct au_iinfo *iinfo; ++ struct super_block *sb; ++ struct au_hinode *hi; ++ struct inode *h_inode; ++ struct au_branch *br; ++ au_writef_t xwrite; ++ ++ sb = inode->i_sb; ++ mnt_flags = au_mntflags(sb); ++ if (!au_opt_test(mnt_flags, XINO) ++ || inode->i_ino == AUFS_ROOT_INO) ++ return; ++ ++ if (unlinked) { ++ au_xigen_inc(inode); ++ au_xib_clear_bit(inode); ++ } ++ ++ iinfo = au_ii(inode); ++ if (!iinfo) ++ return; ++ ++ bindex = iinfo->ii_bstart; ++ if (bindex < 0) ++ return; ++ ++ xwrite = au_sbi(sb)->si_xwrite; ++ try_trunc = !!au_opt_test(mnt_flags, TRUNC_XINO); ++ hi = iinfo->ii_hinode + bindex; ++ bend = iinfo->ii_bend; ++ for (; bindex <= bend; bindex++, hi++) { ++ h_inode = hi->hi_inode; ++ if (!h_inode ++ || (!unlinked && h_inode->i_nlink)) ++ continue; ++ ++ /* inode may not be revalidated */ ++ bi = au_br_index(sb, hi->hi_id); ++ if (bi < 0) ++ continue; ++ ++ br = au_sbr(sb, bi); ++ err = au_xino_do_write(xwrite, br->br_xino.xi_file, ++ h_inode->i_ino, /*ino*/0); ++ if (!err && try_trunc ++ && au_test_fs_trunc_xino(au_br_sb(br))) ++ xino_try_trunc(sb, br); ++ } ++} ++ ++/* get an unused inode number from bitmap */ ++ino_t au_xino_new_ino(struct super_block *sb) ++{ ++ ino_t ino; ++ unsigned long *p, pindex, ul, pend; ++ struct au_sbinfo *sbinfo; ++ struct file *file; ++ int free_bit, err; ++ ++ if (!au_opt_test(au_mntflags(sb), XINO)) ++ return iunique(sb, AUFS_FIRST_INO); ++ ++ sbinfo = au_sbi(sb); ++ mutex_lock(&sbinfo->si_xib_mtx); ++ p = sbinfo->si_xib_buf; ++ free_bit = sbinfo->si_xib_next_bit; ++ if (free_bit < page_bits && !test_bit(free_bit, p)) ++ goto out; /* success */ ++ free_bit = find_first_zero_bit(p, page_bits); ++ if (free_bit < page_bits) ++ goto out; /* success */ ++ ++ pindex = sbinfo->si_xib_last_pindex; ++ for (ul = pindex - 1; ul < ULONG_MAX; ul--) { ++ err = xib_pindex(sb, ul); ++ if (unlikely(err)) ++ goto out_err; ++ free_bit = find_first_zero_bit(p, page_bits); ++ if (free_bit < page_bits) ++ goto out; /* success */ ++ } ++ ++ file = sbinfo->si_xib; ++ pend = vfsub_f_size_read(file) / PAGE_SIZE; ++ for (ul = pindex + 1; ul <= pend; ul++) { ++ err = xib_pindex(sb, ul); ++ if (unlikely(err)) ++ goto out_err; ++ free_bit = find_first_zero_bit(p, page_bits); ++ if (free_bit < page_bits) ++ goto out; /* success */ ++ } ++ BUG(); ++ ++out: ++ set_bit(free_bit, p); ++ sbinfo->si_xib_next_bit = free_bit + 1; ++ pindex = sbinfo->si_xib_last_pindex; ++ mutex_unlock(&sbinfo->si_xib_mtx); ++ ino = xib_calc_ino(pindex, free_bit); ++ AuDbg("i%lu\n", (unsigned long)ino); ++ return ino; ++out_err: ++ mutex_unlock(&sbinfo->si_xib_mtx); ++ AuDbg("i0\n"); ++ return 0; ++} ++ ++/* ++ * read @ino from xinofile for the specified branch{@sb, @bindex} ++ * at the position of @h_ino. ++ * if @ino does not exist and @do_new is true, get new one. ++ */ ++int au_xino_read(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ ino_t *ino) ++{ ++ int err; ++ ssize_t sz; ++ loff_t pos; ++ struct file *file; ++ struct au_sbinfo *sbinfo; ++ ++ *ino = 0; ++ if (!au_opt_test(au_mntflags(sb), XINO)) ++ return 0; /* no xino */ ++ ++ err = 0; ++ sbinfo = au_sbi(sb); ++ pos = h_ino; ++ if (unlikely(au_loff_max / sizeof(*ino) - 1 < pos)) { ++ AuIOErr1("too large hi%lu\n", (unsigned long)h_ino); ++ return -EFBIG; ++ } ++ pos *= sizeof(*ino); ++ ++ file = au_sbr(sb, bindex)->br_xino.xi_file; ++ if (vfsub_f_size_read(file) < pos + sizeof(*ino)) ++ return 0; /* no ino */ ++ ++ sz = xino_fread(sbinfo->si_xread, file, ino, sizeof(*ino), &pos); ++ if (sz == sizeof(*ino)) ++ return 0; /* success */ ++ ++ err = sz; ++ if (unlikely(sz >= 0)) { ++ err = -EIO; ++ AuIOErr("xino read error (%zd)\n", sz); ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* create and set a new xino file */ ++ ++struct file *au_xino_create(struct super_block *sb, char *fname, int silent) ++{ ++ struct file *file; ++ struct dentry *h_parent, *d; ++ struct inode *h_dir, *inode; ++ int err; ++ ++ /* ++ * at mount-time, and the xino file is the default path, ++ * hnotify is disabled so we have no notify events to ignore. ++ * when a user specified the xino, we cannot get au_hdir to be ignored. ++ */ ++ file = vfsub_filp_open(fname, O_RDWR | O_CREAT | O_EXCL | O_LARGEFILE ++ /* | __FMODE_NONOTIFY */, ++ S_IRUGO | S_IWUGO); ++ if (IS_ERR(file)) { ++ if (!silent) ++ pr_err("open %s(%ld)\n", fname, PTR_ERR(file)); ++ return file; ++ } ++ ++ /* keep file count */ ++ err = 0; ++ inode = file_inode(file); ++ h_parent = dget_parent(file->f_dentry); ++ h_dir = h_parent->d_inode; ++ mutex_lock_nested(&h_dir->i_mutex, AuLsc_I_PARENT); ++ /* mnt_want_write() is unnecessary here */ ++ /* no delegation since it is just created */ ++ if (inode->i_nlink) ++ err = vfsub_unlink(h_dir, &file->f_path, /*delegated*/NULL, ++ /*force*/0); ++ mutex_unlock(&h_dir->i_mutex); ++ dput(h_parent); ++ if (unlikely(err)) { ++ if (!silent) ++ pr_err("unlink %s(%d)\n", fname, err); ++ goto out; ++ } ++ ++ err = -EINVAL; ++ d = file->f_dentry; ++ if (unlikely(sb == d->d_sb)) { ++ if (!silent) ++ pr_err("%s must be outside\n", fname); ++ goto out; ++ } ++ if (unlikely(au_test_fs_bad_xino(d->d_sb))) { ++ if (!silent) ++ pr_err("xino doesn't support %s(%s)\n", ++ fname, au_sbtype(d->d_sb)); ++ goto out; ++ } ++ return file; /* success */ ++ ++out: ++ fput(file); ++ file = ERR_PTR(err); ++ return file; ++} ++ ++/* ++ * find another branch who is on the same filesystem of the specified ++ * branch{@btgt}. search until @bend. ++ */ ++static int is_sb_shared(struct super_block *sb, aufs_bindex_t btgt, ++ aufs_bindex_t bend) ++{ ++ aufs_bindex_t bindex; ++ struct super_block *tgt_sb = au_sbr_sb(sb, btgt); ++ ++ for (bindex = 0; bindex < btgt; bindex++) ++ if (unlikely(tgt_sb == au_sbr_sb(sb, bindex))) ++ return bindex; ++ for (bindex++; bindex <= bend; bindex++) ++ if (unlikely(tgt_sb == au_sbr_sb(sb, bindex))) ++ return bindex; ++ return -1; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * initialize the xinofile for the specified branch @br ++ * at the place/path where @base_file indicates. ++ * test whether another branch is on the same filesystem or not, ++ * if @do_test is true. ++ */ ++int au_xino_br(struct super_block *sb, struct au_branch *br, ino_t h_ino, ++ struct file *base_file, int do_test) ++{ ++ int err; ++ ino_t ino; ++ aufs_bindex_t bend, bindex; ++ struct au_branch *shared_br, *b; ++ struct file *file; ++ struct super_block *tgt_sb; ++ ++ shared_br = NULL; ++ bend = au_sbend(sb); ++ if (do_test) { ++ tgt_sb = au_br_sb(br); ++ for (bindex = 0; bindex <= bend; bindex++) { ++ b = au_sbr(sb, bindex); ++ if (tgt_sb == au_br_sb(b)) { ++ shared_br = b; ++ break; ++ } ++ } ++ } ++ ++ if (!shared_br || !shared_br->br_xino.xi_file) { ++ struct au_xino_lock_dir ldir; ++ ++ au_xino_lock_dir(sb, base_file, &ldir); ++ /* mnt_want_write() is unnecessary here */ ++ file = au_xino_create2(base_file, NULL); ++ au_xino_unlock_dir(&ldir); ++ err = PTR_ERR(file); ++ if (IS_ERR(file)) ++ goto out; ++ br->br_xino.xi_file = file; ++ } else { ++ br->br_xino.xi_file = shared_br->br_xino.xi_file; ++ get_file(br->br_xino.xi_file); ++ } ++ ++ ino = AUFS_ROOT_INO; ++ err = au_xino_do_write(au_sbi(sb)->si_xwrite, br->br_xino.xi_file, ++ h_ino, ino); ++ if (unlikely(err)) { ++ fput(br->br_xino.xi_file); ++ br->br_xino.xi_file = NULL; ++ } ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* trucate a xino bitmap file */ ++ ++/* todo: slow */ ++static int do_xib_restore(struct super_block *sb, struct file *file, void *page) ++{ ++ int err, bit; ++ ssize_t sz; ++ unsigned long pindex; ++ loff_t pos, pend; ++ struct au_sbinfo *sbinfo; ++ au_readf_t func; ++ ino_t *ino; ++ unsigned long *p; ++ ++ err = 0; ++ sbinfo = au_sbi(sb); ++ MtxMustLock(&sbinfo->si_xib_mtx); ++ p = sbinfo->si_xib_buf; ++ func = sbinfo->si_xread; ++ pend = vfsub_f_size_read(file); ++ pos = 0; ++ while (pos < pend) { ++ sz = xino_fread(func, file, page, PAGE_SIZE, &pos); ++ err = sz; ++ if (unlikely(sz <= 0)) ++ goto out; ++ ++ err = 0; ++ for (ino = page; sz > 0; ino++, sz -= sizeof(ino)) { ++ if (unlikely(*ino < AUFS_FIRST_INO)) ++ continue; ++ ++ xib_calc_bit(*ino, &pindex, &bit); ++ AuDebugOn(page_bits <= bit); ++ err = xib_pindex(sb, pindex); ++ if (!err) ++ set_bit(bit, p); ++ else ++ goto out; ++ } ++ } ++ ++out: ++ return err; ++} ++ ++static int xib_restore(struct super_block *sb) ++{ ++ int err; ++ aufs_bindex_t bindex, bend; ++ void *page; ++ ++ err = -ENOMEM; ++ page = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!page)) ++ goto out; ++ ++ err = 0; ++ bend = au_sbend(sb); ++ for (bindex = 0; !err && bindex <= bend; bindex++) ++ if (!bindex || is_sb_shared(sb, bindex, bindex - 1) < 0) ++ err = do_xib_restore ++ (sb, au_sbr(sb, bindex)->br_xino.xi_file, page); ++ else ++ AuDbg("b%d\n", bindex); ++ free_page((unsigned long)page); ++ ++out: ++ return err; ++} ++ ++int au_xib_trunc(struct super_block *sb) ++{ ++ int err; ++ ssize_t sz; ++ loff_t pos; ++ struct au_xino_lock_dir ldir; ++ struct au_sbinfo *sbinfo; ++ unsigned long *p; ++ struct file *file; ++ ++ SiMustWriteLock(sb); ++ ++ err = 0; ++ sbinfo = au_sbi(sb); ++ if (!au_opt_test(sbinfo->si_mntflags, XINO)) ++ goto out; ++ ++ file = sbinfo->si_xib; ++ if (vfsub_f_size_read(file) <= PAGE_SIZE) ++ goto out; ++ ++ au_xino_lock_dir(sb, file, &ldir); ++ /* mnt_want_write() is unnecessary here */ ++ file = au_xino_create2(sbinfo->si_xib, NULL); ++ au_xino_unlock_dir(&ldir); ++ err = PTR_ERR(file); ++ if (IS_ERR(file)) ++ goto out; ++ fput(sbinfo->si_xib); ++ sbinfo->si_xib = file; ++ ++ p = sbinfo->si_xib_buf; ++ memset(p, 0, PAGE_SIZE); ++ pos = 0; ++ sz = xino_fwrite(sbinfo->si_xwrite, sbinfo->si_xib, p, PAGE_SIZE, &pos); ++ if (unlikely(sz != PAGE_SIZE)) { ++ err = sz; ++ AuIOErr("err %d\n", err); ++ if (sz >= 0) ++ err = -EIO; ++ goto out; ++ } ++ ++ mutex_lock(&sbinfo->si_xib_mtx); ++ /* mnt_want_write() is unnecessary here */ ++ err = xib_restore(sb); ++ mutex_unlock(&sbinfo->si_xib_mtx); ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * xino mount option handlers ++ */ ++static au_readf_t find_readf(struct file *h_file) ++{ ++ const struct file_operations *fop = h_file->f_op; ++ ++ if (fop->read) ++ return fop->read; ++ if (fop->aio_read) ++ return do_sync_read; ++ if (fop->read_iter) ++ return new_sync_read; ++ return ERR_PTR(-ENOSYS); ++} ++ ++static au_writef_t find_writef(struct file *h_file) ++{ ++ const struct file_operations *fop = h_file->f_op; ++ ++ if (fop->write) ++ return fop->write; ++ if (fop->aio_write) ++ return do_sync_write; ++ if (fop->write_iter) ++ return new_sync_write; ++ return ERR_PTR(-ENOSYS); ++} ++ ++/* xino bitmap */ ++static void xino_clear_xib(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ sbinfo->si_xread = NULL; ++ sbinfo->si_xwrite = NULL; ++ if (sbinfo->si_xib) ++ fput(sbinfo->si_xib); ++ sbinfo->si_xib = NULL; ++ free_page((unsigned long)sbinfo->si_xib_buf); ++ sbinfo->si_xib_buf = NULL; ++} ++ ++static int au_xino_set_xib(struct super_block *sb, struct file *base) ++{ ++ int err; ++ loff_t pos; ++ struct au_sbinfo *sbinfo; ++ struct file *file; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ file = au_xino_create2(base, sbinfo->si_xib); ++ err = PTR_ERR(file); ++ if (IS_ERR(file)) ++ goto out; ++ if (sbinfo->si_xib) ++ fput(sbinfo->si_xib); ++ sbinfo->si_xib = file; ++ sbinfo->si_xread = find_readf(file); ++ sbinfo->si_xwrite = find_writef(file); ++ ++ err = -ENOMEM; ++ if (!sbinfo->si_xib_buf) ++ sbinfo->si_xib_buf = (void *)get_zeroed_page(GFP_NOFS); ++ if (unlikely(!sbinfo->si_xib_buf)) ++ goto out_unset; ++ ++ sbinfo->si_xib_last_pindex = 0; ++ sbinfo->si_xib_next_bit = 0; ++ if (vfsub_f_size_read(file) < PAGE_SIZE) { ++ pos = 0; ++ err = xino_fwrite(sbinfo->si_xwrite, file, sbinfo->si_xib_buf, ++ PAGE_SIZE, &pos); ++ if (unlikely(err != PAGE_SIZE)) ++ goto out_free; ++ } ++ err = 0; ++ goto out; /* success */ ++ ++out_free: ++ free_page((unsigned long)sbinfo->si_xib_buf); ++ sbinfo->si_xib_buf = NULL; ++ if (err >= 0) ++ err = -EIO; ++out_unset: ++ fput(sbinfo->si_xib); ++ sbinfo->si_xib = NULL; ++ sbinfo->si_xread = NULL; ++ sbinfo->si_xwrite = NULL; ++out: ++ return err; ++} ++ ++/* xino for each branch */ ++static void xino_clear_br(struct super_block *sb) ++{ ++ aufs_bindex_t bindex, bend; ++ struct au_branch *br; ++ ++ bend = au_sbend(sb); ++ for (bindex = 0; bindex <= bend; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (!br || !br->br_xino.xi_file) ++ continue; ++ ++ fput(br->br_xino.xi_file); ++ br->br_xino.xi_file = NULL; ++ } ++} ++ ++static int au_xino_set_br(struct super_block *sb, struct file *base) ++{ ++ int err; ++ ino_t ino; ++ aufs_bindex_t bindex, bend, bshared; ++ struct { ++ struct file *old, *new; ++ } *fpair, *p; ++ struct au_branch *br; ++ struct inode *inode; ++ au_writef_t writef; ++ ++ SiMustWriteLock(sb); ++ ++ err = -ENOMEM; ++ bend = au_sbend(sb); ++ fpair = kcalloc(bend + 1, sizeof(*fpair), GFP_NOFS); ++ if (unlikely(!fpair)) ++ goto out; ++ ++ inode = sb->s_root->d_inode; ++ ino = AUFS_ROOT_INO; ++ writef = au_sbi(sb)->si_xwrite; ++ for (bindex = 0, p = fpair; bindex <= bend; bindex++, p++) { ++ br = au_sbr(sb, bindex); ++ bshared = is_sb_shared(sb, bindex, bindex - 1); ++ if (bshared >= 0) { ++ /* shared xino */ ++ *p = fpair[bshared]; ++ get_file(p->new); ++ } ++ ++ if (!p->new) { ++ /* new xino */ ++ p->old = br->br_xino.xi_file; ++ p->new = au_xino_create2(base, br->br_xino.xi_file); ++ err = PTR_ERR(p->new); ++ if (IS_ERR(p->new)) { ++ p->new = NULL; ++ goto out_pair; ++ } ++ } ++ ++ err = au_xino_do_write(writef, p->new, ++ au_h_iptr(inode, bindex)->i_ino, ino); ++ if (unlikely(err)) ++ goto out_pair; ++ } ++ ++ for (bindex = 0, p = fpair; bindex <= bend; bindex++, p++) { ++ br = au_sbr(sb, bindex); ++ if (br->br_xino.xi_file) ++ fput(br->br_xino.xi_file); ++ get_file(p->new); ++ br->br_xino.xi_file = p->new; ++ } ++ ++out_pair: ++ for (bindex = 0, p = fpair; bindex <= bend; bindex++, p++) ++ if (p->new) ++ fput(p->new); ++ else ++ break; ++ kfree(fpair); ++out: ++ return err; ++} ++ ++void au_xino_clr(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ ++ au_xigen_clr(sb); ++ xino_clear_xib(sb); ++ xino_clear_br(sb); ++ sbinfo = au_sbi(sb); ++ /* lvalue, do not call au_mntflags() */ ++ au_opt_clr(sbinfo->si_mntflags, XINO); ++} ++ ++int au_xino_set(struct super_block *sb, struct au_opt_xino *xino, int remount) ++{ ++ int err, skip; ++ struct dentry *parent, *cur_parent; ++ struct qstr *dname, *cur_name; ++ struct file *cur_xino; ++ struct inode *dir; ++ struct au_sbinfo *sbinfo; ++ ++ SiMustWriteLock(sb); ++ ++ err = 0; ++ sbinfo = au_sbi(sb); ++ parent = dget_parent(xino->file->f_dentry); ++ if (remount) { ++ skip = 0; ++ dname = &xino->file->f_dentry->d_name; ++ cur_xino = sbinfo->si_xib; ++ if (cur_xino) { ++ cur_parent = dget_parent(cur_xino->f_dentry); ++ cur_name = &cur_xino->f_dentry->d_name; ++ skip = (cur_parent == parent ++ && au_qstreq(dname, cur_name)); ++ dput(cur_parent); ++ } ++ if (skip) ++ goto out; ++ } ++ ++ au_opt_set(sbinfo->si_mntflags, XINO); ++ dir = parent->d_inode; ++ mutex_lock_nested(&dir->i_mutex, AuLsc_I_PARENT); ++ /* mnt_want_write() is unnecessary here */ ++ err = au_xino_set_xib(sb, xino->file); ++ if (!err) ++ err = au_xigen_set(sb, xino->file); ++ if (!err) ++ err = au_xino_set_br(sb, xino->file); ++ mutex_unlock(&dir->i_mutex); ++ if (!err) ++ goto out; /* success */ ++ ++ /* reset all */ ++ AuIOErr("failed creating xino(%d).\n", err); ++ au_xigen_clr(sb); ++ xino_clear_xib(sb); ++ ++out: ++ dput(parent); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * create a xinofile at the default place/path. ++ */ ++struct file *au_xino_def(struct super_block *sb) ++{ ++ struct file *file; ++ char *page, *p; ++ struct au_branch *br; ++ struct super_block *h_sb; ++ struct path path; ++ aufs_bindex_t bend, bindex, bwr; ++ ++ br = NULL; ++ bend = au_sbend(sb); ++ bwr = -1; ++ for (bindex = 0; bindex <= bend; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (au_br_writable(br->br_perm) ++ && !au_test_fs_bad_xino(au_br_sb(br))) { ++ bwr = bindex; ++ break; ++ } ++ } ++ ++ if (bwr >= 0) { ++ file = ERR_PTR(-ENOMEM); ++ page = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!page)) ++ goto out; ++ path.mnt = au_br_mnt(br); ++ path.dentry = au_h_dptr(sb->s_root, bwr); ++ p = d_path(&path, page, PATH_MAX - sizeof(AUFS_XINO_FNAME)); ++ file = (void *)p; ++ if (!IS_ERR(p)) { ++ strcat(p, "/" AUFS_XINO_FNAME); ++ AuDbg("%s\n", p); ++ file = au_xino_create(sb, p, /*silent*/0); ++ if (!IS_ERR(file)) ++ au_xino_brid_set(sb, br->br_id); ++ } ++ free_page((unsigned long)page); ++ } else { ++ file = au_xino_create(sb, AUFS_XINO_DEFPATH, /*silent*/0); ++ if (IS_ERR(file)) ++ goto out; ++ h_sb = file->f_dentry->d_sb; ++ if (unlikely(au_test_fs_bad_xino(h_sb))) { ++ pr_err("xino doesn't support %s(%s)\n", ++ AUFS_XINO_DEFPATH, au_sbtype(h_sb)); ++ fput(file); ++ file = ERR_PTR(-EINVAL); ++ } ++ if (!IS_ERR(file)) ++ au_xino_brid_set(sb, -1); ++ } ++ ++out: ++ return file; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_xino_path(struct seq_file *seq, struct file *file) ++{ ++ int err; ++ ++ err = au_seq_path(seq, &file->f_path); ++ if (unlikely(err)) ++ goto out; ++ ++#define Deleted "\\040(deleted)" ++ seq->count -= sizeof(Deleted) - 1; ++ AuDebugOn(memcmp(seq->buf + seq->count, Deleted, ++ sizeof(Deleted) - 1)); ++#undef Deleted ++ ++out: ++ return err; ++} +diff --git a/fs/buffer.c b/fs/buffer.c +index 20805db..363569f 100644 +--- a/fs/buffer.c ++++ b/fs/buffer.c +@@ -2450,7 +2450,7 @@ int block_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf, + * Update file times before taking page lock. We may end up failing the + * fault so this update may be superfluous but who really cares... + */ +- file_update_time(vma->vm_file); ++ vma_file_update_time(vma); + + ret = __block_page_mkwrite(vma, vmf, get_block); + sb_end_pagefault(sb); +diff --git a/fs/dcache.c b/fs/dcache.c +index d25f8fd..857990a 100644 +--- a/fs/dcache.c ++++ b/fs/dcache.c +@@ -1022,7 +1022,7 @@ enum d_walk_ret { + * + * The @enter() and @finish() callbacks are called with d_lock held. + */ +-static void d_walk(struct dentry *parent, void *data, ++void d_walk(struct dentry *parent, void *data, + enum d_walk_ret (*enter)(void *, struct dentry *), + void (*finish)(void *)) + { +diff --git a/fs/fcntl.c b/fs/fcntl.c +index 99d440a..de1a407 100644 +--- a/fs/fcntl.c ++++ b/fs/fcntl.c +@@ -29,7 +29,7 @@ + + #define SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | O_DIRECT | O_NOATIME) + +-static int setfl(int fd, struct file * filp, unsigned long arg) ++int setfl(int fd, struct file * filp, unsigned long arg) + { + struct inode * inode = file_inode(filp); + int error = 0; +@@ -59,6 +59,8 @@ static int setfl(int fd, struct file * filp, unsigned long arg) + + if (filp->f_op->check_flags) + error = filp->f_op->check_flags(arg); ++ if (!error && filp->f_op->setfl) ++ error = filp->f_op->setfl(filp, arg); + if (error) + return error; + +diff --git a/fs/inode.c b/fs/inode.c +index 56d1d2b..2998e86 100644 +--- a/fs/inode.c ++++ b/fs/inode.c +@@ -1497,7 +1497,7 @@ static int relatime_need_update(struct vfsmount *mnt, struct inode *inode, + * This does the actual work of updating an inodes time or version. Must have + * had called mnt_want_write() before calling this. + */ +-static int update_time(struct inode *inode, struct timespec *time, int flags) ++int update_time(struct inode *inode, struct timespec *time, int flags) + { + if (inode->i_op->update_time) + return inode->i_op->update_time(inode, time, flags); +diff --git a/fs/proc/base.c b/fs/proc/base.c +index 7dc3ea8..b368ad5 100644 +--- a/fs/proc/base.c ++++ b/fs/proc/base.c +@@ -1735,7 +1735,7 @@ static int proc_map_files_get_link(struct dentry *dentry, struct path *path) + down_read(&mm->mmap_sem); + vma = find_exact_vma(mm, vm_start, vm_end); + if (vma && vma->vm_file) { +- *path = vma->vm_file->f_path; ++ *path = vma_pr_or_file(vma)->f_path; + path_get(path); + rc = 0; + } +diff --git a/fs/proc/nommu.c b/fs/proc/nommu.c +index d4a3574..1397181 100644 +--- a/fs/proc/nommu.c ++++ b/fs/proc/nommu.c +@@ -45,7 +45,10 @@ static int nommu_region_show(struct seq_file *m, struct vm_region *region) + file = region->vm_file; + + if (file) { +- struct inode *inode = file_inode(region->vm_file); ++ struct inode *inode; ++ ++ file = vmr_pr_or_file(region); ++ inode = file_inode(file); + dev = inode->i_sb->s_dev; + ino = inode->i_ino; + } +diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c +index 69aa378..426b962 100644 +--- a/fs/proc/task_mmu.c ++++ b/fs/proc/task_mmu.c +@@ -276,7 +276,10 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid) + const char *name = NULL; + + if (file) { +- struct inode *inode = file_inode(vma->vm_file); ++ struct inode *inode; ++ ++ file = vma_pr_or_file(vma); ++ inode = file_inode(file); + dev = inode->i_sb->s_dev; + ino = inode->i_ino; + pgoff = ((loff_t)vma->vm_pgoff) << PAGE_SHIFT; +@@ -1447,7 +1450,7 @@ static int show_numa_map(struct seq_file *m, void *v, int is_pid) + struct proc_maps_private *proc_priv = &numa_priv->proc_maps; + struct vm_area_struct *vma = v; + struct numa_maps *md = &numa_priv->md; +- struct file *file = vma->vm_file; ++ struct file *file = vma_pr_or_file(vma); + struct mm_struct *mm = vma->vm_mm; + struct mm_walk walk = {}; + struct mempolicy *pol; +diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c +index 599ec2e..1740207 100644 +--- a/fs/proc/task_nommu.c ++++ b/fs/proc/task_nommu.c +@@ -160,7 +160,10 @@ static int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma, + file = vma->vm_file; + + if (file) { +- struct inode *inode = file_inode(vma->vm_file); ++ struct inode *inode; ++ ++ file = vma_pr_or_file(vma); ++ inode = file_inode(file); + dev = inode->i_sb->s_dev; + ino = inode->i_ino; + pgoff = (loff_t)vma->vm_pgoff << PAGE_SHIFT; +diff --git a/fs/splice.c b/fs/splice.c +index 75c6058..619359a 100644 +--- a/fs/splice.c ++++ b/fs/splice.c +@@ -1114,8 +1114,8 @@ EXPORT_SYMBOL(generic_splice_sendpage); + /* + * Attempt to initiate a splice from pipe to file. + */ +-static long do_splice_from(struct pipe_inode_info *pipe, struct file *out, +- loff_t *ppos, size_t len, unsigned int flags) ++long do_splice_from(struct pipe_inode_info *pipe, struct file *out, ++ loff_t *ppos, size_t len, unsigned int flags) + { + ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, + loff_t *, size_t, unsigned int); +@@ -1131,9 +1131,9 @@ static long do_splice_from(struct pipe_inode_info *pipe, struct file *out, + /* + * Attempt to initiate a splice from a file to a pipe. + */ +-static long do_splice_to(struct file *in, loff_t *ppos, +- struct pipe_inode_info *pipe, size_t len, +- unsigned int flags) ++long do_splice_to(struct file *in, loff_t *ppos, ++ struct pipe_inode_info *pipe, size_t len, ++ unsigned int flags) + { + ssize_t (*splice_read)(struct file *, loff_t *, + struct pipe_inode_info *, size_t, unsigned int); +diff --git a/include/linux/file.h b/include/linux/file.h +index 4d69123..62cffc0 100644 +--- a/include/linux/file.h ++++ b/include/linux/file.h +@@ -19,6 +19,7 @@ struct dentry; + struct path; + extern struct file *alloc_file(struct path *, fmode_t mode, + const struct file_operations *fop); ++extern struct file *get_empty_filp(void); + + static inline void fput_light(struct file *file, int fput_needed) + { +diff --git a/include/linux/fs.h b/include/linux/fs.h +index 6fd017e..c44d25d 100644 +--- a/include/linux/fs.h ++++ b/include/linux/fs.h +@@ -1149,6 +1149,7 @@ extern void fasync_free(struct fasync_struct *); + /* can be called from interrupts */ + extern void kill_fasync(struct fasync_struct **, int, int); + ++extern int setfl(int fd, struct file * filp, unsigned long arg); + extern void __f_setown(struct file *filp, struct pid *, enum pid_type, int force); + extern void f_setown(struct file *filp, unsigned long arg, int force); + extern void f_delown(struct file *filp); +@@ -1507,6 +1508,7 @@ struct file_operations { + ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int); + unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); + int (*check_flags)(int); ++ int (*setfl)(struct file *, unsigned long); + int (*flock) (struct file *, int, struct file_lock *); + ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int); + ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int); +@@ -2662,6 +2664,7 @@ extern int inode_change_ok(const struct inode *, struct iattr *); + extern int inode_newsize_ok(const struct inode *, loff_t offset); + extern void setattr_copy(struct inode *inode, const struct iattr *attr); + ++extern int update_time(struct inode *, struct timespec *, int); + extern int file_update_time(struct file *file); + + extern int generic_show_options(struct seq_file *m, struct dentry *root); +diff --git a/include/linux/mm.h b/include/linux/mm.h +index 86a977b..a2d0dbb 100644 +--- a/include/linux/mm.h ++++ b/include/linux/mm.h +@@ -1208,6 +1208,28 @@ static inline int fixup_user_fault(struct task_struct *tsk, + } + #endif + ++extern void vma_do_file_update_time(struct vm_area_struct *, const char[], int); ++extern struct file *vma_do_pr_or_file(struct vm_area_struct *, const char[], ++ int); ++extern void vma_do_get_file(struct vm_area_struct *, const char[], int); ++extern void vma_do_fput(struct vm_area_struct *, const char[], int); ++ ++#define vma_file_update_time(vma) vma_do_file_update_time(vma, __func__, \ ++ __LINE__) ++#define vma_pr_or_file(vma) vma_do_pr_or_file(vma, __func__, \ ++ __LINE__) ++#define vma_get_file(vma) vma_do_get_file(vma, __func__, __LINE__) ++#define vma_fput(vma) vma_do_fput(vma, __func__, __LINE__) ++ ++#ifndef CONFIG_MMU ++extern struct file *vmr_do_pr_or_file(struct vm_region *, const char[], int); ++extern void vmr_do_fput(struct vm_region *, const char[], int); ++ ++#define vmr_pr_or_file(region) vmr_do_pr_or_file(region, __func__, \ ++ __LINE__) ++#define vmr_fput(region) vmr_do_fput(region, __func__, __LINE__) ++#endif /* !CONFIG_MMU */ ++ + extern int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write); + extern int access_remote_vm(struct mm_struct *mm, unsigned long addr, + void *buf, int len, int write); +diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h +index 6e0b286..8f374ed 100644 +--- a/include/linux/mm_types.h ++++ b/include/linux/mm_types.h +@@ -232,6 +232,7 @@ struct vm_region { + unsigned long vm_top; /* region allocated to here */ + unsigned long vm_pgoff; /* the offset in vm_file corresponding to vm_start */ + struct file *vm_file; /* the backing file or NULL */ ++ struct file *vm_prfile; /* the virtual backing file or NULL */ + + int vm_usage; /* region usage count (access under nommu_region_sem) */ + bool vm_icache_flushed : 1; /* true if the icache has been flushed for +@@ -300,6 +301,7 @@ struct vm_area_struct { + unsigned long vm_pgoff; /* Offset (within vm_file) in PAGE_SIZE + units, *not* PAGE_CACHE_SIZE */ + struct file * vm_file; /* File we map to (can be NULL). */ ++ struct file *vm_prfile; /* shadow of vm_file */ + void * vm_private_data; /* was vm_pte (shared mem) */ + + #ifndef CONFIG_MMU +diff --git a/include/linux/splice.h b/include/linux/splice.h +index da2751d..2e0fca6 100644 +--- a/include/linux/splice.h ++++ b/include/linux/splice.h +@@ -83,4 +83,10 @@ extern void splice_shrink_spd(struct splice_pipe_desc *); + extern void spd_release_page(struct splice_pipe_desc *, unsigned int); + + extern const struct pipe_buf_operations page_cache_pipe_buf_ops; ++ ++extern long do_splice_from(struct pipe_inode_info *pipe, struct file *out, ++ loff_t *ppos, size_t len, unsigned int flags); ++extern long do_splice_to(struct file *in, loff_t *ppos, ++ struct pipe_inode_info *pipe, size_t len, ++ unsigned int flags); + #endif +diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild +index 8523f9b..11f8f74 100644 +--- a/include/uapi/linux/Kbuild ++++ b/include/uapi/linux/Kbuild +@@ -56,6 +56,7 @@ header-y += atmppp.h + header-y += atmsap.h + header-y += atmsvc.h + header-y += audit.h ++header-y += aufs_type.h + header-y += auto_fs.h + header-y += auto_fs4.h + header-y += auxvec.h +diff --git a/include/uapi/linux/aufs_type.h b/include/uapi/linux/aufs_type.h +new file mode 100644 +index 0000000..75915f8 +--- /dev/null ++++ b/include/uapi/linux/aufs_type.h +@@ -0,0 +1,419 @@ ++/* ++ * Copyright (C) 2005-2016 Junjiro R. Okajima ++ * ++ * This program, aufs is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++ ++#ifndef __AUFS_TYPE_H__ ++#define __AUFS_TYPE_H__ ++ ++#define AUFS_NAME "aufs" ++ ++#ifdef __KERNEL__ ++/* ++ * define it before including all other headers. ++ * sched.h may use pr_* macros before defining "current", so define the ++ * no-current version first, and re-define later. ++ */ ++#define pr_fmt(fmt) AUFS_NAME " %s:%d: " fmt, __func__, __LINE__ ++#include ++#undef pr_fmt ++#define pr_fmt(fmt) \ ++ AUFS_NAME " %s:%d:%.*s[%d]: " fmt, __func__, __LINE__, \ ++ (int)sizeof(current->comm), current->comm, current->pid ++#else ++#include ++#include ++#endif /* __KERNEL__ */ ++ ++#include ++ ++#define AUFS_VERSION "3.18.25+-20160509" ++ ++/* todo? move this to linux-2.6.19/include/magic.h */ ++#define AUFS_SUPER_MAGIC ('a' << 24 | 'u' << 16 | 'f' << 8 | 's') ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_BRANCH_MAX_127 ++typedef int8_t aufs_bindex_t; ++#define AUFS_BRANCH_MAX 127 ++#else ++typedef int16_t aufs_bindex_t; ++#ifdef CONFIG_AUFS_BRANCH_MAX_511 ++#define AUFS_BRANCH_MAX 511 ++#elif defined(CONFIG_AUFS_BRANCH_MAX_1023) ++#define AUFS_BRANCH_MAX 1023 ++#elif defined(CONFIG_AUFS_BRANCH_MAX_32767) ++#define AUFS_BRANCH_MAX 32767 ++#endif ++#endif ++ ++#ifdef __KERNEL__ ++#ifndef AUFS_BRANCH_MAX ++#error unknown CONFIG_AUFS_BRANCH_MAX value ++#endif ++#endif /* __KERNEL__ */ ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define AUFS_FSTYPE AUFS_NAME ++ ++#define AUFS_ROOT_INO 2 ++#define AUFS_FIRST_INO 11 ++ ++#define AUFS_WH_PFX ".wh." ++#define AUFS_WH_PFX_LEN ((int)sizeof(AUFS_WH_PFX) - 1) ++#define AUFS_WH_TMP_LEN 4 ++/* a limit for rmdir/rename a dir and copyup */ ++#define AUFS_MAX_NAMELEN (NAME_MAX \ ++ - AUFS_WH_PFX_LEN * 2 /* doubly whiteouted */\ ++ - 1 /* dot */\ ++ - AUFS_WH_TMP_LEN) /* hex */ ++#define AUFS_XINO_FNAME "." AUFS_NAME ".xino" ++#define AUFS_XINO_DEFPATH "/tmp/" AUFS_XINO_FNAME ++#define AUFS_XINO_DEF_SEC 30 /* seconds */ ++#define AUFS_XINO_DEF_TRUNC 45 /* percentage */ ++#define AUFS_DIRWH_DEF 3 ++#define AUFS_RDCACHE_DEF 10 /* seconds */ ++#define AUFS_RDCACHE_MAX 3600 /* seconds */ ++#define AUFS_RDBLK_DEF 512 /* bytes */ ++#define AUFS_RDHASH_DEF 32 ++#define AUFS_WKQ_NAME AUFS_NAME "d" ++#define AUFS_MFS_DEF_SEC 30 /* seconds */ ++#define AUFS_MFS_MAX_SEC 3600 /* seconds */ ++#define AUFS_FHSM_CACHE_DEF_SEC 30 /* seconds */ ++#define AUFS_PLINK_WARN 50 /* number of plinks in a single bucket */ ++ ++/* pseudo-link maintenace under /proc */ ++#define AUFS_PLINK_MAINT_NAME "plink_maint" ++#define AUFS_PLINK_MAINT_DIR "fs/" AUFS_NAME ++#define AUFS_PLINK_MAINT_PATH AUFS_PLINK_MAINT_DIR "/" AUFS_PLINK_MAINT_NAME ++ ++#define AUFS_DIROPQ_NAME AUFS_WH_PFX ".opq" /* whiteouted doubly */ ++#define AUFS_WH_DIROPQ AUFS_WH_PFX AUFS_DIROPQ_NAME ++ ++#define AUFS_BASE_NAME AUFS_WH_PFX AUFS_NAME ++#define AUFS_PLINKDIR_NAME AUFS_WH_PFX "plnk" ++#define AUFS_ORPHDIR_NAME AUFS_WH_PFX "orph" ++ ++/* doubly whiteouted */ ++#define AUFS_WH_BASE AUFS_WH_PFX AUFS_BASE_NAME ++#define AUFS_WH_PLINKDIR AUFS_WH_PFX AUFS_PLINKDIR_NAME ++#define AUFS_WH_ORPHDIR AUFS_WH_PFX AUFS_ORPHDIR_NAME ++ ++/* branch permissions and attributes */ ++#define AUFS_BRPERM_RW "rw" ++#define AUFS_BRPERM_RO "ro" ++#define AUFS_BRPERM_RR "rr" ++#define AUFS_BRATTR_COO_REG "coo_reg" ++#define AUFS_BRATTR_COO_ALL "coo_all" ++#define AUFS_BRATTR_FHSM "fhsm" ++#define AUFS_BRATTR_UNPIN "unpin" ++#define AUFS_BRATTR_ICEX "icex" ++#define AUFS_BRATTR_ICEX_SEC "icexsec" ++#define AUFS_BRATTR_ICEX_SYS "icexsys" ++#define AUFS_BRATTR_ICEX_TR "icextr" ++#define AUFS_BRATTR_ICEX_USR "icexusr" ++#define AUFS_BRATTR_ICEX_OTH "icexoth" ++#define AUFS_BRRATTR_WH "wh" ++#define AUFS_BRWATTR_NLWH "nolwh" ++#define AUFS_BRWATTR_MOO "moo" ++ ++#define AuBrPerm_RW 1 /* writable, hardlinkable wh */ ++#define AuBrPerm_RO (1 << 1) /* readonly */ ++#define AuBrPerm_RR (1 << 2) /* natively readonly */ ++#define AuBrPerm_Mask (AuBrPerm_RW | AuBrPerm_RO | AuBrPerm_RR) ++ ++#define AuBrAttr_COO_REG (1 << 3) /* copy-up on open */ ++#define AuBrAttr_COO_ALL (1 << 4) ++#define AuBrAttr_COO_Mask (AuBrAttr_COO_REG | AuBrAttr_COO_ALL) ++ ++#define AuBrAttr_FHSM (1 << 5) /* file-based hsm */ ++#define AuBrAttr_UNPIN (1 << 6) /* rename-able top dir of ++ branch. meaningless since ++ linux-3.18-rc1 */ ++ ++/* ignore error in copying XATTR */ ++#define AuBrAttr_ICEX_SEC (1 << 7) ++#define AuBrAttr_ICEX_SYS (1 << 8) ++#define AuBrAttr_ICEX_TR (1 << 9) ++#define AuBrAttr_ICEX_USR (1 << 10) ++#define AuBrAttr_ICEX_OTH (1 << 11) ++#define AuBrAttr_ICEX (AuBrAttr_ICEX_SEC \ ++ | AuBrAttr_ICEX_SYS \ ++ | AuBrAttr_ICEX_TR \ ++ | AuBrAttr_ICEX_USR \ ++ | AuBrAttr_ICEX_OTH) ++ ++#define AuBrRAttr_WH (1 << 12) /* whiteout-able */ ++#define AuBrRAttr_Mask AuBrRAttr_WH ++ ++#define AuBrWAttr_NoLinkWH (1 << 13) /* un-hardlinkable whiteouts */ ++#define AuBrWAttr_MOO (1 << 14) /* move-up on open */ ++#define AuBrWAttr_Mask (AuBrWAttr_NoLinkWH | AuBrWAttr_MOO) ++ ++#define AuBrAttr_CMOO_Mask (AuBrAttr_COO_Mask | AuBrWAttr_MOO) ++ ++/* #warning test userspace */ ++#ifdef __KERNEL__ ++#ifndef CONFIG_AUFS_FHSM ++#undef AuBrAttr_FHSM ++#define AuBrAttr_FHSM 0 ++#endif ++#ifndef CONFIG_AUFS_XATTR ++#undef AuBrAttr_ICEX ++#define AuBrAttr_ICEX 0 ++#undef AuBrAttr_ICEX_SEC ++#define AuBrAttr_ICEX_SEC 0 ++#undef AuBrAttr_ICEX_SYS ++#define AuBrAttr_ICEX_SYS 0 ++#undef AuBrAttr_ICEX_TR ++#define AuBrAttr_ICEX_TR 0 ++#undef AuBrAttr_ICEX_USR ++#define AuBrAttr_ICEX_USR 0 ++#undef AuBrAttr_ICEX_OTH ++#define AuBrAttr_ICEX_OTH 0 ++#endif ++#endif ++ ++/* the longest combination */ ++/* AUFS_BRATTR_ICEX and AUFS_BRATTR_ICEX_TR don't affect here */ ++#define AuBrPermStrSz sizeof(AUFS_BRPERM_RW \ ++ "+" AUFS_BRATTR_COO_REG \ ++ "+" AUFS_BRATTR_FHSM \ ++ "+" AUFS_BRATTR_UNPIN \ ++ "+" AUFS_BRATTR_ICEX_SEC \ ++ "+" AUFS_BRATTR_ICEX_SYS \ ++ "+" AUFS_BRATTR_ICEX_USR \ ++ "+" AUFS_BRATTR_ICEX_OTH \ ++ "+" AUFS_BRWATTR_NLWH) ++ ++typedef struct { ++ char a[AuBrPermStrSz]; ++} au_br_perm_str_t; ++ ++static inline int au_br_writable(int brperm) ++{ ++ return brperm & AuBrPerm_RW; ++} ++ ++static inline int au_br_whable(int brperm) ++{ ++ return brperm & (AuBrPerm_RW | AuBrRAttr_WH); ++} ++ ++static inline int au_br_wh_linkable(int brperm) ++{ ++ return !(brperm & AuBrWAttr_NoLinkWH); ++} ++ ++static inline int au_br_cmoo(int brperm) ++{ ++ return brperm & AuBrAttr_CMOO_Mask; ++} ++ ++static inline int au_br_fhsm(int brperm) ++{ ++ return brperm & AuBrAttr_FHSM; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ioctl */ ++enum { ++ /* readdir in userspace */ ++ AuCtl_RDU, ++ AuCtl_RDU_INO, ++ ++ AuCtl_WBR_FD, /* pathconf wrapper */ ++ AuCtl_IBUSY, /* busy inode */ ++ AuCtl_MVDOWN, /* move-down */ ++ AuCtl_BR, /* info about branches */ ++ AuCtl_FHSM_FD /* connection for fhsm */ ++}; ++ ++/* borrowed from linux/include/linux/kernel.h */ ++#ifndef ALIGN ++#define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a)-1) ++#define __ALIGN_MASK(x, mask) (((x)+(mask))&~(mask)) ++#endif ++ ++/* borrowed from linux/include/linux/compiler-gcc3.h */ ++#ifndef __aligned ++#define __aligned(x) __attribute__((aligned(x))) ++#endif ++ ++#ifdef __KERNEL__ ++#ifndef __packed ++#define __packed __attribute__((packed)) ++#endif ++#endif ++ ++struct au_rdu_cookie { ++ uint64_t h_pos; ++ int16_t bindex; ++ uint8_t flags; ++ uint8_t pad; ++ uint32_t generation; ++} __aligned(8); ++ ++struct au_rdu_ent { ++ uint64_t ino; ++ int16_t bindex; ++ uint8_t type; ++ uint8_t nlen; ++ uint8_t wh; ++ char name[0]; ++} __aligned(8); ++ ++static inline int au_rdu_len(int nlen) ++{ ++ /* include the terminating NULL */ ++ return ALIGN(sizeof(struct au_rdu_ent) + nlen + 1, ++ sizeof(uint64_t)); ++} ++ ++union au_rdu_ent_ul { ++ struct au_rdu_ent __user *e; ++ uint64_t ul; ++}; ++ ++enum { ++ AufsCtlRduV_SZ, ++ AufsCtlRduV_End ++}; ++ ++struct aufs_rdu { ++ /* input */ ++ union { ++ uint64_t sz; /* AuCtl_RDU */ ++ uint64_t nent; /* AuCtl_RDU_INO */ ++ }; ++ union au_rdu_ent_ul ent; ++ uint16_t verify[AufsCtlRduV_End]; ++ ++ /* input/output */ ++ uint32_t blk; ++ ++ /* output */ ++ union au_rdu_ent_ul tail; ++ /* number of entries which were added in a single call */ ++ uint64_t rent; ++ uint8_t full; ++ uint8_t shwh; ++ ++ struct au_rdu_cookie cookie; ++} __aligned(8); ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct aufs_wbr_fd { ++ uint32_t oflags; ++ int16_t brid; ++} __aligned(8); ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct aufs_ibusy { ++ uint64_t ino, h_ino; ++ int16_t bindex; ++} __aligned(8); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* error code for move-down */ ++/* the actual message strings are implemented in aufs-util.git */ ++enum { ++ EAU_MVDOWN_OPAQUE = 1, ++ EAU_MVDOWN_WHITEOUT, ++ EAU_MVDOWN_UPPER, ++ EAU_MVDOWN_BOTTOM, ++ EAU_MVDOWN_NOUPPER, ++ EAU_MVDOWN_NOLOWERBR, ++ EAU_Last ++}; ++ ++/* flags for move-down */ ++#define AUFS_MVDOWN_DMSG 1 ++#define AUFS_MVDOWN_OWLOWER (1 << 1) /* overwrite lower */ ++#define AUFS_MVDOWN_KUPPER (1 << 2) /* keep upper */ ++#define AUFS_MVDOWN_ROLOWER (1 << 3) /* do even if lower is RO */ ++#define AUFS_MVDOWN_ROLOWER_R (1 << 4) /* did on lower RO */ ++#define AUFS_MVDOWN_ROUPPER (1 << 5) /* do even if upper is RO */ ++#define AUFS_MVDOWN_ROUPPER_R (1 << 6) /* did on upper RO */ ++#define AUFS_MVDOWN_BRID_UPPER (1 << 7) /* upper brid */ ++#define AUFS_MVDOWN_BRID_LOWER (1 << 8) /* lower brid */ ++#define AUFS_MVDOWN_FHSM_LOWER (1 << 9) /* find fhsm attr for lower */ ++#define AUFS_MVDOWN_STFS (1 << 10) /* req. stfs */ ++#define AUFS_MVDOWN_STFS_FAILED (1 << 11) /* output: stfs is unusable */ ++#define AUFS_MVDOWN_BOTTOM (1 << 12) /* output: no more lowers */ ++ ++/* index for move-down */ ++enum { ++ AUFS_MVDOWN_UPPER, ++ AUFS_MVDOWN_LOWER, ++ AUFS_MVDOWN_NARRAY ++}; ++ ++/* ++ * additional info of move-down ++ * number of free blocks and inodes. ++ * subset of struct kstatfs, but smaller and always 64bit. ++ */ ++struct aufs_stfs { ++ uint64_t f_blocks; ++ uint64_t f_bavail; ++ uint64_t f_files; ++ uint64_t f_ffree; ++}; ++ ++struct aufs_stbr { ++ int16_t brid; /* optional input */ ++ int16_t bindex; /* output */ ++ struct aufs_stfs stfs; /* output when AUFS_MVDOWN_STFS set */ ++} __aligned(8); ++ ++struct aufs_mvdown { ++ uint32_t flags; /* input/output */ ++ struct aufs_stbr stbr[AUFS_MVDOWN_NARRAY]; /* input/output */ ++ int8_t au_errno; /* output */ ++} __aligned(8); ++ ++/* ---------------------------------------------------------------------- */ ++ ++union aufs_brinfo { ++ /* PATH_MAX may differ between kernel-space and user-space */ ++ char _spacer[4096]; ++ struct { ++ int16_t id; ++ int perm; ++ char path[0]; ++ }; ++} __aligned(8); ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define AuCtlType 'A' ++#define AUFS_CTL_RDU _IOWR(AuCtlType, AuCtl_RDU, struct aufs_rdu) ++#define AUFS_CTL_RDU_INO _IOWR(AuCtlType, AuCtl_RDU_INO, struct aufs_rdu) ++#define AUFS_CTL_WBR_FD _IOW(AuCtlType, AuCtl_WBR_FD, \ ++ struct aufs_wbr_fd) ++#define AUFS_CTL_IBUSY _IOWR(AuCtlType, AuCtl_IBUSY, struct aufs_ibusy) ++#define AUFS_CTL_MVDOWN _IOWR(AuCtlType, AuCtl_MVDOWN, \ ++ struct aufs_mvdown) ++#define AUFS_CTL_BRINFO _IOW(AuCtlType, AuCtl_BR, union aufs_brinfo) ++#define AUFS_CTL_FHSM_FD _IOW(AuCtlType, AuCtl_FHSM_FD, int) ++ ++#endif /* __AUFS_TYPE_H__ */ +diff --git a/kernel/fork.c b/kernel/fork.c +index 0a4f601..67ecb91 100644 +--- a/kernel/fork.c ++++ b/kernel/fork.c +@@ -430,7 +430,7 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm) + struct inode *inode = file_inode(file); + struct address_space *mapping = file->f_mapping; + +- get_file(file); ++ vma_get_file(tmp); + if (tmp->vm_flags & VM_DENYWRITE) + atomic_dec(&inode->i_writecount); + mutex_lock(&mapping->i_mmap_mutex); +diff --git a/mm/Makefile b/mm/Makefile +index 8405eb0..e0bda2d 100644 +--- a/mm/Makefile ++++ b/mm/Makefile +@@ -18,7 +18,7 @@ obj-y := filemap.o mempool.o oom_kill.o \ + mm_init.o mmu_context.o percpu.o slab_common.o \ + compaction.o vmacache.o \ + interval_tree.o list_lru.o workingset.o \ +- iov_iter.o debug.o $(mmu-y) ++ iov_iter.o prfile.o debug.o $(mmu-y) + + obj-y += init-mm.o + +diff --git a/mm/filemap.c b/mm/filemap.c +index 7e6ab98..2fe1e57 100644 +--- a/mm/filemap.c ++++ b/mm/filemap.c +@@ -2063,7 +2063,7 @@ int filemap_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) + int ret = VM_FAULT_LOCKED; + + sb_start_pagefault(inode->i_sb); +- file_update_time(vma->vm_file); ++ vma_file_update_time(vma); + lock_page(page); + if (page->mapping != inode->i_mapping) { + unlock_page(page); +diff --git a/mm/fremap.c b/mm/fremap.c +index 72b8fa3..a00bbf0 100644 +--- a/mm/fremap.c ++++ b/mm/fremap.c +@@ -224,16 +224,28 @@ get_write_lock: + */ + if (mapping_cap_account_dirty(mapping)) { + unsigned long addr; +- struct file *file = get_file(vma->vm_file); ++ struct file *file = vma->vm_file, ++ *prfile = vma->vm_prfile; ++ + /* mmap_region may free vma; grab the info now */ + vm_flags = vma->vm_flags; + ++ vma_get_file(vma); + addr = mmap_region(file, start, size, vm_flags, pgoff); +- fput(file); ++ vma_fput(vma); + if (IS_ERR_VALUE(addr)) { + err = addr; + } else { + BUG_ON(addr != start); ++ if (prfile) { ++ struct vm_area_struct *new_vma; ++ ++ new_vma = find_vma(mm, addr); ++ if (!new_vma->vm_prfile) ++ new_vma->vm_prfile = prfile; ++ if (new_vma != vma) ++ get_file(prfile); ++ } + err = 0; + } + goto out_freed; +diff --git a/mm/memory.c b/mm/memory.c +index 90fb265..844df2e 100644 +--- a/mm/memory.c ++++ b/mm/memory.c +@@ -2156,7 +2156,7 @@ reuse: + + /* file_update_time outside page_lock */ + if (vma->vm_file) +- file_update_time(vma->vm_file); ++ vma_file_update_time(vma); + } + put_page(dirty_page); + if (page_mkwrite) { +diff --git a/mm/mmap.c b/mm/mmap.c +index f88b4f9..9994987 100644 +--- a/mm/mmap.c ++++ b/mm/mmap.c +@@ -277,7 +277,7 @@ static struct vm_area_struct *remove_vma(struct vm_area_struct *vma) + if (vma->vm_ops && vma->vm_ops->close) + vma->vm_ops->close(vma); + if (vma->vm_file) +- fput(vma->vm_file); ++ vma_fput(vma); + mpol_put(vma_policy(vma)); + kmem_cache_free(vm_area_cachep, vma); + return next; +@@ -895,7 +895,7 @@ again: remove_next = 1 + (end > next->vm_end); + if (remove_next) { + if (file) { + uprobe_munmap(next, next->vm_start, next->vm_end); +- fput(file); ++ vma_fput(vma); + } + if (next->anon_vma) + anon_vma_merge(vma, next); +@@ -1680,8 +1680,8 @@ out: + return addr; + + unmap_and_free_vma: ++ vma_fput(vma); + vma->vm_file = NULL; +- fput(file); + + /* Undo any partial mapping done by a device driver. */ + unmap_region(mm, vma, prev, vma->vm_start, vma->vm_end); +@@ -2480,7 +2480,7 @@ static int __split_vma(struct mm_struct *mm, struct vm_area_struct *vma, + goto out_free_mpol; + + if (new->vm_file) +- get_file(new->vm_file); ++ vma_get_file(new); + + if (new->vm_ops && new->vm_ops->open) + new->vm_ops->open(new); +@@ -2499,7 +2499,7 @@ static int __split_vma(struct mm_struct *mm, struct vm_area_struct *vma, + if (new->vm_ops && new->vm_ops->close) + new->vm_ops->close(new); + if (new->vm_file) +- fput(new->vm_file); ++ vma_fput(new); + unlink_anon_vmas(new); + out_free_mpol: + mpol_put(vma_policy(new)); +@@ -2889,7 +2889,7 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap, + if (anon_vma_clone(new_vma, vma)) + goto out_free_mempol; + if (new_vma->vm_file) +- get_file(new_vma->vm_file); ++ vma_get_file(new_vma); + if (new_vma->vm_ops && new_vma->vm_ops->open) + new_vma->vm_ops->open(new_vma); + vma_link(mm, new_vma, prev, rb_link, rb_parent); +diff --git a/mm/nommu.c b/mm/nommu.c +index b5ba5bc..a7662fc 100644 +--- a/mm/nommu.c ++++ b/mm/nommu.c +@@ -658,7 +658,7 @@ static void __put_nommu_region(struct vm_region *region) + up_write(&nommu_region_sem); + + if (region->vm_file) +- fput(region->vm_file); ++ vmr_fput(region); + + /* IO memory and memory shared directly out of the pagecache + * from ramfs/tmpfs mustn't be released here */ +@@ -823,7 +823,7 @@ static void delete_vma(struct mm_struct *mm, struct vm_area_struct *vma) + if (vma->vm_ops && vma->vm_ops->close) + vma->vm_ops->close(vma); + if (vma->vm_file) +- fput(vma->vm_file); ++ vma_fput(vma); + put_nommu_region(vma->vm_region); + kmem_cache_free(vm_area_cachep, vma); + } +@@ -1385,7 +1385,7 @@ unsigned long do_mmap_pgoff(struct file *file, + goto error_just_free; + } + } +- fput(region->vm_file); ++ vmr_fput(region); + kmem_cache_free(vm_region_jar, region); + region = pregion; + result = start; +@@ -1461,10 +1461,10 @@ error_just_free: + up_write(&nommu_region_sem); + error: + if (region->vm_file) +- fput(region->vm_file); ++ vmr_fput(region); + kmem_cache_free(vm_region_jar, region); + if (vma->vm_file) +- fput(vma->vm_file); ++ vma_fput(vma); + kmem_cache_free(vm_area_cachep, vma); + kleave(" = %d", ret); + return ret; +diff --git a/mm/prfile.c b/mm/prfile.c +new file mode 100644 +index 0000000..532e518 +--- /dev/null ++++ b/mm/prfile.c +@@ -0,0 +1,86 @@ ++/* ++ * Mainly for aufs which mmap(2) diffrent file and wants to print different path ++ * in /proc/PID/maps. ++ * Call these functions via macros defined in linux/mm.h. ++ * ++ * See Documentation/filesystems/aufs/design/06mmap.txt ++ * ++ * Copyright (c) 2014 Junjro R. Okajima ++ * Copyright (c) 2014 Ian Campbell ++ */ ++ ++#include ++#include ++#include ++ ++/* #define PRFILE_TRACE */ ++static inline void prfile_trace(struct file *f, struct file *pr, ++ const char func[], int line, const char func2[]) ++{ ++#ifdef PRFILE_TRACE ++ if (pr) ++ pr_info("%s:%d: %s, %s\n", func, line, func2, ++ f ? (char *)f->f_dentry->d_name.name : "(null)"); ++#endif ++} ++ ++void vma_do_file_update_time(struct vm_area_struct *vma, const char func[], ++ int line) ++{ ++ struct file *f = vma->vm_file, *pr = vma->vm_prfile; ++ ++ prfile_trace(f, pr, func, line, __func__); ++ file_update_time(f); ++ if (f && pr) ++ file_update_time(pr); ++} ++ ++struct file *vma_do_pr_or_file(struct vm_area_struct *vma, const char func[], ++ int line) ++{ ++ struct file *f = vma->vm_file, *pr = vma->vm_prfile; ++ ++ prfile_trace(f, pr, func, line, __func__); ++ return (f && pr) ? pr : f; ++} ++ ++void vma_do_get_file(struct vm_area_struct *vma, const char func[], int line) ++{ ++ struct file *f = vma->vm_file, *pr = vma->vm_prfile; ++ ++ prfile_trace(f, pr, func, line, __func__); ++ get_file(f); ++ if (f && pr) ++ get_file(pr); ++} ++ ++void vma_do_fput(struct vm_area_struct *vma, const char func[], int line) ++{ ++ struct file *f = vma->vm_file, *pr = vma->vm_prfile; ++ ++ prfile_trace(f, pr, func, line, __func__); ++ fput(f); ++ if (f && pr) ++ fput(pr); ++} ++ ++#ifndef CONFIG_MMU ++struct file *vmr_do_pr_or_file(struct vm_region *region, const char func[], ++ int line) ++{ ++ struct file *f = region->vm_file, *pr = region->vm_prfile; ++ ++ prfile_trace(f, pr, func, line, __func__); ++ return (f && pr) ? pr : f; ++} ++ ++void vmr_do_fput(struct vm_region *region, const char func[], int line) ++{ ++ struct file *f = region->vm_file, *pr = region->vm_prfile; ++ ++ prfile_trace(f, pr, func, line, __func__); ++ fput(f); ++ if (f && pr) ++ fput(pr); ++} ++#endif /* !CONFIG_MMU */ +-- +2.1.4 + diff --git a/packages/base/any/kernels/3.18.25/patches/series b/packages/base/any/kernels/3.18.25/patches/series new file mode 100644 index 00000000..f6b71ff1 --- /dev/null +++ b/packages/base/any/kernels/3.18.25/patches/series @@ -0,0 +1 @@ +aufs.patch From 082789b01222a1bcd89cb5ec6d8470955779c48b Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Fri, 13 May 2016 10:20:46 -0700 Subject: [PATCH 051/113] Back out onlyaml rewrite to another branch --- .../all/vendor-config-onl/src/python/onl/YamlUtils.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/packages/base/all/vendor-config-onl/src/python/onl/YamlUtils.py b/packages/base/all/vendor-config-onl/src/python/onl/YamlUtils.py index 44822148..4381f799 100644 --- a/packages/base/all/vendor-config-onl/src/python/onl/YamlUtils.py +++ b/packages/base/all/vendor-config-onl/src/python/onl/YamlUtils.py @@ -3,12 +3,6 @@ """ import yaml -try: - import onlyaml - def load(stream): - return yaml.load(stream, Loader=onlyaml.Loader) -except ImportError: - load = yaml.load def merge(p1, p2): """Merge two YAML files. @@ -34,7 +28,7 @@ def merge(p1, p2): buf2 = fd.read() # read p1 as-is, make sure it looks like a 'default' YAML - c1 = load(buf1) + c1 = yaml.load(buf1) k1 = list(c1.keys()) if k1 != ['default']: raise ValueError("%s: invalid top-level keys for default mapping: %s" @@ -44,7 +38,7 @@ def merge(p1, p2): lines = buf2.splitlines(False) lines = [x for x in lines if x != '---'] buf3 = buf1 + "\n" + "\n".join(lines) - c2 = load(buf3) + c2 = yaml.load(buf3) c2.pop('default', None) k2 = list(c2.keys()) From 1d19e6fd662bd42abfe9b766af48b4d9b3140711 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Fri, 13 May 2016 11:32:49 -0700 Subject: [PATCH 052/113] Fixed conditional for arch test --- builds/any/installer/new-hotness/installer.sh.in | 2 -- 1 file changed, 2 deletions(-) diff --git a/builds/any/installer/new-hotness/installer.sh.in b/builds/any/installer/new-hotness/installer.sh.in index 050290bc..a2cab8a0 100644 --- a/builds/any/installer/new-hotness/installer.sh.in +++ b/builds/any/installer/new-hotness/installer.sh.in @@ -25,8 +25,6 @@ IARCH="@ARCH@" ARCH=`uname -m` if test "$ARCH" != "$IARCH"; then - : -else # identify mappings between kernel arch and debian arch case "$IARCH:$ARCH" in armel:arm7l) ;; From e11a5bd0cd5fa1683cea40a332528e62449ae71f Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Fri, 13 May 2016 11:53:57 -0700 Subject: [PATCH 053/113] Propagate the '--force' flag properly --- .../all/vendor-config-onl/src/python/onl/install/BaseInstall.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/base/all/vendor-config-onl/src/python/onl/install/BaseInstall.py b/packages/base/all/vendor-config-onl/src/python/onl/install/BaseInstall.py index da4c62ab..08e41e76 100644 --- a/packages/base/all/vendor-config-onl/src/python/onl/install/BaseInstall.py +++ b/packages/base/all/vendor-config-onl/src/python/onl/install/BaseInstall.py @@ -55,7 +55,7 @@ class Base: ubootEnv = ubootEnv) self.log = log or logging.getLogger(self.__class__.__name__) - self.force = False + self.force = force # unmount filesystems as needed self.device = None From 0e6f10c92a16a8f7e3e6def18c89309794218188 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Fri, 13 May 2016 11:54:29 -0700 Subject: [PATCH 054/113] Minor installer fixes - handle powerpc architecture renames - pass --force flag for GPT installs --- builds/any/installer/new-hotness/installer.sh.in | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/builds/any/installer/new-hotness/installer.sh.in b/builds/any/installer/new-hotness/installer.sh.in index a2cab8a0..9a44660e 100644 --- a/builds/any/installer/new-hotness/installer.sh.in +++ b/builds/any/installer/new-hotness/installer.sh.in @@ -28,6 +28,7 @@ if test "$ARCH" != "$IARCH"; then # identify mappings between kernel arch and debian arch case "$IARCH:$ARCH" in armel:arm7l) ;; + powerpc:ppc) ;; *) echo echo "------------------------------------" @@ -462,7 +463,7 @@ echo "installer_postinst=\"/mnt/installer/$b\"" >> "${rootdir}/etc/onl/installer # anyway installer_say "Launching ONL installer" -installer_shell=${installer_shell-"/usr/bin/onl-install"} +installer_shell=${installer_shell-"/usr/bin/onl-install --force"} chroot "${rootdir}" $installer_shell if test -f "$postinst"; then From d67d6d97b7a7b0f3407a62904bcefcac469e9041 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Mon, 16 May 2016 11:44:21 -0700 Subject: [PATCH 055/113] installer fixes for amd64 - unmount filesystems before the chroot --- .../any/installer/new-hotness/installer.sh.in | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/builds/any/installer/new-hotness/installer.sh.in b/builds/any/installer/new-hotness/installer.sh.in index 9a44660e..4c7fdfd2 100644 --- a/builds/any/installer/new-hotness/installer.sh.in +++ b/builds/any/installer/new-hotness/installer.sh.in @@ -463,7 +463,31 @@ echo "installer_postinst=\"/mnt/installer/$b\"" >> "${rootdir}/etc/onl/installer # anyway installer_say "Launching ONL installer" -installer_shell=${installer_shell-"/usr/bin/onl-install --force"} + +installer_shell_dfl="/usr/bin/onl-install --force" +installer_shell=${installer_shell-"$installer_shell_dfl"} +# default, unmount flash filesystems and run the installer script + +# Ugh, unmount /mnt filesystems here, +# they are not accessible from within the chroot +installer_force_umount() { + local dev mpt + dev=$1; shift + mpt=$1; shift + case "$mpt" in + /mnt/*) + installer_say "Unmounting $mpt (--force)" + umount "$mpt" + ;; + esac +} +if test "$installer_shell" = "$installer_shell_dfl"; then + visit_proc_mounts installer_force_umount +else + installer_say "*** using non-default installer command: $installer_shell" + installer_say "*** watch out for lingering mount-points" +fi + chroot "${rootdir}" $installer_shell if test -f "$postinst"; then From b7c148efcdc2328b9fb4c27923c265e8bce41942 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Mon, 16 May 2016 11:51:04 -0700 Subject: [PATCH 056/113] installer fixes for arm - Fixed arch typo --- builds/any/installer/new-hotness/installer.sh.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builds/any/installer/new-hotness/installer.sh.in b/builds/any/installer/new-hotness/installer.sh.in index 4c7fdfd2..7982c5a1 100644 --- a/builds/any/installer/new-hotness/installer.sh.in +++ b/builds/any/installer/new-hotness/installer.sh.in @@ -27,7 +27,7 @@ ARCH=`uname -m` if test "$ARCH" != "$IARCH"; then # identify mappings between kernel arch and debian arch case "$IARCH:$ARCH" in - armel:arm7l) ;; + armel:armv7l) ;; powerpc:ppc) ;; *) echo From 7783d7bb18fc6dde80cf19cda02dd9d5768af230 Mon Sep 17 00:00:00 2001 From: Jeffrey Townsend Date: Mon, 16 May 2016 23:37:04 +0000 Subject: [PATCH 057/113] Support LED Character Devices - Set ONLP_LED_CAP_CHAR to support a character display. - Implement onlp_ledi_char_set(). - Add the when implementing onlp_ledi_info_get(). --- .../any/onlp/src/onlp/module/auto/onlp.yml | 31 +++++++++---------- .../any/onlp/src/onlp/module/inc/onlp/led.h | 28 ++++++++++++----- .../src/onlp/module/inc/onlp/platformi/ledi.h | 20 ++++++++---- .../base/any/onlp/src/onlp/module/src/led.c | 23 ++++++++++++++ .../any/onlp/src/onlp/module/src/onlp_enums.c | 2 ++ 5 files changed, 75 insertions(+), 29 deletions(-) diff --git a/packages/base/any/onlp/src/onlp/module/auto/onlp.yml b/packages/base/any/onlp/src/onlp/module/auto/onlp.yml index 4507898f..47adc6e6 100644 --- a/packages/base/any/onlp/src/onlp/module/auto/onlp.yml +++ b/packages/base/any/onlp/src/onlp/module/auto/onlp.yml @@ -163,20 +163,21 @@ thermal_threshold: &thermal_threshold # LED caps led_caps: &led_caps -- ON_OFF : (1 << 0) -- RED : (1 << 10) -- RED_BLINKING : (1 << 11) -- ORANGE : (1 << 12) -- ORANGE_BLINKING : (1 << 13) -- YELLOW : ( 1 << 14) -- YELLOW_BLINKING : (1 << 15) -- GREEN : (1 << 16) -- GREEN_BLINKING : (1 << 17) -- BLUE : (1 << 18) -- BLUE_BLINKING : (1 << 19) -- PURPLE: (1 << 20) -- PURPLE_BLINKING : (1 << 21) -- AUTO : (1 << 22) +- ON_OFF : (1 << 0) +- CHAR : (1 << 1) +- RED : (1 << 10) +- RED_BLINKING : (1 << 11) +- ORANGE : (1 << 12) +- ORANGE_BLINKING : (1 << 13) +- YELLOW : (1 << 14) +- YELLOW_BLINKING : (1 << 15) +- GREEN : (1 << 16) +- GREEN_BLINKING : (1 << 17) +- BLUE : (1 << 18) +- BLUE_BLINKING : (1 << 19) +- PURPLE : (1 << 20) +- PURPLE_BLINKING : (1 << 21) +- AUTO : (1 << 22) # LED status led_status: &led_status @@ -307,5 +308,3 @@ definitions: xmacro: ONLP_OID_TYPE_ENTRY: members: *oid_types - - diff --git a/packages/base/any/onlp/src/onlp/module/inc/onlp/led.h b/packages/base/any/onlp/src/onlp/module/inc/onlp/led.h index 233cd243..2909b9df 100644 --- a/packages/base/any/onlp/src/onlp/module/inc/onlp/led.h +++ b/packages/base/any/onlp/src/onlp/module/inc/onlp/led.h @@ -1,21 +1,21 @@ /************************************************************ * - * - * Copyright 2014, 2015 Big Switch Networks, Inc. - * + * + * Copyright 2014, 2015 Big Switch Networks, Inc. + * * Licensed under the Eclipse Public License, Version 1.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.eclipse.org/legal/epl-v10.html - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, * either express or implied. See the License for the specific * language governing permissions and limitations under the * License. - * + * * ************************************************************ * @@ -32,11 +32,12 @@ /** onlp_led_caps */ typedef enum onlp_led_caps_e { ONLP_LED_CAPS_ON_OFF = (1 << 0), + ONLP_LED_CAPS_CHAR = (1 << 1), ONLP_LED_CAPS_RED = (1 << 10), ONLP_LED_CAPS_RED_BLINKING = (1 << 11), ONLP_LED_CAPS_ORANGE = (1 << 12), ONLP_LED_CAPS_ORANGE_BLINKING = (1 << 13), - ONLP_LED_CAPS_YELLOW = ( 1 << 14), + ONLP_LED_CAPS_YELLOW = (1 << 14), ONLP_LED_CAPS_YELLOW_BLINKING = (1 << 15), ONLP_LED_CAPS_GREEN = (1 << 16), ONLP_LED_CAPS_GREEN_BLINKING = (1 << 17), @@ -91,6 +92,10 @@ typedef struct onlp_led_info_s { /** Current mode, if capable. */ onlp_led_mode_t mode; + + /** Current char, if capable. */ + char character; + } onlp_led_info_t; /** @@ -124,6 +129,15 @@ int onlp_led_set(onlp_oid_t id, int on_or_off); */ int onlp_led_mode_set(onlp_oid_t id, onlp_led_mode_t color); + +/** + * @brief Set the LED char + * @param id The LED OID + * @param c The character. + * @note Only relevant if the LED supports the char capability. + */ +int onlp_led_char_set(onlp_oid_t id, char c); + /** * @brief LED OID debug dump * @param id The LED OID diff --git a/packages/base/any/onlp/src/onlp/module/inc/onlp/platformi/ledi.h b/packages/base/any/onlp/src/onlp/module/inc/onlp/platformi/ledi.h index 9bb043fa..7d5bb545 100644 --- a/packages/base/any/onlp/src/onlp/module/inc/onlp/platformi/ledi.h +++ b/packages/base/any/onlp/src/onlp/module/inc/onlp/platformi/ledi.h @@ -1,21 +1,21 @@ /************************************************************ * - * - * Copyright 2014, 2015 Big Switch Networks, Inc. - * + * + * Copyright 2014, 2015 Big Switch Networks, Inc. + * * Licensed under the Eclipse Public License, Version 1.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.eclipse.org/legal/epl-v10.html - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, * either express or implied. See the License for the specific * language governing permissions and limitations under the * License. - * + * * ************************************************************ * @@ -63,4 +63,12 @@ int onlp_ledi_ioctl(onlp_oid_t id, va_list vargs); */ int onlp_ledi_mode_set(onlp_oid_t id, onlp_led_mode_t mode); +/** + * @brief Set the LED character. + * @param id The LED OID + * @param c The character.. + * @notes Only called if the char capability is set. + */ +int onlp_ledi_char_set(onlp_oid_t id, char c); + #endif /* __ONLP_LED_H__ */ diff --git a/packages/base/any/onlp/src/onlp/module/src/led.c b/packages/base/any/onlp/src/onlp/module/src/led.c index f78fac92..50f85809 100644 --- a/packages/base/any/onlp/src/onlp/module/src/led.c +++ b/packages/base/any/onlp/src/onlp/module/src/led.c @@ -117,6 +117,25 @@ onlp_led_mode_set_locked__(onlp_oid_t id, onlp_led_mode_t mode) } ONLP_LOCKED_API2(onlp_led_mode_set, onlp_oid_t, id, onlp_led_mode_t, mode); +static int +onlp_led_char_set_locked__(onlp_oid_t id, char c) +{ + onlp_led_info_t info; + ONLP_LED_PRESENT_OR_RETURN(id, &info); + + /* + * The mode enumeration values always match + * the capability bit positions. + */ + if(info.caps & ONLP_LED_CAPS_CHAR) { + return onlp_ledi_char_set(id, c); + } + else { + return ONLP_STATUS_E_UNSUPPORTED; + } +} +ONLP_LOCKED_API2(onlp_led_char_set, onlp_oid_t, id, char, c); + /************************************************************ * * Debug and Show Functions @@ -144,6 +163,7 @@ onlp_led_dump(onlp_oid_t id, aim_pvs_t* pvs, uint32_t flags) iof_iprintf(&iof, "Status: %{onlp_led_status_flags}", info.status); iof_iprintf(&iof, "Caps: %{onlp_led_caps_flags}", info.caps); iof_iprintf(&iof, "Mode: %{onlp_led_mode}", info.mode); + iof_iprintf(&iof, "Char: %c", info.character); } else { iof_iprintf(&iof, "Not present."); @@ -189,6 +209,9 @@ onlp_led_show(onlp_oid_t id, aim_pvs_t* pvs, uint32_t flags) /* Present */ iof_iprintf(&iof, "State: Present"); iof_iprintf(&iof, "Mode: %{onlp_led_mode}", info.mode); + if(info.caps & ONLP_LED_CAPS_CHAR) { + iof_iprintf(&iof, "Char: %c", info.character); + } } else { onlp_oid_show_state_missing(&iof); diff --git a/packages/base/any/onlp/src/onlp/module/src/onlp_enums.c b/packages/base/any/onlp/src/onlp/module/src/onlp_enums.c index 7fd366bf..0c5a185f 100644 --- a/packages/base/any/onlp/src/onlp/module/src/onlp_enums.c +++ b/packages/base/any/onlp/src/onlp/module/src/onlp_enums.c @@ -282,6 +282,7 @@ onlp_fan_status_valid(onlp_fan_status_t e) aim_map_si_t onlp_led_caps_map[] = { { "ON_OFF", ONLP_LED_CAPS_ON_OFF }, + { "CHAR", ONLP_LED_CAPS_CHAR }, { "RED", ONLP_LED_CAPS_RED }, { "RED_BLINKING", ONLP_LED_CAPS_RED_BLINKING }, { "ORANGE", ONLP_LED_CAPS_ORANGE }, @@ -301,6 +302,7 @@ aim_map_si_t onlp_led_caps_map[] = aim_map_si_t onlp_led_caps_desc_map[] = { { "None", ONLP_LED_CAPS_ON_OFF }, + { "None", ONLP_LED_CAPS_CHAR }, { "None", ONLP_LED_CAPS_RED }, { "None", ONLP_LED_CAPS_RED_BLINKING }, { "None", ONLP_LED_CAPS_ORANGE }, From 918e43ac946a8aa937d19ca64f1928d8715d73be Mon Sep 17 00:00:00 2001 From: Jeffrey Townsend Date: Mon, 16 May 2016 23:38:11 +0000 Subject: [PATCH 058/113] New onlp_ledi_char_set(). --- .../src/onlp_platform_defaults/module/src/ledi.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/base/any/onlp/src/onlp_platform_defaults/module/src/ledi.c b/packages/base/any/onlp/src/onlp_platform_defaults/module/src/ledi.c index 89644ecf..461130b2 100644 --- a/packages/base/any/onlp/src/onlp_platform_defaults/module/src/ledi.c +++ b/packages/base/any/onlp/src/onlp_platform_defaults/module/src/ledi.c @@ -1,21 +1,21 @@ /************************************************************ * - * - * Copyright 2014, 2015 Big Switch Networks, Inc. - * + * + * Copyright 2014, 2015 Big Switch Networks, Inc. + * * Licensed under the Eclipse Public License, Version 1.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.eclipse.org/legal/epl-v10.html - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, * either express or implied. See the License for the specific * language governing permissions and limitations under the * License. - * + * * ************************************************************ * @@ -30,3 +30,4 @@ __ONLP_DEFAULTI_IMPLEMENTATION(onlp_ledi_info_get(onlp_oid_t id, onlp_led_info_t __ONLP_DEFAULTI_IMPLEMENTATION(onlp_ledi_set(onlp_oid_t id, int on_or_off)); __ONLP_DEFAULTI_IMPLEMENTATION(onlp_ledi_ioctl(onlp_oid_t id, va_list vargs)); __ONLP_DEFAULTI_IMPLEMENTATION(onlp_ledi_mode_set(onlp_oid_t id, onlp_led_mode_t mode)); +__ONLP_DEFAULTI_IMPLEMENTATION(onlp_ledi_char_set(onlp_oid_t id, char c)); From 4f56199c351048fefe39dce6e8dad392e249b49f Mon Sep 17 00:00:00 2001 From: Jeffrey Townsend Date: Mon, 16 May 2016 23:47:15 +0000 Subject: [PATCH 059/113] The new-hotness installer is now the regular-hotness installer. --- builds/amd64/installer/{new-hotness => }/Makefile | 0 builds/amd64/installer/{new-hotness => }/PKG.yml | 0 builds/amd64/installer/{new-hotness => }/builds/.gitignore | 0 builds/amd64/installer/{new-hotness => }/builds/Makefile | 0 builds/amd64/installer/{new-hotness => }/builds/boot-config | 0 builds/any/installer/{new-hotness => }/APKG.yml | 0 builds/any/installer/{new-hotness => }/grub/builds/Makefile | 0 builds/any/installer/{new-hotness => }/installer.sh.in | 0 builds/any/installer/{new-hotness => }/uboot/builds/Makefile | 0 builds/armel/installer/{new-hotness => }/Makefile | 0 builds/armel/installer/{new-hotness => }/PKG.yml | 0 builds/armel/installer/{new-hotness => }/builds/.gitignore | 0 builds/armel/installer/{new-hotness => }/builds/Makefile | 0 builds/armel/installer/{new-hotness => }/builds/boot-config | 0 builds/powerpc/installer/{new-hotness => }/Makefile | 0 builds/powerpc/installer/{new-hotness => }/PKG.yml | 0 builds/powerpc/installer/{new-hotness => }/builds/.gitignore | 0 builds/powerpc/installer/{new-hotness => }/builds/Makefile | 0 builds/powerpc/installer/{new-hotness => }/builds/boot-config | 0 19 files changed, 0 insertions(+), 0 deletions(-) rename builds/amd64/installer/{new-hotness => }/Makefile (100%) rename builds/amd64/installer/{new-hotness => }/PKG.yml (100%) rename builds/amd64/installer/{new-hotness => }/builds/.gitignore (100%) rename builds/amd64/installer/{new-hotness => }/builds/Makefile (100%) rename builds/amd64/installer/{new-hotness => }/builds/boot-config (100%) rename builds/any/installer/{new-hotness => }/APKG.yml (100%) rename builds/any/installer/{new-hotness => }/grub/builds/Makefile (100%) rename builds/any/installer/{new-hotness => }/installer.sh.in (100%) rename builds/any/installer/{new-hotness => }/uboot/builds/Makefile (100%) rename builds/armel/installer/{new-hotness => }/Makefile (100%) rename builds/armel/installer/{new-hotness => }/PKG.yml (100%) rename builds/armel/installer/{new-hotness => }/builds/.gitignore (100%) rename builds/armel/installer/{new-hotness => }/builds/Makefile (100%) rename builds/armel/installer/{new-hotness => }/builds/boot-config (100%) rename builds/powerpc/installer/{new-hotness => }/Makefile (100%) rename builds/powerpc/installer/{new-hotness => }/PKG.yml (100%) rename builds/powerpc/installer/{new-hotness => }/builds/.gitignore (100%) rename builds/powerpc/installer/{new-hotness => }/builds/Makefile (100%) rename builds/powerpc/installer/{new-hotness => }/builds/boot-config (100%) diff --git a/builds/amd64/installer/new-hotness/Makefile b/builds/amd64/installer/Makefile similarity index 100% rename from builds/amd64/installer/new-hotness/Makefile rename to builds/amd64/installer/Makefile diff --git a/builds/amd64/installer/new-hotness/PKG.yml b/builds/amd64/installer/PKG.yml similarity index 100% rename from builds/amd64/installer/new-hotness/PKG.yml rename to builds/amd64/installer/PKG.yml diff --git a/builds/amd64/installer/new-hotness/builds/.gitignore b/builds/amd64/installer/builds/.gitignore similarity index 100% rename from builds/amd64/installer/new-hotness/builds/.gitignore rename to builds/amd64/installer/builds/.gitignore diff --git a/builds/amd64/installer/new-hotness/builds/Makefile b/builds/amd64/installer/builds/Makefile similarity index 100% rename from builds/amd64/installer/new-hotness/builds/Makefile rename to builds/amd64/installer/builds/Makefile diff --git a/builds/amd64/installer/new-hotness/builds/boot-config b/builds/amd64/installer/builds/boot-config similarity index 100% rename from builds/amd64/installer/new-hotness/builds/boot-config rename to builds/amd64/installer/builds/boot-config diff --git a/builds/any/installer/new-hotness/APKG.yml b/builds/any/installer/APKG.yml similarity index 100% rename from builds/any/installer/new-hotness/APKG.yml rename to builds/any/installer/APKG.yml diff --git a/builds/any/installer/new-hotness/grub/builds/Makefile b/builds/any/installer/grub/builds/Makefile similarity index 100% rename from builds/any/installer/new-hotness/grub/builds/Makefile rename to builds/any/installer/grub/builds/Makefile diff --git a/builds/any/installer/new-hotness/installer.sh.in b/builds/any/installer/installer.sh.in similarity index 100% rename from builds/any/installer/new-hotness/installer.sh.in rename to builds/any/installer/installer.sh.in diff --git a/builds/any/installer/new-hotness/uboot/builds/Makefile b/builds/any/installer/uboot/builds/Makefile similarity index 100% rename from builds/any/installer/new-hotness/uboot/builds/Makefile rename to builds/any/installer/uboot/builds/Makefile diff --git a/builds/armel/installer/new-hotness/Makefile b/builds/armel/installer/Makefile similarity index 100% rename from builds/armel/installer/new-hotness/Makefile rename to builds/armel/installer/Makefile diff --git a/builds/armel/installer/new-hotness/PKG.yml b/builds/armel/installer/PKG.yml similarity index 100% rename from builds/armel/installer/new-hotness/PKG.yml rename to builds/armel/installer/PKG.yml diff --git a/builds/armel/installer/new-hotness/builds/.gitignore b/builds/armel/installer/builds/.gitignore similarity index 100% rename from builds/armel/installer/new-hotness/builds/.gitignore rename to builds/armel/installer/builds/.gitignore diff --git a/builds/armel/installer/new-hotness/builds/Makefile b/builds/armel/installer/builds/Makefile similarity index 100% rename from builds/armel/installer/new-hotness/builds/Makefile rename to builds/armel/installer/builds/Makefile diff --git a/builds/armel/installer/new-hotness/builds/boot-config b/builds/armel/installer/builds/boot-config similarity index 100% rename from builds/armel/installer/new-hotness/builds/boot-config rename to builds/armel/installer/builds/boot-config diff --git a/builds/powerpc/installer/new-hotness/Makefile b/builds/powerpc/installer/Makefile similarity index 100% rename from builds/powerpc/installer/new-hotness/Makefile rename to builds/powerpc/installer/Makefile diff --git a/builds/powerpc/installer/new-hotness/PKG.yml b/builds/powerpc/installer/PKG.yml similarity index 100% rename from builds/powerpc/installer/new-hotness/PKG.yml rename to builds/powerpc/installer/PKG.yml diff --git a/builds/powerpc/installer/new-hotness/builds/.gitignore b/builds/powerpc/installer/builds/.gitignore similarity index 100% rename from builds/powerpc/installer/new-hotness/builds/.gitignore rename to builds/powerpc/installer/builds/.gitignore diff --git a/builds/powerpc/installer/new-hotness/builds/Makefile b/builds/powerpc/installer/builds/Makefile similarity index 100% rename from builds/powerpc/installer/new-hotness/builds/Makefile rename to builds/powerpc/installer/builds/Makefile diff --git a/builds/powerpc/installer/new-hotness/builds/boot-config b/builds/powerpc/installer/builds/boot-config similarity index 100% rename from builds/powerpc/installer/new-hotness/builds/boot-config rename to builds/powerpc/installer/builds/boot-config From 3646da03a35f0e0b7e785123c3319715d4907106 Mon Sep 17 00:00:00 2001 From: Jeffrey Townsend Date: Mon, 16 May 2016 16:55:18 -0700 Subject: [PATCH 060/113] The new-hotness installer is now the regular-hotness installer. --- builds/amd64/installer/PKG.yml | 3 +-- builds/amd64/installer/builds/Makefile | 2 +- builds/any/installer/grub/builds/Makefile | 3 +-- builds/any/installer/uboot/builds/Makefile | 5 ++--- builds/armel/installer/PKG.yml | 3 +-- builds/armel/installer/builds/Makefile | 2 +- builds/powerpc/installer/PKG.yml | 3 +-- builds/powerpc/installer/builds/Makefile | 2 +- 8 files changed, 9 insertions(+), 14 deletions(-) diff --git a/builds/amd64/installer/PKG.yml b/builds/amd64/installer/PKG.yml index 55693e33..7f363cd8 100644 --- a/builds/amd64/installer/PKG.yml +++ b/builds/amd64/installer/PKG.yml @@ -1,2 +1 @@ -!include $ONL/builds/any/installer/new-hotness/APKG.yml ARCH=amd64 - +!include $ONL/builds/any/installer/APKG.yml ARCH=amd64 diff --git a/builds/amd64/installer/builds/Makefile b/builds/amd64/installer/builds/Makefile index 065c502a..1f5d777c 100644 --- a/builds/amd64/installer/builds/Makefile +++ b/builds/amd64/installer/builds/Makefile @@ -1,2 +1,2 @@ include $(ONL)/make/config.amd64.mk -include $(ONL)/builds/any/installer/new-hotness/grub/builds/Makefile +include $(ONL)/builds/any/installer/grub/builds/Makefile diff --git a/builds/any/installer/grub/builds/Makefile b/builds/any/installer/grub/builds/Makefile index fabadf3b..99be574f 100644 --- a/builds/any/installer/grub/builds/Makefile +++ b/builds/any/installer/grub/builds/Makefile @@ -32,7 +32,7 @@ __installer: __installer_platform_files __installer_swi_files -e 's^@INITRD_OFFSET@^^g' \ -e 's^@INITRD_SIZE@^^g' \ -e 's^@ARCH@^$(INSTALLER_ARCH)^g' \ - $(ONL)/builds/any/installer/new-hotness/installer.sh.in \ + $(ONL)/builds/any/installer/installer.sh.in \ >> installer.sh $(ONL_V_at)echo "PAYLOAD_FOLLOWS" >> installer.sh $(ONL_V_at)cp /dev/null $(MKSHAR_PERMS) @@ -91,4 +91,3 @@ shar installer: installer clean: rm -f *.swi *.installer $(notdir $(KERNELS)) *initrd*.cpio.gz - diff --git a/builds/any/installer/uboot/builds/Makefile b/builds/any/installer/uboot/builds/Makefile index ebd2248e..ea5ad357 100644 --- a/builds/any/installer/uboot/builds/Makefile +++ b/builds/any/installer/uboot/builds/Makefile @@ -33,7 +33,7 @@ __installer: installer.sh __installer_fit_files __installer_platform_files __ins $(ONL_V_at)rm -rf installer.sh *.itb *.swi version-onl.sh autoperms.sh $(ONL_V_at)md5sum "$(INSTALLER_NAME)" | awk '{ print $$1 }' > "$(INSTALLER_NAME).md5sum" -installer.sh: Makefile $(ONL)/builds/any/installer/new-hotness/installer.sh.in +installer.sh: Makefile $(ONL)/builds/any/installer/installer.sh.in $(ONL_V_GEN)cp /dev/null $@ $(ONL_V_at): ;\ set -e ;\ @@ -50,7 +50,7 @@ installer.sh: Makefile $(ONL)/builds/any/installer/new-hotness/installer.sh.in -e "s^@INITRD_OFFSET@^$$start^g" \ -e "s^@INITRD_SIZE@^$$sz^g" \ -e 's^@ARCH@^$(ARCH)^g' \ - $(ONL)/builds/any/installer/new-hotness/installer.sh.in \ + $(ONL)/builds/any/installer/installer.sh.in \ >> $@ $(ONL_V_at)echo "PAYLOAD_FOLLOWS" >> $@ @@ -108,4 +108,3 @@ shar installer: installer clean: rm -f *.swi *.installer *.cpio.gz - diff --git a/builds/armel/installer/PKG.yml b/builds/armel/installer/PKG.yml index 8cf5ff66..2dba5e13 100644 --- a/builds/armel/installer/PKG.yml +++ b/builds/armel/installer/PKG.yml @@ -1,2 +1 @@ -!include $ONL/builds/any/installer/new-hotness/APKG.yml ARCH=armel - +!include $ONL/builds/any/installer/APKG.yml ARCH=armel diff --git a/builds/armel/installer/builds/Makefile b/builds/armel/installer/builds/Makefile index e2eb47a8..f1443e22 100644 --- a/builds/armel/installer/builds/Makefile +++ b/builds/armel/installer/builds/Makefile @@ -1,2 +1,2 @@ include $(ONL)/make/config.armel.mk -include $(ONL)/builds/any/installer/new-hotness/uboot/builds/Makefile +include $(ONL)/builds/any/installer/uboot/builds/Makefile diff --git a/builds/powerpc/installer/PKG.yml b/builds/powerpc/installer/PKG.yml index c7c734e7..2bb3e575 100644 --- a/builds/powerpc/installer/PKG.yml +++ b/builds/powerpc/installer/PKG.yml @@ -1,2 +1 @@ -!include $ONL/builds/any/installer/new-hotness/APKG.yml ARCH=powerpc - +!include $ONL/builds/any/installer/APKG.yml ARCH=powerpc diff --git a/builds/powerpc/installer/builds/Makefile b/builds/powerpc/installer/builds/Makefile index e94db6bd..414f0bbb 100644 --- a/builds/powerpc/installer/builds/Makefile +++ b/builds/powerpc/installer/builds/Makefile @@ -1,2 +1,2 @@ include $(ONL)/make/config.powerpc.mk -include $(ONL)/builds/any/installer/new-hotness/uboot/builds/Makefile +include $(ONL)/builds/any/installer/uboot/builds/Makefile From 266608c85aa055e8e4ca9dcdbaefec01b7c02591 Mon Sep 17 00:00:00 2001 From: Jeffrey Townsend Date: Tue, 17 May 2016 01:39:34 +0000 Subject: [PATCH 061/113] Rename the legacy installer as such. If will be removed once the new installers are fully qualified on all platforms. --- Makefile | 6 +++--- builds/amd64/installer/legacy/builds/Makefile | 3 +-- builds/any/installer/legacy/APKG.yml | 14 ++------------ builds/any/installer/legacy/fit/builds/Makefile | 2 +- 4 files changed, 7 insertions(+), 18 deletions(-) diff --git a/Makefile b/Makefile index 743df60f..96dab5a6 100644 --- a/Makefile +++ b/Makefile @@ -23,7 +23,7 @@ onl-amd64 onl-x86 x86 x86_64 amd64: packages_base_all $(MAKE) -C packages/base/amd64/faultd $(MAKE) -C builds/amd64/rootfs $(MAKE) -C builds/amd64/swi - $(MAKE) -C builds/amd64/installer/legacy + $(MAKE) -C builds/amd64/installer onl-ppc ppc: packages_base_all $(MAKE) -C packages/base/powerpc/kernels @@ -34,7 +34,7 @@ onl-ppc ppc: packages_base_all $(MAKE) -C packages/base/powerpc/fit $(MAKE) -C builds/powerpc/rootfs $(MAKE) -C builds/powerpc/swi - $(MAKE) -C builds/powerpc/installer/legacy + $(MAKE) -C builds/powerpc/installer ifdef ONL_DEBIAN_SUITE_jessie @@ -51,7 +51,7 @@ onl-arm arm: arm_toolchain_check packages_base_all $(MAKE) -C packages/base/armel/fit $(MAKE) -C builds/armel/rootfs $(MAKE) -C builds/armel/swi - $(MAKE) -C builds/armel/installer/legacy + $(MAKE) -C builds/armel/installer else onl-arm arm: diff --git a/builds/amd64/installer/legacy/builds/Makefile b/builds/amd64/installer/legacy/builds/Makefile index 158cbf6c..c32b3bce 100644 --- a/builds/amd64/installer/legacy/builds/Makefile +++ b/builds/amd64/installer/legacy/builds/Makefile @@ -14,7 +14,7 @@ MKSHAR_PERMS = autoperms.sh # Hardcoded to match ONL File naming conventions. include $(ONL)/make/version-onl.mk -INSTALLER_NAME=$(FNAME_PRODUCT_VERSION)_ONL-OS_$(FNAME_BUILD_ID)_$(UARCH)_INSTALLER +INSTALLER_NAME=$(FNAME_PRODUCT_VERSION)_ONL-OS_$(FNAME_BUILD_ID)_$(UARCH)_LEGACY_INSTALLER @@ -41,4 +41,3 @@ shar installer: installer clean: rm -f *.swi *.installer $(notdir $(KERNELS)) initrd-amd64 - diff --git a/builds/any/installer/legacy/APKG.yml b/builds/any/installer/legacy/APKG.yml index cad485cf..a53d0129 100644 --- a/builds/any/installer/legacy/APKG.yml +++ b/builds/any/installer/legacy/APKG.yml @@ -10,8 +10,8 @@ common: maintainer: support@bigswitch.com packages: - - name: onl-installer - summary: Open Network Linux $ARCH Installer + - name: onl-legacy-installer + summary: Open Network Linux $ARCH Legacy Installer files: builds/*INSTALLER : $$PKG_INSTALL/ @@ -23,13 +23,3 @@ packages: release: - builds/*INSTALLER : $ARCH/ - builds/*.md5sum : $ARCH/ - - - - - - - - - - diff --git a/builds/any/installer/legacy/fit/builds/Makefile b/builds/any/installer/legacy/fit/builds/Makefile index 38609d49..ce7e1c65 100644 --- a/builds/any/installer/legacy/fit/builds/Makefile +++ b/builds/any/installer/legacy/fit/builds/Makefile @@ -6,7 +6,7 @@ THISDIR := $(dir $(lastword $(MAKEFILE_LIST))) # Hardcoded to match ONL File naming conventions. include $(ONL)/make/version-onl.mk -INSTALLER_NAME=$(FNAME_PRODUCT_VERSION)_ONL-OS_$(FNAME_BUILD_ID)_$(UARCH)_INSTALLER +INSTALLER_NAME=$(FNAME_PRODUCT_VERSION)_ONL-OS_$(FNAME_BUILD_ID)_$(UARCH)_LEGACY_INSTALLER FIT_IMAGE_ALL := $(shell $(ONLPM) --find-file onl-loader-fit:$(ARCH) onl-loader-fit.itb) From 837ad410219f89dcaf9824bd50ffbc5bcc451c57 Mon Sep 17 00:00:00 2001 From: Jeffrey Townsend Date: Tue, 17 May 2016 18:30:17 +0000 Subject: [PATCH 062/113] Fix connection configuration. --- .../any/rootfs/jessie/common/overlay/etc/snmp/snmpd.conf | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/builds/any/rootfs/jessie/common/overlay/etc/snmp/snmpd.conf b/builds/any/rootfs/jessie/common/overlay/etc/snmp/snmpd.conf index b885cb39..13eb88f7 100644 --- a/builds/any/rootfs/jessie/common/overlay/etc/snmp/snmpd.conf +++ b/builds/any/rootfs/jessie/common/overlay/etc/snmp/snmpd.conf @@ -12,7 +12,7 @@ # # Listen for connections from the local system only -agentAddress udp:127.0.0.1:161 +# agentAddress udp:127.0.0.1:161 # Listen for connections on all interfaces (both IPv4 *and* IPv6) agentAddress udp:161,udp6:[::1]:161 @@ -48,9 +48,9 @@ view systemonly included .1.3.6.1.4.1.42623 # Full access from the local host rocommunity public localhost # Default access to basic system info -rocommunity public default -V systemonly + rocommunity public default -V systemonly # rocommunity6 is for IPv6 -rocommunity6 public default -V systemonly + rocommunity6 public default -V systemonly # Full access from an example network # Adjust this network address to match your local @@ -139,7 +139,7 @@ load 12 10 5 # Event MIB - automatically generate alerts # # Remember to activate the 'createUser' lines above -iquerySecName internalUser +iquerySecName internalUser rouser internalUser # generate traps on UCD error conditions defaultMonitors yes From 8c8f7c35c1f718f2b5ac19eaafcc23e1cd670675 Mon Sep 17 00:00:00 2001 From: Jeffrey Townsend Date: Tue, 17 May 2016 12:45:55 -0700 Subject: [PATCH 063/113] Latest --- packages/platforms-closed | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/platforms-closed b/packages/platforms-closed index 3880b54f..1bea6253 160000 --- a/packages/platforms-closed +++ b/packages/platforms-closed @@ -1 +1 @@ -Subproject commit 3880b54fe9480edb6e8c2df7714d83e4e6aaf774 +Subproject commit 1bea6253f9814607df5c51a7cf5e1ee509331a37 From 80d06bec5a596ca335a72c29b8666511237d8490 Mon Sep 17 00:00:00 2001 From: Jeffrey Townsend Date: Tue, 17 May 2016 12:46:18 -0700 Subject: [PATCH 064/113] Remove comments. --- .../all/vendor-config-onl/src/python/onl/install/BaseInstall.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/base/all/vendor-config-onl/src/python/onl/install/BaseInstall.py b/packages/base/all/vendor-config-onl/src/python/onl/install/BaseInstall.py index 08e41e76..274268f9 100644 --- a/packages/base/all/vendor-config-onl/src/python/onl/install/BaseInstall.py +++ b/packages/base/all/vendor-config-onl/src/python/onl/install/BaseInstall.py @@ -358,7 +358,6 @@ class Base: return 0 GRUB_TPL = """\ -#serial --port=0x3f8 --speed=115200 --word=8 --parity=no --stop=1 serial %(serial)s terminal_input serial terminal_output serial @@ -369,7 +368,6 @@ menuentry OpenNetworkLinux { echo 'Loading Open Network Linux ...' insmod gzio insmod part_msdos - #linux /kernel-3.9.6-x86-64-all nopat console=ttyS0,115200n8 onl_platform=x86-64-kvm-x86-64-r0 linux /%(kernel)s %(args)s onl_platform=%(platform)s initrd /%(initrd)s } From 911183ee7f125bba18d594d275b276fbc368bf99 Mon Sep 17 00:00:00 2001 From: Jeffrey Townsend Date: Tue, 17 May 2016 12:46:58 -0700 Subject: [PATCH 065/113] Import from ONLP Repository. --- .../any/onlp/src/onlp/module/auto/onlp.yml | 2 + .../src/onlp/module/inc/onlp/platformi/sysi.h | 5 + .../any/onlp/src/onlp/module/inc/onlp/sfp.h | 2 + .../any/onlp/src/onlp/module/src/onlp_enums.c | 2 + .../any/onlp/src/onlp/module/src/onlp_main.c | 36 +- .../onlp/src/onlp/module/src/onlp_module.c | 24 + .../src/onlp/module/src/platform_manager.c | 1 + .../onlp_platform_defaults/module/src/sysi.c | 1 + .../onlp_platform_defaults.mk | 10 +- .../src/onlplib/module/inc/onlplib/thermal.h | 36 + .../any/onlp/src/onlplib/module/src/thermal.c | 51 + packages/base/any/onlp/src/onlplib/onlplib.mk | 10 +- .../base/any/onlp/src/sff/module/auto/sff.yml | 5 + .../any/onlp/src/sff/module/inc/sff/8436.h | 14 + .../any/onlp/src/sff/module/inc/sff/sff.h | 91 +- .../onlp/src/sff/module/inc/sff/sff_config.h | 10 + .../any/onlp/src/sff/module/inc/sff/sff_db.h | 60 + .../base/any/onlp/src/sff/module/src/sff.c | 450 ++--- .../any/onlp/src/sff/module/src/sff_config.c | 5 + .../base/any/onlp/src/sff/module/src/sff_db.c | 1468 +++++++++++++++++ .../any/onlp/src/sff/module/src/sff_enums.c | 2 + packages/base/any/onlp/src/sff/sff.mk | 10 +- packages/base/any/onlp/src/sff/utest/main.c | 1037 +----------- 23 files changed, 2050 insertions(+), 1282 deletions(-) create mode 100644 packages/base/any/onlp/src/onlplib/module/inc/onlplib/thermal.h create mode 100644 packages/base/any/onlp/src/onlplib/module/src/thermal.c create mode 100644 packages/base/any/onlp/src/sff/module/inc/sff/sff_db.h create mode 100644 packages/base/any/onlp/src/sff/module/src/sff_db.c diff --git a/packages/base/any/onlp/src/onlp/module/auto/onlp.yml b/packages/base/any/onlp/src/onlp/module/auto/onlp.yml index 47adc6e6..972d47eb 100644 --- a/packages/base/any/onlp/src/onlp/module/auto/onlp.yml +++ b/packages/base/any/onlp/src/onlp/module/auto/onlp.yml @@ -111,6 +111,7 @@ sfp_control: &sfp_control - RX_LOS - TX_FAULT - TX_DISABLE +- TX_DISABLE_CHANNEL - LP_MODE - POWER_OVERRIDE @@ -253,6 +254,7 @@ definitions: - RX_LOS - TX_FAULT - TX_DISABLE + - TX_DISABLE_CHANNEL - LP_MODE - POWER_OVERRIDE onlp_sfp_control_flag: diff --git a/packages/base/any/onlp/src/onlp/module/inc/onlp/platformi/sysi.h b/packages/base/any/onlp/src/onlp/module/inc/onlp/platformi/sysi.h index d4bde216..bc05146a 100644 --- a/packages/base/any/onlp/src/onlp/module/inc/onlp/platformi/sysi.h +++ b/packages/base/any/onlp/src/onlp/module/inc/onlp/platformi/sysi.h @@ -130,6 +130,11 @@ int onlp_sysi_oids_get(onlp_oid_t* table, int max); int onlp_sysi_ioctl(int code, va_list vargs); +/** + * @brief Platform management initialization. + */ +int onlp_sysi_platform_manage_init(void); + /** * @brief Perform necessary platform fan management. * @note This function should automatically adjust the FAN speeds diff --git a/packages/base/any/onlp/src/onlp/module/inc/onlp/sfp.h b/packages/base/any/onlp/src/onlp/module/inc/onlp/sfp.h index 6208e3ee..173a38ae 100644 --- a/packages/base/any/onlp/src/onlp/module/inc/onlp/sfp.h +++ b/packages/base/any/onlp/src/onlp/module/inc/onlp/sfp.h @@ -39,6 +39,7 @@ typedef enum onlp_sfp_control_e { ONLP_SFP_CONTROL_RX_LOS, ONLP_SFP_CONTROL_TX_FAULT, ONLP_SFP_CONTROL_TX_DISABLE, + ONLP_SFP_CONTROL_TX_DISABLE_CHANNEL, ONLP_SFP_CONTROL_LP_MODE, ONLP_SFP_CONTROL_POWER_OVERRIDE, ONLP_SFP_CONTROL_LAST = ONLP_SFP_CONTROL_POWER_OVERRIDE, @@ -238,6 +239,7 @@ int onlp_sfp_control_flags_get(int port, uint32_t* flags); "RX_LOS", \ "TX_FAULT", \ "TX_DISABLE", \ + "TX_DISABLE_CHANNEL", \ "LP_MODE", \ "POWER_OVERRIDE", \ } diff --git a/packages/base/any/onlp/src/onlp/module/src/onlp_enums.c b/packages/base/any/onlp/src/onlp/module/src/onlp_enums.c index 0c5a185f..f5c9a74d 100644 --- a/packages/base/any/onlp/src/onlp/module/src/onlp_enums.c +++ b/packages/base/any/onlp/src/onlp/module/src/onlp_enums.c @@ -728,6 +728,7 @@ aim_map_si_t onlp_sfp_control_map[] = { "RX_LOS", ONLP_SFP_CONTROL_RX_LOS }, { "TX_FAULT", ONLP_SFP_CONTROL_TX_FAULT }, { "TX_DISABLE", ONLP_SFP_CONTROL_TX_DISABLE }, + { "TX_DISABLE_CHANNEL", ONLP_SFP_CONTROL_TX_DISABLE_CHANNEL }, { "LP_MODE", ONLP_SFP_CONTROL_LP_MODE }, { "POWER_OVERRIDE", ONLP_SFP_CONTROL_POWER_OVERRIDE }, { NULL, 0 } @@ -740,6 +741,7 @@ aim_map_si_t onlp_sfp_control_desc_map[] = { "None", ONLP_SFP_CONTROL_RX_LOS }, { "None", ONLP_SFP_CONTROL_TX_FAULT }, { "None", ONLP_SFP_CONTROL_TX_DISABLE }, + { "None", ONLP_SFP_CONTROL_TX_DISABLE_CHANNEL }, { "None", ONLP_SFP_CONTROL_LP_MODE }, { "None", ONLP_SFP_CONTROL_POWER_OVERRIDE }, { NULL, 0 } diff --git a/packages/base/any/onlp/src/onlp/module/src/onlp_main.c b/packages/base/any/onlp/src/onlp/module/src/onlp_main.c index f20b1f0b..5afbb143 100644 --- a/packages/base/any/onlp/src/onlp/module/src/onlp_main.c +++ b/packages/base/any/onlp/src/onlp/module/src/onlp_main.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -38,7 +39,7 @@ static void platform_manager_daemon__(const char* pidfile, char** argv); * This should be moved to common. */ static void -show_inventory__(aim_pvs_t* pvs) +show_inventory__(aim_pvs_t* pvs, int database) { int port; onlp_sfp_bitmap_t bitmap; @@ -50,8 +51,10 @@ show_inventory__(aim_pvs_t* pvs) aim_printf(pvs, "No SFPs on this platform.\n"); } else { + if(!database) { aim_printf(pvs, "Port Type Media Status Len Vendor Model S/N \n"); aim_printf(pvs, "---- -------------- ------ ------ ----- ---------------- ---------------- ----------------\n"); + } AIM_BITMAP_ITER(&bitmap, port) { int rv; @@ -60,7 +63,9 @@ show_inventory__(aim_pvs_t* pvs) rv = onlp_sfp_is_present(port); if(rv == 0) { + if(!database) { aim_printf(pvs, "%4d NONE\n", port); + } continue; } @@ -76,17 +81,21 @@ show_inventory__(aim_pvs_t* pvs) continue; } - sff_info_t sff; + sff_eeprom_t sff; char status_str[32] = {0}; - sff_info_init(&sff, data); + sff_eeprom_parse(&sff, data); - if(!sff.supported) { + if(!sff.identified) { /* Present but unidentified. */ aim_printf(pvs, "%13d UNK\n", port); continue; } + if(database) { + sff_db_entry_struct(&sff, &aim_pvs_stdout); + continue; + } uint32_t status = 0; char* cp = status_str; @@ -105,13 +114,13 @@ show_inventory__(aim_pvs_t* pvs) } aim_printf(pvs, "%4d %-14s %-6s %-6.6s %-5.5s %-16.16s %-16.16s %16.16s\n", port, - sff.module_type_name, - sff.media_type_name, + sff.info.module_type_name, + sff.info.media_type_name, status_str, - sff.length_desc, - sff.vendor, - sff.model, - sff.serial); + sff.info.length_desc, + sff.info.vendor, + sff.info.model, + sff.info.serial); } } } @@ -170,6 +179,7 @@ onlpdump_main(int argc, char* argv[]) int S = 0; int l = 0; int M = 0; + int b = 0; char* pidfile = NULL; const char* O = NULL; const char* t = NULL; @@ -182,7 +192,7 @@ onlpdump_main(int argc, char* argv[]) return onlp_sys_debug(&aim_pvs_stdout, argc-2, argv+2); } - while( (c = getopt(argc, argv, "srehdojmyM:ipxlSt:O:")) != -1) { + while( (c = getopt(argc, argv, "srehdojmyM:ipxlSt:O:b")) != -1) { switch(c) { case 's': show=1; break; @@ -201,6 +211,7 @@ onlpdump_main(int argc, char* argv[]) case 'O': O = optarg; break; case 'S': S=1; break; case 'l': l=1; break; + case 'b': b=1; break; case 'y': show=1; showflags |= ONLP_OID_SHOW_F_YAML; break; default: help=1; rv = 1; break; } @@ -223,6 +234,7 @@ onlpdump_main(int argc, char* argv[]) printf(" -t Decode TlvInfo data.\n"); printf(" -O Dump OID.\n"); printf(" -S Decode SFP Inventory\n"); + printf(" -b Decode SFP Inventory into SFF database entries.\n"); printf(" -l API Lock test.\n"); return rv; } @@ -262,7 +274,7 @@ onlpdump_main(int argc, char* argv[]) } if(S) { - show_inventory__(&aim_pvs_stdout); + show_inventory__(&aim_pvs_stdout, b); return 0; } diff --git a/packages/base/any/onlp/src/onlp/module/src/onlp_module.c b/packages/base/any/onlp/src/onlp/module/src/onlp_module.c index 4d050bd2..541d3c6e 100644 --- a/packages/base/any/onlp/src/onlp/module/src/onlp_module.c +++ b/packages/base/any/onlp/src/onlp/module/src/onlp_module.c @@ -27,12 +27,36 @@ #include "onlp_log.h" #include +#include + +static int +onlp_aim_ts__onlp_oid(aim_datatype_context_t* dtc, aim_va_list_t* vargs, + const char** rv) +{ + onlp_oid_t oid = va_arg(vargs->val, onlp_oid_t); + int id = ONLP_OID_ID_GET(oid); + + switch(ONLP_OID_TYPE_GET(oid)) + { +#define ONLP_OID_TYPE_ENTRY(_name, _value) \ + case ONLP_OID_TYPE_##_name: \ + *rv = aim_fstrdup("%s:%d", #_name, id); \ + break; +#include + } + + return AIM_DATATYPE_OK; +} static int datatypes_init__(void) { #define ONLP_ENUMERATION_ENTRY(_enum_name, _desc) AIM_DATATYPE_MAP_REGISTER(_enum_name, _enum_name##_map, _desc, AIM_LOG_INTERNAL); #include + aim_datatype_register(0, "onlp_oid", + "ONLP OID", + NULL, + onlp_aim_ts__onlp_oid, NULL); /* diff --git a/packages/base/any/onlp/src/onlp/module/src/platform_manager.c b/packages/base/any/onlp/src/onlp/module/src/platform_manager.c index dfcba142..75054d6f 100644 --- a/packages/base/any/onlp/src/onlp/module/src/platform_manager.c +++ b/packages/base/any/onlp/src/onlp/module/src/platform_manager.c @@ -134,6 +134,7 @@ onlp_sys_platform_manage_init(void) int i; uint64_t now = os_time_monotonic(); + onlp_sysi_platform_manage_init(); control__.tw = timer_wheel_create(4, 512, now); for(i = 0; i < AIM_ARRAYSIZE(management_entries); i++) { diff --git a/packages/base/any/onlp/src/onlp_platform_defaults/module/src/sysi.c b/packages/base/any/onlp/src/onlp_platform_defaults/module/src/sysi.c index 76b66ab7..c5146f21 100644 --- a/packages/base/any/onlp/src/onlp_platform_defaults/module/src/sysi.c +++ b/packages/base/any/onlp/src/onlp_platform_defaults/module/src/sysi.c @@ -65,6 +65,7 @@ __ONLP_DEFAULTI_IMPLEMENTATION(onlp_sysi_oids_get(onlp_oid_t* table, int max)); __ONLP_DEFAULTI_IMPLEMENTATION(onlp_sysi_platform_info_get(onlp_platform_info_t* pi)); __ONLP_DEFAULTI_VIMPLEMENTATION(onlp_sysi_platform_info_free(onlp_platform_info_t* pi)); __ONLP_DEFAULTI_IMPLEMENTATION(onlp_sysi_ioctl(int id, va_list vargs)); +__ONLP_DEFAULTI_IMPLEMENTATION(onlp_sysi_platform_manage_init(void)); __ONLP_DEFAULTI_IMPLEMENTATION(onlp_sysi_platform_manage_fans(void)); __ONLP_DEFAULTI_IMPLEMENTATION(onlp_sysi_platform_manage_leds(void)); diff --git a/packages/base/any/onlp/src/onlp_platform_defaults/onlp_platform_defaults.mk b/packages/base/any/onlp/src/onlp_platform_defaults/onlp_platform_defaults.mk index 301c4fe0..fa66350e 100644 --- a/packages/base/any/onlp/src/onlp_platform_defaults/onlp_platform_defaults.mk +++ b/packages/base/any/onlp/src/onlp_platform_defaults/onlp_platform_defaults.mk @@ -3,12 +3,12 @@ # # Inclusive Makefile for the onlp_platform_defaults module. # -# Autogenerated 2016-03-23 18:28:25.688419 +# Autogenerated 2016-05-17 17:43:05.660985 # ############################################################################### onlp_platform_defaults_BASEDIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) -include $(onlp_platform_defaults_BASEDIR)/module/make.mk -include $(onlp_platform_defaults_BASEDIR)/module/auto/make.mk -include $(onlp_platform_defaults_BASEDIR)/module/src/make.mk -include $(onlp_platform_defaults_BASEDIR)/utest/_make.mk +include $(onlp_platform_defaults_BASEDIR)module/make.mk +include $(onlp_platform_defaults_BASEDIR)module/auto/make.mk +include $(onlp_platform_defaults_BASEDIR)module/src/make.mk +include $(onlp_platform_defaults_BASEDIR)utest/_make.mk diff --git a/packages/base/any/onlp/src/onlplib/module/inc/onlplib/thermal.h b/packages/base/any/onlp/src/onlplib/module/inc/onlplib/thermal.h new file mode 100644 index 00000000..025e90a4 --- /dev/null +++ b/packages/base/any/onlp/src/onlplib/module/inc/onlplib/thermal.h @@ -0,0 +1,36 @@ +/************************************************************** + * + * + * Copyright 2014, 2015 Big Switch Networks, Inc. + * + * Licensed under the Eclipse Public License, Version 1.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.eclipse.org/legal/epl-v10.html + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + * + * + ************************************************************** + * + * Common thermal support routines. + * + ************************************************************/ +#ifndef __ONLPLIB_THERMAL_H__ +#define __ONLPLIB_THERMAL_H__ +#include +#include +/** + * @brief Read the mcelsius value from the given file. + * @param fname Filename + * @param info Thermal info structure. + */ +int onlplib_thermal_read_file(const char* fname, onlp_thermal_info_t* info); + +#endif /* __ONLPLIB_THERMAL_H__ */ diff --git a/packages/base/any/onlp/src/onlplib/module/src/thermal.c b/packages/base/any/onlp/src/onlplib/module/src/thermal.c new file mode 100644 index 00000000..32d1c931 --- /dev/null +++ b/packages/base/any/onlp/src/onlplib/module/src/thermal.c @@ -0,0 +1,51 @@ +/************************************************************** + * + * + * Copyright 2014, 2015 Big Switch Networks, Inc. + * + * Licensed under the Eclipse Public License, Version 1.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.eclipse.org/legal/epl-v10.html + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + * + * + ************************************************************** + * + * Common thermal support routines. + * + ************************************************************/ +#include +#include +#include + +int +onlplib_thermal_read_file(const char* fname, onlp_thermal_info_t* info) +{ + int ret; + int rv = onlp_file_read_int(&info->mcelsius, fname); + + if(rv == ONLP_STATUS_E_MISSING) { + /* Absent */ + info->status = 0; + ret = 0; + } + else if(rv >= 0) { + /* Present */ + info->status |= 1; + ret = 0; + } + else { + /** Other error. */ + ret = ONLP_STATUS_E_INTERNAL; + } + return ret; +} + diff --git a/packages/base/any/onlp/src/onlplib/onlplib.mk b/packages/base/any/onlp/src/onlplib/onlplib.mk index 889b3b94..c33c4de3 100644 --- a/packages/base/any/onlp/src/onlplib/onlplib.mk +++ b/packages/base/any/onlp/src/onlplib/onlplib.mk @@ -3,12 +3,12 @@ # # Inclusive Makefile for the onlplib module. # -# Autogenerated 2016-03-23 18:28:25.806397 +# Autogenerated 2016-05-17 17:43:05.779760 # ############################################################################### onlplib_BASEDIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) -include $(onlplib_BASEDIR)/module/make.mk -include $(onlplib_BASEDIR)/module/auto/make.mk -include $(onlplib_BASEDIR)/module/src/make.mk -include $(onlplib_BASEDIR)/utest/_make.mk +include $(onlplib_BASEDIR)module/make.mk +include $(onlplib_BASEDIR)module/auto/make.mk +include $(onlplib_BASEDIR)module/src/make.mk +include $(onlplib_BASEDIR)utest/_make.mk diff --git a/packages/base/any/onlp/src/sff/module/auto/sff.yml b/packages/base/any/onlp/src/sff/module/auto/sff.yml index dd31d020..3ccd142c 100644 --- a/packages/base/any/onlp/src/sff/module/auto/sff.yml +++ b/packages/base/any/onlp/src/sff/module/auto/sff.yml @@ -32,6 +32,9 @@ cdefs: &cdefs - SFF_CONFIG_INCLUDE_EXT_CC_CHECK: doc: "Include extended checksum verification." default: 0 +- SFF_CONFIG_INCLUDE_DATABASE: + doc: "Include eeprom database." + default: 1 sff_media_types: &sff_media_types - COPPER: @@ -56,6 +59,8 @@ sff_module_types: &sff_module_types desc: "40GBASE-SR4" - 40G_BASE_LR4: desc: "40GBASE-LR4" +- 40G_BASE_LM4: + desc: "40GBASE-LM4" - 40G_BASE_ACTIVE: desc: "40GBASE-ACTIVE" - 40G_BASE_CR: diff --git a/packages/base/any/onlp/src/sff/module/inc/sff/8436.h b/packages/base/any/onlp/src/sff/module/inc/sff/8436.h index 3bedc8f8..d2c0e35f 100644 --- a/packages/base/any/onlp/src/sff/module/inc/sff/8436.h +++ b/packages/base/any/onlp/src/sff/module/inc/sff/8436.h @@ -224,6 +224,8 @@ #define SFF8436_DOM_GET_RXPWR_TYPE(idprom) \ (idprom[220] & SFF8436_RX_PWR_TYPE_MASK) +/* SFF8436 registers */ +#define SFF8436_CONTROL_TX_DISABLE 86 /* alternate ways to identify pre-standard 40G cables */ static inline int _sff8436_qsfp_40g_pre(const uint8_t* idprom) @@ -255,6 +257,18 @@ _sff8436_qsfp_40g_pre(const uint8_t* idprom) return 0; } +static inline int +_sff8436_qsfp_40g_lm4(const uint8_t* idprom) +{ + if(!SFF8436_MODULE_QSFP_PLUS_V2(idprom)) { + return 0; + } + /* Restrict to Finisar FTL4C3QE1C at this point. */ + if(strncmp("FTL4C3QE1C ", (char*)idprom+168, 16)) { + return 0; + } + return SFF8436_MEDIA_NONE(idprom); +} static inline int _sff8436_bitrate(const uint8_t *idprom) diff --git a/packages/base/any/onlp/src/sff/module/inc/sff/sff.h b/packages/base/any/onlp/src/sff/module/inc/sff/sff.h index cd110cdb..20e3b3f4 100644 --- a/packages/base/any/onlp/src/sff/module/inc/sff/sff.h +++ b/packages/base/any/onlp/src/sff/module/inc/sff/sff.h @@ -1,21 +1,21 @@ /************************************************************ * - * - * Copyright 2014, 2015 Big Switch Networks, Inc. - * + * + * Copyright 2014, 2015 Big Switch Networks, Inc. + * * Licensed under the Eclipse Public License, Version 1.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.eclipse.org/legal/epl-v10.html - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, * either express or implied. See the License for the specific * language governing permissions and limitations under the * License. - * + * * ************************************************************ * @@ -103,6 +103,7 @@ typedef enum sff_module_type_e { SFF_MODULE_TYPE_40G_BASE_CR4, SFF_MODULE_TYPE_40G_BASE_SR4, SFF_MODULE_TYPE_40G_BASE_LR4, + SFF_MODULE_TYPE_40G_BASE_LM4, SFF_MODULE_TYPE_40G_BASE_ACTIVE, SFF_MODULE_TYPE_40G_BASE_CR, SFF_MODULE_TYPE_40G_BASE_SR2, @@ -137,6 +138,7 @@ typedef enum sff_module_type_e { "40G_BASE_CR4", \ "40G_BASE_SR4", \ "40G_BASE_LR4", \ + "40G_BASE_LM4", \ "40G_BASE_ACTIVE", \ "40G_BASE_CR", \ "40G_BASE_SR2", \ @@ -228,7 +230,7 @@ sff_module_type_t sff_module_type_get(const uint8_t* idprom); * @brief Determine the SFF Media type (from the idprom data)./ * @param idprom The SFF idprom. */ -sff_media_type_t sff_media_type_get(const uint8_t* idprom); +sff_media_type_t sff_media_type_get(sff_module_type_t mt); /** @@ -238,45 +240,35 @@ sff_media_type_t sff_media_type_get(const uint8_t* idprom); * @returns 0 on successful parse. * @returns < 0 on error. */ -int sff_module_caps_get(const uint8_t* idprom, uint32_t* caps); +int sff_module_caps_get(sff_module_type_t mt, uint32_t* caps); -/** - * Display a summary of the given SFF module. - * @param idprom The idprom data - * @param pvs The output pvs. - */ - -void sff_module_show(const uint8_t* idprom, aim_pvs_t* pvs); - - - -/** - * SFF Module Information Structure - */ typedef struct sff_info_s { - /** Raw eeprom data */ - uint8_t eeprom[256]; /** Vendor Name */ char vendor[17]; + /** Model Number */ char model[17]; + /** Serial Number */ char serial[17]; /** SFP Type */ sff_sfp_type_t sfp_type; + /** SFP Type Name */ const char* sfp_type_name; /** Module Type */ sff_module_type_t module_type; + /** Module Type Name */ const char* module_type_name; /** Media Type */ sff_media_type_t media_type; + /** Media Type Name */ const char* media_type_name; @@ -286,15 +278,26 @@ typedef struct sff_info_s { /** Cable length, if available */ int length; char length_desc[16]; +} sff_info_t; - /** computed checksums for idprom contents */ +/** + * SFF Module Information Structure + */ +typedef struct sff_eeprom_s { + /** Raw eeprom data */ + uint8_t eeprom[256]; + + /** computed checksums for eeprom contents */ uint8_t cc_base; uint8_t cc_ext; - /** whether this SFP is supported */ - int supported; + /** Whether this EEPROM was successfully parsed and identified. */ + int identified; -} sff_info_t; + /** Parsed SFF Information */ + sff_info_t info; + +} sff_eeprom_t; /** @@ -305,14 +308,28 @@ typedef struct sff_info_s { * @note if eeprom is NULL it is assumed the rv->eeprom buffer * has already been initialized. */ -int sff_info_init(sff_info_t* rv, uint8_t* eeprom); +int sff_eeprom_parse(sff_eeprom_t* rv, uint8_t* eeprom); /** * @brief Initialize an SFF module information structure from a file. * @param rv [out] Receives thh data. * @param fname The filename. */ -int sff_info_init_file(sff_info_t* rv, const char* fname); +int sff_eeprom_parse_file(sff_eeprom_t* rv, const char* fname); + +/** + * @brief Clear an sff_eeprom_t structure. + * @param eeprom The eeprom structure. + */ +void sff_eeprom_invalidate(sff_eeprom_t *info); + +/** + * @brief Determine if this is a valid SFP + * (whether or not we can parse it) + * @param info The info structure. + * @param verbose Whether to report errors on invalid contents. + */ +int sff_eeprom_validate(sff_eeprom_t *info, int verbose); /** * @brief Show an sff info structure. @@ -322,18 +339,12 @@ int sff_info_init_file(sff_info_t* rv, const char* fname); void sff_info_show(sff_info_t* info, aim_pvs_t* pvs); /** - * @brief Invalidate an idprom data structure, - * such that any resulting sff_info_init will fail. - * @param eeprom The idprom buffer (256 bytes). + * @brief Populate an SFF info structure from a module type. */ -void sff_info_invalidate(sff_info_t *info); +int sff_info_from_module_type(sff_info_t* info, + sff_sfp_type_t st, + sff_module_type_t mt); + -/** - * @brief Determine if this is a valid SFP - * (whether or not we can parse it) - * @param info The info structure. - * @param verbose Whether to report errors on invalid contents. - */ -int sff_info_valid(sff_info_t *info, int verbose); #endif /* __SFF_SFF_H__ */ diff --git a/packages/base/any/onlp/src/sff/module/inc/sff/sff_config.h b/packages/base/any/onlp/src/sff/module/inc/sff/sff_config.h index 966d24c4..c3e5d6de 100644 --- a/packages/base/any/onlp/src/sff/module/inc/sff/sff_config.h +++ b/packages/base/any/onlp/src/sff/module/inc/sff/sff_config.h @@ -109,6 +109,16 @@ #define SFF_CONFIG_INCLUDE_EXT_CC_CHECK 0 #endif +/** + * SFF_CONFIG_INCLUDE_DATABASE + * + * Include eeprom database. */ + + +#ifndef SFF_CONFIG_INCLUDE_DATABASE +#define SFF_CONFIG_INCLUDE_DATABASE 1 +#endif + /** diff --git a/packages/base/any/onlp/src/sff/module/inc/sff/sff_db.h b/packages/base/any/onlp/src/sff/module/inc/sff/sff_db.h new file mode 100644 index 00000000..2242cd57 --- /dev/null +++ b/packages/base/any/onlp/src/sff/module/inc/sff/sff_db.h @@ -0,0 +1,60 @@ +/************************************************************ + * + * + * Copyright 2014, 2015 Big Switch Networks, Inc. + * + * Licensed under the Eclipse Public License, Version 1.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.eclipse.org/legal/epl-v10.html + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + * + * + ************************************************************ + * + * + * + ***********************************************************/ +#ifndef __SFF_DB_H__ +#define __SFF_DB_H__ + +#include +#include +#include + +typedef struct { + sff_eeprom_t se; +} sff_db_entry_t; + +/** + * @brief Get the database entry table. + * @param entries Receives the table pointer. + * @param count Receives the size of the table. + */ +int sff_db_get(sff_db_entry_t** entries, int* count); + +/** + * @brief Return any entry with the given module type. + * @param se Receives the information struct. + * @param type The type to retreive. + */ +int sff_db_get_type(sff_eeprom_t* se, sff_module_type_t type); + + +/** + * @brief Output the given SFF information to a database entry. + * @param info The source information. + * @param pvs The output pvs.; + * @note This is used mainly for generating new entries for the SFF db from a running system. + */ +int sff_db_entry_struct(sff_eeprom_t* se, aim_pvs_t* pvs); + +#endif /* __SFF_DB_H__ */ + diff --git a/packages/base/any/onlp/src/sff/module/src/sff.c b/packages/base/any/onlp/src/sff/module/src/sff.c index 20650c0e..74cad3e5 100644 --- a/packages/base/any/onlp/src/sff/module/src/sff.c +++ b/packages/base/any/onlp/src/sff/module/src/sff.c @@ -1,21 +1,21 @@ /************************************************************ * - * - * Copyright 2014, 2015 Big Switch Networks, Inc. - * + * + * Copyright 2014, 2015 Big Switch Networks, Inc. + * * Licensed under the Eclipse Public License, Version 1.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.eclipse.org/legal/epl-v10.html - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, * either express or implied. See the License for the specific * language governing permissions and limitations under the * License. - * + * * ************************************************************ * @@ -30,16 +30,16 @@ #include sff_sfp_type_t -sff_sfp_type_get(const uint8_t* idprom) +sff_sfp_type_get(const uint8_t* eeprom) { - if(idprom) { - if(SFF8472_MODULE_SFP(idprom)) { + if(eeprom) { + if(SFF8472_MODULE_SFP(eeprom)) { return SFF_SFP_TYPE_SFP; } - if(SFF8436_MODULE_QSFP_PLUS_V2(idprom)) { + if(SFF8436_MODULE_QSFP_PLUS_V2(eeprom)) { return SFF_SFP_TYPE_QSFP_PLUS; } - if(SFF8636_MODULE_QSFP28(idprom)) { + if(SFF8636_MODULE_QSFP28(eeprom)) { return SFF_SFP_TYPE_QSFP28; } } @@ -47,92 +47,97 @@ sff_sfp_type_get(const uint8_t* idprom) } sff_module_type_t -sff_module_type_get(const uint8_t* idprom) +sff_module_type_get(const uint8_t* eeprom) { - if (SFF8636_MODULE_QSFP28(idprom) - && SFF8636_MEDIA_EXTENDED(idprom) - && SFF8636_MEDIA_100GE_AOC(idprom)) + if (SFF8636_MODULE_QSFP28(eeprom) + && SFF8636_MEDIA_EXTENDED(eeprom) + && SFF8636_MEDIA_100GE_AOC(eeprom)) return SFF_MODULE_TYPE_100G_AOC; - if (SFF8636_MODULE_QSFP28(idprom) - && SFF8636_MEDIA_EXTENDED(idprom) - && SFF8636_MEDIA_100GE_SR4(idprom)) + if (SFF8636_MODULE_QSFP28(eeprom) + && SFF8636_MEDIA_EXTENDED(eeprom) + && SFF8636_MEDIA_100GE_SR4(eeprom)) return SFF_MODULE_TYPE_100G_BASE_SR4; - if (SFF8636_MODULE_QSFP28(idprom) - && SFF8636_MEDIA_EXTENDED(idprom) - && SFF8636_MEDIA_100GE_LR4(idprom)) + if (SFF8636_MODULE_QSFP28(eeprom) + && SFF8636_MEDIA_EXTENDED(eeprom) + && SFF8636_MEDIA_100GE_LR4(eeprom)) return SFF_MODULE_TYPE_100G_BASE_LR4; - if (SFF8636_MODULE_QSFP28(idprom) - && SFF8636_MEDIA_EXTENDED(idprom) - && SFF8636_MEDIA_100GE_CR4(idprom)) + if (SFF8636_MODULE_QSFP28(eeprom) + && SFF8636_MEDIA_EXTENDED(eeprom) + && SFF8636_MEDIA_100GE_CR4(eeprom)) return SFF_MODULE_TYPE_100G_BASE_CR4; - if (SFF8636_MODULE_QSFP28(idprom) - && SFF8636_MEDIA_EXTENDED(idprom) - && SFF8636_MEDIA_100GE_CWDM4(idprom)) + if (SFF8636_MODULE_QSFP28(eeprom) + && SFF8636_MEDIA_EXTENDED(eeprom) + && SFF8636_MEDIA_100GE_CWDM4(eeprom)) return SFF_MODULE_TYPE_100G_CWDM4; - - if (SFF8436_MODULE_QSFP_PLUS_V2(idprom) - && SFF8436_MEDIA_40GE_CR4(idprom)) + + if (SFF8436_MODULE_QSFP_PLUS_V2(eeprom) + && SFF8436_MEDIA_40GE_CR4(eeprom)) return SFF_MODULE_TYPE_40G_BASE_CR4; - if (SFF8436_MODULE_QSFP_PLUS_V2(idprom) - && SFF8436_MEDIA_40GE_SR4(idprom)) + if (SFF8436_MODULE_QSFP_PLUS_V2(eeprom) + && SFF8436_MEDIA_40GE_SR4(eeprom)) return SFF_MODULE_TYPE_40G_BASE_SR4; - if (SFF8436_MODULE_QSFP_PLUS_V2(idprom) - && _sff8436_qsfp_40g_sr4_aoc_pre(idprom)) + if (SFF8436_MODULE_QSFP_PLUS_V2(eeprom) + && _sff8436_qsfp_40g_sr4_aoc_pre(eeprom)) return SFF_MODULE_TYPE_40G_BASE_SR4; - if (SFF8436_MODULE_QSFP_PLUS_V2(idprom) - && SFF8436_MEDIA_40GE_LR4(idprom)) + if (SFF8436_MODULE_QSFP_PLUS_V2(eeprom) + && SFF8436_MEDIA_40GE_LR4(eeprom)) return SFF_MODULE_TYPE_40G_BASE_LR4; - if (SFF8436_MODULE_QSFP_PLUS_V2(idprom) - && SFF8436_MEDIA_40GE_ACTIVE(idprom)) + if (SFF8436_MODULE_QSFP_PLUS_V2(eeprom) + && SFF8436_MEDIA_40GE_ACTIVE(eeprom)) return SFF_MODULE_TYPE_40G_BASE_ACTIVE; - if (SFF8436_MODULE_QSFP_PLUS_V2(idprom) - && _sff8436_qsfp_40g_aoc_breakout(idprom)) + if (SFF8436_MODULE_QSFP_PLUS_V2(eeprom) + && _sff8436_qsfp_40g_aoc_breakout(eeprom)) return SFF_MODULE_TYPE_40G_BASE_SR4; - if (SFF8436_MODULE_QSFP_PLUS_V2(idprom) - && SFF8436_MEDIA_40GE_CR(idprom)) + if (SFF8436_MODULE_QSFP_PLUS_V2(eeprom) + && SFF8436_MEDIA_40GE_CR(eeprom)) return SFF_MODULE_TYPE_40G_BASE_CR; /* pre-standard finisar optics */ - if (SFF8436_MODULE_QSFP_PLUS_V2(idprom) - && _sff8436_qsfp_40g_pre(idprom) - && (SFF8436_TECH_FC_FIBER_LONG(idprom) - || SFF8436_MEDIA_FC_FIBER_SM(idprom))) + if (SFF8436_MODULE_QSFP_PLUS_V2(eeprom) + && _sff8436_qsfp_40g_pre(eeprom) + && (SFF8436_TECH_FC_FIBER_LONG(eeprom) + || SFF8436_MEDIA_FC_FIBER_SM(eeprom))) return SFF_MODULE_TYPE_40G_BASE_LR4; - if (SFF8436_MODULE_QSFP_PLUS_V2(idprom) - && _sff8436_qsfp_40g_pre(idprom) - && (SFF8436_TECH_FC_FIBER_SHORT(idprom) - || SFF8436_MEDIA_FC_FIBER_MM(idprom))) + if (SFF8436_MODULE_QSFP_PLUS_V2(eeprom) + && _sff8436_qsfp_40g_pre(eeprom) + && (SFF8436_TECH_FC_FIBER_SHORT(eeprom) + || SFF8436_MEDIA_FC_FIBER_MM(eeprom))) return SFF_MODULE_TYPE_40G_BASE_SR4; /* pre-standard QSFP-BiDi optics */ - if (SFF8436_MODULE_QSFP_PLUS_V2(idprom) - && _sff8436_qsfp_40g_sr2_bidi_pre(idprom)) + if (SFF8436_MODULE_QSFP_PLUS_V2(eeprom) + && _sff8436_qsfp_40g_sr2_bidi_pre(eeprom)) return SFF_MODULE_TYPE_40G_BASE_SR2; - if (SFF8472_MODULE_SFP(idprom) - && SFF8472_MEDIA_XGE_SR(idprom) - && !_sff8472_media_gbe_sx_fc_hack(idprom)) + if (SFF8436_MODULE_QSFP_PLUS_V2(eeprom) + && _sff8436_qsfp_40g_lm4(eeprom)) { + return SFF_MODULE_TYPE_40G_BASE_LM4; + } + + if (SFF8472_MODULE_SFP(eeprom) + && SFF8472_MEDIA_XGE_SR(eeprom) + && !_sff8472_media_gbe_sx_fc_hack(eeprom)) return SFF_MODULE_TYPE_10G_BASE_SR; - if (SFF8472_MODULE_SFP(idprom) - && SFF8472_MEDIA_XGE_LR(idprom) - && !_sff8472_media_gbe_lx_fc_hack(idprom)) + if (SFF8472_MODULE_SFP(eeprom) + && SFF8472_MEDIA_XGE_LR(eeprom) + && !_sff8472_media_gbe_lx_fc_hack(eeprom)) return SFF_MODULE_TYPE_10G_BASE_LR; - if (SFF8472_MODULE_SFP(idprom) - && SFF8472_MEDIA_XGE_LRM(idprom) - && !_sff8472_media_gbe_lx_fc_hack(idprom)) + if (SFF8472_MODULE_SFP(eeprom) + && SFF8472_MEDIA_XGE_LRM(eeprom) + && !_sff8472_media_gbe_lx_fc_hack(eeprom)) return SFF_MODULE_TYPE_10G_BASE_LRM; /* @@ -141,71 +146,69 @@ sff_module_type_get(const uint8_t* idprom) * See also _sff8472_media_cr_passive, which encodes some * additional workarounds for these cables. */ - if (SFF8472_MODULE_SFP(idprom) - && SFF8472_MEDIA_XGE_ER(idprom) - && !_sff8472_inf_1x_cu_active(idprom) - && !_sff8472_inf_1x_cu_passive(idprom)) + if (SFF8472_MODULE_SFP(eeprom) + && SFF8472_MEDIA_XGE_ER(eeprom) + && !_sff8472_inf_1x_cu_active(eeprom) + && !_sff8472_inf_1x_cu_passive(eeprom)) return SFF_MODULE_TYPE_10G_BASE_ER; /* XXX roth - not sure on this one */ - if (SFF8472_MODULE_SFP(idprom) - && _sff8472_media_cr_passive(idprom)) + if (SFF8472_MODULE_SFP(eeprom) + && _sff8472_media_cr_passive(eeprom)) return SFF_MODULE_TYPE_10G_BASE_CR; - if (SFF8472_MODULE_SFP(idprom) - && _sff8472_media_cr_active(idprom)) { - if (_sff8472_sfp_10g_aoc(idprom)) + if (SFF8472_MODULE_SFP(eeprom) + && _sff8472_media_cr_active(eeprom)) { + if (_sff8472_sfp_10g_aoc(eeprom)) return SFF_MODULE_TYPE_10G_BASE_SR; else return SFF_MODULE_TYPE_10G_BASE_CR; } - if (SFF8472_MODULE_SFP(idprom) - && SFF8472_MEDIA_GBE_SX(idprom)) + if (SFF8472_MODULE_SFP(eeprom) + && SFF8472_MEDIA_GBE_SX(eeprom)) return SFF_MODULE_TYPE_1G_BASE_SX; - if (SFF8472_MODULE_SFP(idprom) - && SFF8472_MEDIA_GBE_LX(idprom)) + if (SFF8472_MODULE_SFP(eeprom) + && SFF8472_MEDIA_GBE_LX(eeprom)) return SFF_MODULE_TYPE_1G_BASE_LX; - if (SFF8472_MODULE_SFP(idprom) - && SFF8472_MEDIA_GBE_CX(idprom)) + if (SFF8472_MODULE_SFP(eeprom) + && SFF8472_MEDIA_GBE_CX(eeprom)) return SFF_MODULE_TYPE_1G_BASE_CX; - if (SFF8472_MODULE_SFP(idprom) - && SFF8472_MEDIA_GBE_T(idprom)) + if (SFF8472_MODULE_SFP(eeprom) + && SFF8472_MEDIA_GBE_T(eeprom)) return SFF_MODULE_TYPE_1G_BASE_T; - if (SFF8472_MODULE_SFP(idprom) - && SFF8472_MEDIA_GBE_LX(idprom)) + if (SFF8472_MODULE_SFP(eeprom) + && SFF8472_MEDIA_GBE_LX(eeprom)) return SFF_MODULE_TYPE_1G_BASE_LX; - if (SFF8472_MODULE_SFP(idprom) - && SFF8472_MEDIA_CBE_LX(idprom)) + if (SFF8472_MODULE_SFP(eeprom) + && SFF8472_MEDIA_CBE_LX(eeprom)) return SFF_MODULE_TYPE_100_BASE_LX; - if (SFF8472_MODULE_SFP(idprom) - && SFF8472_MEDIA_CBE_FX(idprom)) + if (SFF8472_MODULE_SFP(eeprom) + && SFF8472_MEDIA_CBE_FX(eeprom)) return SFF_MODULE_TYPE_100_BASE_FX; /* non-standard (e.g. Finisar) ZR media */ - if (SFF8472_MODULE_SFP(idprom) - && _sff8472_media_zr(idprom)) + if (SFF8472_MODULE_SFP(eeprom) + && _sff8472_media_zr(eeprom)) return SFF_MODULE_TYPE_10G_BASE_ZR; /* non-standard (e.g. Finisar) SRL media */ - if (SFF8472_MODULE_SFP(idprom) - && _sff8472_media_srlite(idprom)) + if (SFF8472_MODULE_SFP(eeprom) + && _sff8472_media_srlite(eeprom)) return SFF_MODULE_TYPE_10G_BASE_SRL; return SFF_MODULE_TYPE_INVALID; } sff_media_type_t -sff_media_type_get(const uint8_t* idprom) +sff_media_type_get(sff_module_type_t mt) { - sff_module_type_t mt = sff_module_type_get(idprom); - switch(mt) { case SFF_MODULE_TYPE_100G_BASE_CR4: @@ -222,6 +225,7 @@ sff_media_type_get(const uint8_t* idprom) case SFF_MODULE_TYPE_100G_CWDM4: case SFF_MODULE_TYPE_40G_BASE_SR4: case SFF_MODULE_TYPE_40G_BASE_LR4: + case SFF_MODULE_TYPE_40G_BASE_LM4: case SFF_MODULE_TYPE_40G_BASE_ACTIVE: case SFF_MODULE_TYPE_40G_BASE_SR2: case SFF_MODULE_TYPE_10G_BASE_SR: @@ -247,14 +251,11 @@ sff_media_type_get(const uint8_t* idprom) } int -sff_module_caps_get(const uint8_t* idprom, uint32_t *caps) +sff_module_caps_get(sff_module_type_t mt, uint32_t *caps) { - if (idprom == NULL) - return -1; if (caps == NULL) return -1; - sff_module_type_t mt = sff_module_type_get(idprom); *caps = 0; switch(mt) @@ -270,6 +271,7 @@ sff_module_caps_get(const uint8_t* idprom, uint32_t *caps) case SFF_MODULE_TYPE_40G_BASE_CR4: case SFF_MODULE_TYPE_40G_BASE_SR4: case SFF_MODULE_TYPE_40G_BASE_LR4: + case SFF_MODULE_TYPE_40G_BASE_LM4: case SFF_MODULE_TYPE_40G_BASE_ACTIVE: case SFF_MODULE_TYPE_40G_BASE_CR: case SFF_MODULE_TYPE_40G_BASE_SR2: @@ -305,24 +307,6 @@ sff_module_caps_get(const uint8_t* idprom, uint32_t *caps) } } -void -sff_module_show(const uint8_t* idprom, aim_pvs_t* pvs) -{ - - if (SFF8436_MODULE_QSFP_PLUS_V2(idprom) || - SFF8636_MODULE_QSFP28(idprom)) { - aim_printf(pvs, - "%-12.12s %-16.16s %-16.16s %-16.16s\n", - sff_module_type_desc(sff_module_type_get(idprom)), - idprom+148, idprom+168, idprom+196); - } else { - aim_printf(pvs, - "%-12.12s %-16.16s %-16.16s %-16.16s\n", - sff_module_type_desc(sff_module_type_get(idprom)), - idprom+20, idprom+40, idprom+68); - } -} - static void make_printable__(char* string) { @@ -342,154 +326,176 @@ make_printable__(char* string) * @note if eeprom is NULL it is assumed the rv->eeprom buffer * has already been initialized. */ + int -sff_info_init(sff_info_t* rv, uint8_t* eeprom) +sff_eeprom_parse(sff_eeprom_t* se, uint8_t* eeprom) { - if(rv == NULL) { + if(se == NULL) { return -1; } - rv->supported = 0; + se->identified = 0; if(eeprom) { - SFF_MEMCPY(rv->eeprom, eeprom, 256); + SFF_MEMCPY(se->eeprom, eeprom, 256); } - if (SFF8472_MODULE_SFP(rv->eeprom)) { + if (SFF8472_MODULE_SFP(se->eeprom)) { /* See SFF-8472 pp22, pp28 */ int i; - for (i = 0, rv->cc_base = 0; i < 63; ++i) - rv->cc_base = (rv->cc_base + rv->eeprom[i]) & 0xFF; - for (i = 64, rv->cc_ext = 0; i < 95; ++i) - rv->cc_ext = (rv->cc_ext + rv->eeprom[i]) & 0xFF; - } else if (SFF8436_MODULE_QSFP_PLUS_V2(rv->eeprom) || - SFF8636_MODULE_QSFP28(rv->eeprom)) { + for (i = 0, se->cc_base = 0; i < 63; ++i) + se->cc_base = (se->cc_base + se->eeprom[i]) & 0xFF; + for (i = 64, se->cc_ext = 0; i < 95; ++i) + se->cc_ext = (se->cc_ext + se->eeprom[i]) & 0xFF; + } else if (SFF8436_MODULE_QSFP_PLUS_V2(se->eeprom) || + SFF8636_MODULE_QSFP28(se->eeprom)) { /* See SFF-8436 pp72, pp73 */ int i; - for (i = 128, rv->cc_base = 0; i < 191; ++i) - rv->cc_base = (rv->cc_base + rv->eeprom[i]) & 0xFF; - for (i = 192, rv->cc_ext = 0; i < 223; ++i) - rv->cc_ext = (rv->cc_ext + rv->eeprom[i]) & 0xFF; + for (i = 128, se->cc_base = 0; i < 191; ++i) + se->cc_base = (se->cc_base + se->eeprom[i]) & 0xFF; + for (i = 192, se->cc_ext = 0; i < 223; ++i) + se->cc_ext = (se->cc_ext + se->eeprom[i]) & 0xFF; } - if (!sff_info_valid(rv, 1)) return -1; - - rv->sfp_type = sff_sfp_type_get(rv->eeprom); - if(rv->sfp_type == SFF_SFP_TYPE_INVALID) { - AIM_LOG_ERROR("sff_info_init() failed: invalid sfp type"); + if (!sff_eeprom_validate(se, 1)) { return -1; } - rv->sfp_type_name = sff_sfp_type_desc(rv->sfp_type); + + se->info.sfp_type = sff_sfp_type_get(se->eeprom); + if(se->info.sfp_type == SFF_SFP_TYPE_INVALID) { + AIM_LOG_ERROR("sff_eeprom_parse() failed: invalid sfp type"); + return -1; + } + se->info.sfp_type_name = sff_sfp_type_desc(se->info.sfp_type); const uint8_t *vendor, *model, *serial; - switch(rv->sfp_type) + switch(se->info.sfp_type) { case SFF_SFP_TYPE_QSFP_PLUS: case SFF_SFP_TYPE_QSFP28: - vendor=rv->eeprom+148; - model=rv->eeprom+168; - serial=rv->eeprom+196; + vendor=se->eeprom+148; + model=se->eeprom+168; + serial=se->eeprom+196; break; case SFF_SFP_TYPE_SFP: default: - vendor=rv->eeprom+20; - model=rv->eeprom+40; - serial=rv->eeprom+68; + vendor=se->eeprom+20; + model=se->eeprom+40; + serial=se->eeprom+68; break; } /* handle NULL fields, they should actually be space-padded */ const char *empty = " "; if (*vendor) { - aim_strlcpy(rv->vendor, (char*)vendor, sizeof(rv->vendor)); - make_printable__(rv->vendor); + aim_strlcpy(se->info.vendor, (char*)vendor, sizeof(se->info.vendor)); + make_printable__(se->info.vendor); } else { - aim_strlcpy(rv->vendor, empty, 17); + aim_strlcpy(se->info.vendor, empty, 17); } if (*model) { - aim_strlcpy(rv->model, (char*)model, sizeof(rv->model)); - make_printable__(rv->model); + aim_strlcpy(se->info.model, (char*)model, sizeof(se->info.model)); + make_printable__(se->info.model); } else { - aim_strlcpy(rv->model, empty, 17); + aim_strlcpy(se->info.model, empty, 17); } if (*serial) { - aim_strlcpy(rv->serial, (char*)serial, sizeof(rv->serial)); - make_printable__(rv->serial); + aim_strlcpy(se->info.serial, (char*)serial, sizeof(se->info.serial)); + make_printable__(se->info.serial); } else { - aim_strlcpy(rv->serial, empty, 17); + aim_strlcpy(se->info.serial, empty, 17); } - rv->module_type = sff_module_type_get(rv->eeprom); - if(rv->module_type == SFF_MODULE_TYPE_INVALID) { + se->info.module_type = sff_module_type_get(se->eeprom); + if(se->info.module_type == SFF_MODULE_TYPE_INVALID) { AIM_LOG_ERROR("sff_info_init() failed: invalid module type"); return -1; } - rv->module_type_name = sff_module_type_desc(rv->module_type); - rv->media_type = sff_media_type_get(rv->eeprom); - rv->media_type_name = sff_media_type_desc(rv->media_type); - - if (sff_module_caps_get(rv->eeprom, &rv->caps) < 0) { - AIM_LOG_ERROR("sff_info_init() failed: invalid module caps"); + if(sff_info_from_module_type(&se->info, se->info.sfp_type, + se->info.module_type) < 0) { return -1; } int aoc_length; - switch (rv->media_type) { - case SFF_MEDIA_TYPE_COPPER: - switch (rv->sfp_type) { - case SFF_SFP_TYPE_QSFP_PLUS: - case SFF_SFP_TYPE_QSFP28: - rv->length = rv->eeprom[146]; + switch (se->info.media_type) + { + case SFF_MEDIA_TYPE_COPPER: + switch (se->info.sfp_type) + { + case SFF_SFP_TYPE_QSFP_PLUS: + case SFF_SFP_TYPE_QSFP28: + se->info.length = se->eeprom[146]; + break; + case SFF_SFP_TYPE_SFP: + se->info.length = se->eeprom[18]; + break; + default: + se->info.length = -1; + break; + } break; - case SFF_SFP_TYPE_SFP: - rv->length = rv->eeprom[18]; - break; - default: - rv->length = -1; - break; - } - break; - case SFF_MEDIA_TYPE_FIBER: - switch (rv->sfp_type) { - case SFF_SFP_TYPE_QSFP28: - aoc_length = _sff8636_qsfp28_100g_aoc_length(rv->eeprom); - rv->length = aoc_length; - break; - case SFF_SFP_TYPE_QSFP_PLUS: - case SFF_SFP_TYPE_SFP: - aoc_length = _sff8436_qsfp_40g_aoc_length(rv->eeprom); - if (aoc_length < 0) - aoc_length = _sff8472_sfp_10g_aoc_length(rv->eeprom); - if (aoc_length > 0) - rv->length = aoc_length; - else - rv->length = -1; - break; - default: - rv->length = -1; - break; - } - break; - default: - rv->length = -1; - } - if(rv->length == -1) { - rv->length_desc[0] = 0; + case SFF_MEDIA_TYPE_FIBER: + switch (se->info.sfp_type) + { + case SFF_SFP_TYPE_QSFP28: + aoc_length = _sff8636_qsfp28_100g_aoc_length(se->eeprom); + se->info.length = aoc_length; + break; + case SFF_SFP_TYPE_QSFP_PLUS: + case SFF_SFP_TYPE_SFP: + aoc_length = _sff8436_qsfp_40g_aoc_length(se->eeprom); + if (aoc_length < 0) + aoc_length = _sff8472_sfp_10g_aoc_length(se->eeprom); + if (aoc_length > 0) + se->info.length = aoc_length; + else + se->info.length = -1; + break; + default: + se->info.length = -1; + break; + } + break; + default: + se->info.length = -1; + } + + if(se->info.length == -1) { + se->info.length_desc[0] = 0; } else { - SFF_SNPRINTF(rv->length_desc, sizeof(rv->length_desc), "%dm", rv->length); + SFF_SNPRINTF(se->info.length_desc, sizeof(se->info.length_desc), "%dm", se->info.length); } - rv->supported = 1; + se->identified = 1; return 0; } +int +sff_info_from_module_type(sff_info_t* info, sff_sfp_type_t st, sff_module_type_t mt) +{ + info->sfp_type = st; + info->sfp_type_name = sff_sfp_type_desc(st); + + info->module_type = mt; + info->module_type_name = sff_module_type_desc(mt); + + info->media_type = sff_media_type_get(mt); + info->media_type_name = sff_media_type_desc(info->media_type); + + if (sff_module_caps_get(info->module_type, &info->caps) < 0) { + AIM_LOG_ERROR("sff_info_init() failed: invalid module caps"); + return -1; + } + return 0; +} + void sff_info_show(sff_info_t* info, aim_pvs_t* pvs) { @@ -499,20 +505,20 @@ sff_info_show(sff_info_t* info, aim_pvs_t* pvs) } int -sff_info_init_file(sff_info_t* info, const char* fname) +sff_eeprom_parse_file(sff_eeprom_t* se, const char* fname) { int rv; FILE* fp; - SFF_MEMSET(info, 0, sizeof(*info)); + SFF_MEMSET(se, 0, sizeof(*se)); if( (fp = fopen(fname, "r")) == NULL) { AIM_LOG_ERROR("Failed to open eeprom file %s: %{errno}"); return -1; } - if( (rv = fread(info->eeprom, 1, 256, fp)) > 0) { - if( (rv=sff_info_init(info, NULL)) < 0) { + if( (rv = fread(se->eeprom, 1, 256, fp)) > 0) { + if( (rv=sff_eeprom_parse(se, NULL)) < 0) { AIM_LOG_ERROR("sff_init() failed on data from file %s: %d\n", fname, rv); rv = -1; } @@ -526,53 +532,53 @@ sff_info_init_file(sff_info_t* info, const char* fname) } void -sff_info_invalidate(sff_info_t *info) +sff_eeprom_invalidate(sff_eeprom_t *se) { - memset(info->eeprom, 0xFF, 256); - info->cc_base = 0xFF; - info->cc_ext = 0xFF; - info->supported = 0; + memset(se->eeprom, 0xFF, 256); + se->cc_base = 0xFF; + se->cc_ext = 0xFF; + se->identified = 0; } int -sff_info_valid(sff_info_t *info, int verbose) +sff_eeprom_validate(sff_eeprom_t *se, int verbose) { - if (SFF8436_MODULE_QSFP_PLUS_V2(info->eeprom) || - SFF8636_MODULE_QSFP28(info->eeprom)) { + if (SFF8436_MODULE_QSFP_PLUS_V2(se->eeprom) || + SFF8636_MODULE_QSFP28(se->eeprom)) { - if (info->cc_base != info->eeprom[191]) { + if (se->cc_base != se->eeprom[191]) { if (verbose) { - AIM_LOG_ERROR("sff_info_valid() failed: invalid base QSFP checksum (0x%x should be 0x%x)", - info->eeprom[191], info->cc_base); + AIM_LOG_ERROR("sff_eeprom_validate() failed: invalid base QSFP checksum (0x%x should be 0x%x)", + se->eeprom[191], se->cc_base); } return 0; } #if SFF_CONFIG_INCLUDE_EXT_CC_CHECK == 1 - if (info->cc_ext != info->eeprom[223]) { + if (se->cc_ext != se->eeprom[223]) { if (verbose) { AIM_LOG_ERROR("sff_info_valid() failed: invalid extended QSFP checksum (0x%x should be 0x%x)", - info->eeprom[223], info->cc_ext); + se->eeprom[223], se->cc_ext); } return 0; } #endif - } else if (SFF8472_MODULE_SFP(info->eeprom)) { + } else if (SFF8472_MODULE_SFP(se->eeprom)) { - if (info->cc_base != info->eeprom[63]) { + if (se->cc_base != se->eeprom[63]) { if (verbose) { AIM_LOG_ERROR("sff_info_valid() failed: invalid base SFP checksum (0x%x should be 0x%x)", - info->eeprom[63], info->cc_base); + se->eeprom[63], se->cc_base); } return 0; } #if SFF_CONFIG_INCLUDE_EXT_CC_CHECK == 1 - if (info->cc_ext != info->eeprom[95]) { + if (se->cc_ext != se->eeprom[95]) { if (verbose) { AIM_LOG_ERROR("sff_info_valid() failed: invalid extended SFP checksum (0x%x should be 0x%x)", - info->eeprom[95], info->cc_ext); + se->eeprom[95], se->cc_ext); } return 0; } diff --git a/packages/base/any/onlp/src/sff/module/src/sff_config.c b/packages/base/any/onlp/src/sff/module/src/sff_config.c index 1e448f3b..400b7a72 100644 --- a/packages/base/any/onlp/src/sff/module/src/sff_config.c +++ b/packages/base/any/onlp/src/sff/module/src/sff_config.c @@ -54,6 +54,11 @@ sff_config_settings_t sff_config_settings[] = { __sff_config_STRINGIFY_NAME(SFF_CONFIG_INCLUDE_EXT_CC_CHECK), __sff_config_STRINGIFY_VALUE(SFF_CONFIG_INCLUDE_EXT_CC_CHECK) }, #else { SFF_CONFIG_INCLUDE_EXT_CC_CHECK(__sff_config_STRINGIFY_NAME), "__undefined__" }, +#endif +#ifdef SFF_CONFIG_INCLUDE_DATABASE + { __sff_config_STRINGIFY_NAME(SFF_CONFIG_INCLUDE_DATABASE), __sff_config_STRINGIFY_VALUE(SFF_CONFIG_INCLUDE_DATABASE) }, +#else +{ SFF_CONFIG_INCLUDE_DATABASE(__sff_config_STRINGIFY_NAME), "__undefined__" }, #endif { NULL, NULL } }; diff --git a/packages/base/any/onlp/src/sff/module/src/sff_db.c b/packages/base/any/onlp/src/sff/module/src/sff_db.c new file mode 100644 index 00000000..c6c0ae1e --- /dev/null +++ b/packages/base/any/onlp/src/sff/module/src/sff_db.c @@ -0,0 +1,1468 @@ +/**************************************************************************//** + * + * + * + *****************************************************************************/ +#include + +#define SFF_1G_BASE_SX_PROPERTIES \ + SFF_SFP_TYPE_SFP, "SFP", SFF_MODULE_TYPE_1G_BASE_SX, "1GBASE-SX", SFF_MEDIA_TYPE_FIBER, "Fiber", SFF_MODULE_CAPS_F_1G + + +#define SFF_1G_BASE_LX_PROPERTIES \ + SFF_SFP_TYPE_SFP, "SFP", SFF_MODULE_TYPE_1G_BASE_LX, "1GBASE-LR", SFF_MEDIA_TYPE_FIBER, "Fiber", SFF_MODULE_CAPS_F_1G + + +#define SFF_10G_BASE_CR_PROPERTIES \ + SFF_SFP_TYPE_SFP, "SFP", SFF_MODULE_TYPE_10G_BASE_CR, "10GBASE-CR", SFF_MEDIA_TYPE_COPPER, "Copper", SFF_MODULE_CAPS_F_10G + + +#define SFF_10G_BASE_ZR_PROPERTIES \ + SFF_SFP_TYPE_SFP, "SFP", SFF_MODULE_TYPE_10G_BASE_ZR, "10GBASE-ZR", SFF_MEDIA_TYPE_FIBER, "Fiber", SFF_MODULE_CAPS_F_10G + + +#define SFF_10G_BASE_SR_PROPERTIES \ + SFF_SFP_TYPE_SFP, "SFP", SFF_MODULE_TYPE_10G_BASE_SR, "10GBASE-SR", SFF_MEDIA_TYPE_FIBER, "Fiber",SFF_MODULE_CAPS_F_10G + + +#define SFF_10G_BASE_SRL_PROPERTIES \ + SFF_SFP_TYPE_SFP, "SFP", SFF_MODULE_TYPE_10G_BASE_SRL, "1GBASE-SRL", SFF_MEDIA_TYPE_FIBER, "Fiber", SFF_MODULE_CAPS_F_10G + + +#define SFF_40G_BASE_SR4_PROPERTIES \ + SFF_SFP_TYPE_QSFP_PLUS, "QSFP+", SFF_MODULE_TYPE_40G_BASE_SR4, "40GBASE-SR4", SFF_MEDIA_TYPE_FIBER, "Fiber", SFF_MODULE_CAPS_F_40G + +#define SFF_40G_BASE_LR4_PROPERTIES \ + SFF_SFP_TYPE_QSFP_PLUS, "QSFP+", SFF_MODULE_TYPE_40G_BASE_LR4, "40GBASE-LR4", SFF_MEDIA_TYPE_FIBER, "Fiber", SFF_MODULE_CAPS_F_40G + +#define SFF_40G_BASE_LM4_PROPERTIES \ + SFF_SFP_TYPE_QSFP_PLUS, "QSFP+", SFF_MODULE_TYPE_40G_BASE_LM4, "40GBASE-LM4", SFF_MEDIA_TYPE_FIBER, "Fiber", SFF_MODULE_CAPS_F_40G + + +#define SFF_40G_BASE_CR4_PROPERTIES \ + SFF_SFP_TYPE_QSFP_PLUS, "QSFP+", SFF_MODULE_TYPE_40G_BASE_CR4, "40GBASE-CR4", SFF_MEDIA_TYPE_COPPER, "Copper", SFF_MODULE_CAPS_F_40G + + +#define SFF_40G_BASE_SR2_PROPERTIES \ + SFF_SFP_TYPE_QSFP_PLUS, "QSFP+", SFF_MODULE_TYPE_40G_BASE_SR2, "40GBASE-SR2", SFF_MEDIA_TYPE_FIBER, "Fiber", SFF_MODULE_CAPS_F_40G + +#define SFF_100G_AOC_PROPERTIES \ + SFF_SFP_TYPE_QSFP28, "QSFP28", SFF_MODULE_TYPE_100G_AOC, "100G-AOC", SFF_MEDIA_TYPE_FIBER, "Fiber", SFF_MODULE_CAPS_F_100G + +#define SFF_100G_BASE_LR4_PROPERTIES \ + SFF_SFP_TYPE_QSFP28, "QSFP28", SFF_MODULE_TYPE_100G_BASE_LR4, "100GBASE-LR4", SFF_MEDIA_TYPE_FIBER, "Fiber", SFF_MODULE_CAPS_F_100G + +#define SFF_100G_BASE_SR4_PROPERTIES \ + SFF_SFP_TYPE_QSFP28, "QSFP28", SFF_MODULE_TYPE_100G_BASE_SR4, "100GBASE-SR4", SFF_MEDIA_TYPE_FIBER, "Fiber", SFF_MODULE_CAPS_F_100G + +#define SFF_100G_BASE_CR4_PROPERTIES \ + SFF_SFP_TYPE_QSFP28, "QSFP28", SFF_MODULE_TYPE_100G_BASE_CR4, "100GBASE-CR4", SFF_MEDIA_TYPE_COPPER, "Copper", SFF_MODULE_CAPS_F_100G + +#define SFF_100G_CWDM4_PROPERTIES \ + SFF_SFP_TYPE_QSFP28, "QSFP28", SFF_MODULE_TYPE_100G_CWDM4, "100G-CWDM4", SFF_MEDIA_TYPE_FIBER, "Fiber", SFF_MODULE_CAPS_F_100G + +static sff_db_entry_t sff_database__[] = + { + +#if SFF_CONFIG_INCLUDE_DATABASE == 1 + { + { + .eeprom = { + 0x03, 0x04, 0x07, 0x00, 0x00, 0x00, 0x01, 0x20, 0x40, 0x0c, 0x05, 0x01, 0x15, 0x00, 0x00, 0x00, + 0x1e, 0x0f, 0x00, 0x00, 0x46, 0x49, 0x4e, 0x49, 0x53, 0x41, 0x52, 0x20, 0x43, 0x4f, 0x52, 0x50, + 0x2e, 0x20, 0x20, 0x20, 0x00, 0x00, 0x90, 0x65, 0x46, 0x54, 0x52, 0x4a, 0x38, 0x35, 0x31, 0x39, + 0x50, 0x31, 0x42, 0x4e, 0x4c, 0x20, 0x20, 0x20, 0x41, 0x20, 0x20, 0x20, 0x03, 0x52, 0x00, 0x66, + 0x00, 0x12, 0x00, 0x00, 0x50, 0x38, 0x4a, 0x32, 0x5a, 0x4e, 0x43, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x30, 0x35, 0x31, 0x30, 0x33, 0x31, 0x20, 0x20, 0x58, 0x90, 0x01, 0x74, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + .info = { + "FINISAR CORP. ", + "FTRJ8519P1BNL ", + "P8J2ZNC ", + SFF_1G_BASE_SX_PROPERTIES, + -1, + } + }, + }, + + { + { + .eeprom = { + 0x03, 0x04, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x41, 0x6d, 0x70, 0x68, 0x65, 0x6e, 0x6f, 0x6c, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x00, 0x41, 0x50, 0x48, 0x35, 0x37, 0x31, 0x35, 0x34, 0x30, 0x30, 0x30, + 0x37, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x4b, 0x20, 0x20, 0x20, 0x01, 0x00, 0x00, 0xfa, + 0x00, 0x00, 0x00, 0x00, 0x41, 0x50, 0x46, 0x31, 0x30, 0x30, 0x38, 0x30, 0x30, 0x37, 0x30, 0x31, + 0x34, 0x37, 0x20, 0x20, 0x31, 0x30, 0x30, 0x33, 0x30, 0x32, 0x20, 0x20, 0x00, 0x00, 0x00, 0xa9, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + .info = { + "Amphenol ", + "571540007 ", + "APF10080070147 ", + SFF_10G_BASE_CR_PROPERTIES, + 0x1 + }, + }, + }, + + { + { + .eeprom = { + 0x03, 0x04, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x43, 0x49, 0x53, 0x43, 0x4f, 0x2d, 0x4d, 0x4f, 0x4c, 0x45, 0x58, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x09, 0x3a, 0x37, 0x34, 0x37, 0x35, 0x32, 0x2d, 0x39, 0x35, + 0x31, 0x39, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x38, 0x20, 0x20, 0x01, 0x00, 0x00, 0x11, + 0x00, 0x00, 0x00, 0x00, 0x4d, 0x4f, 0x43, 0x31, 0x35, 0x34, 0x37, 0x30, 0x30, 0x30, 0x48, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x31, 0x31, 0x31, 0x31, 0x32, 0x31, 0x20, 0x20, 0x00, 0x00, 0x00, 0x8f, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x69, 0xf9, 0x8e, 0x5a, + 0x43, 0x4f, 0x50, 0x51, 0x41, 0x41, 0x34, 0x4a, 0x41, 0x42, 0x33, 0x37, 0x2d, 0x30, 0x39, 0x36, + 0x30, 0x2d, 0x30, 0x33, 0x56, 0x30, 0x33, 0x20, 0x01, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0xcc, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x53, 0x46, 0x50, 0x2d, 0x48, 0x31, 0x30, 0x47, 0x42, 0x2d, 0x43, 0x55, 0x31, 0x4d, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x30, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb3, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + .info = { + "CISCO-MOLEX ", + "74752-9519 ", + "MOC1547000H ", + SFF_10G_BASE_CR_PROPERTIES, + 0x1, + }, + }, + }, + + { + { + .eeprom = { + 0x03, 0x04, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x43, 0x39, 0x39, 0x39, 0x39, 0x2d, 0x31, 0x4d, + 0x2d, 0x50, 0x2d, 0x4c, 0x43, 0x20, 0x20, 0x20, 0x41, 0x20, 0x20, 0x20, 0x01, 0x00, 0x00, 0xa1, + 0x00, 0x00, 0x00, 0x00, 0x31, 0x33, 0x30, 0x35, 0x33, 0x30, 0x30, 0x30, 0x34, 0x31, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x31, 0x33, 0x30, 0x34, 0x31, 0x33, 0x20, 0x20, 0x00, 0x00, 0x00, 0x1d, + 0x00, 0x00, 0x11, 0xb6, 0x7f, 0x7f, 0x08, 0x96, 0xee, 0x8e, 0x60, 0x37, 0xb4, 0xc8, 0x8b, 0x88, + 0x66, 0x9c, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa3, 0xdd, 0x56, 0xe8, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + .info = { + " ", + "C9999-1M-P-LC ", + "1305300041 ", + SFF_10G_BASE_CR_PROPERTIES, + 0x0, + } + }, + }, + + { + { + .eeprom = { + 0x03, 0x04, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x43, 0x49, 0x53, 0x43, 0x4f, 0x2d, 0x4d, 0x4f, 0x4c, 0x45, 0x58, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x09, 0x3a, 0x37, 0x34, 0x37, 0x35, 0x32, 0x2d, 0x39, 0x35, + 0x32, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x38, 0x20, 0x20, 0x01, 0x00, 0x00, 0x0b, + 0x00, 0x00, 0x00, 0x00, 0x4d, 0x4f, 0x43, 0x31, 0x36, 0x30, 0x33, 0x30, 0x42, 0x48, 0x34, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x31, 0x32, 0x30, 0x31, 0x31, 0x39, 0x20, 0x20, 0x00, 0x00, 0x00, 0xa5, + 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x04, 0x3b, 0x5b, + 0x43, 0x4f, 0x50, 0x51, 0x41, 0x41, 0x36, 0x4a, 0x41, 0x42, 0x33, 0x37, 0x2d, 0x30, 0x39, 0x36, + 0x31, 0x2d, 0x30, 0x33, 0x56, 0x30, 0x33, 0x20, 0x01, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0xcf, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x53, 0x46, 0x50, 0x2d, 0x48, 0x31, 0x30, 0x47, 0x42, 0x2d, 0x43, 0x55, 0x33, 0x4d, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x30, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb5, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + .info = { + "CISCO-MOLEX ", + "74752-9520 ", + "MOC16030BH4 ", + SFF_10G_BASE_CR_PROPERTIES, + 0x3 + }, + }, + }, + + { + { + .eeprom = { + 0x00, 0x80, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x0d, 0x33, 0x0c, 0xcb, 0x0c, 0xcb, 0x0d, 0x33, 0x1b, 0xd5, 0x1b, 0x54, 0x18, 0xcd, 0x1c, + 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x0c, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x03, 0x67, 0x00, 0x00, 0x00, 0x0a, 0x03, 0x00, 0x00, 0x4f, 0x45, 0x4d, 0x20, 0x20, + 0x0d, 0x00, 0x0c, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, 0x67, 0x00, 0x00, 0x00, + 0x0a, 0x03, 0x00, 0x00, 0x4f, 0x45, 0x4d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x07, 0x00, 0x1e, 0x00, 0x51, 0x53, 0x46, 0x50, 0x2d, 0x34, 0x30, 0x47, + 0x2d, 0x53, 0x52, 0x34, 0x20, 0x20, 0x20, 0x20, 0x31, 0x41, 0x42, 0x68, 0x07, 0xd0, 0x46, 0x0c, + 0x00, 0x00, 0x00, 0xde, 0x41, 0x43, 0x52, 0x34, 0x30, 0x47, 0x30, 0x30, 0x34, 0x31, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x31, 0x32, 0x30, 0x38, 0x32, 0x37, 0x31, 0x39, 0x08, 0x00, 0x00, 0x8a, + 0x00, 0x00, 0x11, 0x9d, 0xf1, 0x68, 0x34, 0xac, 0xb2, 0x3d, 0xc6, 0x19, 0x53, 0x0b, 0xbf, 0xf0, + 0x2e, 0xe1, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf7, 0xfe, 0x58, 0x27, + }, + .info = { + "OEM ", + "QSFP-40G-SR4 ", + "ACR40G0041 ", + SFF_40G_BASE_SR4_PROPERTIES, + -1, + }, + }, + }, + + { + { + .eeprom = { + 0x0d, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x23, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x03, 0xa0, 0x41, 0x6d, 0x70, 0x68, 0x65, 0x6e, 0x6f, 0x6c, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x00, 0x78, 0xa7, 0x14, 0x36, 0x30, 0x33, 0x30, 0x32, 0x30, 0x30, 0x30, + 0x33, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x42, 0x20, 0x07, 0x0b, 0x00, 0x00, 0x46, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x41, 0x50, 0x46, 0x31, 0x33, 0x30, 0x32, 0x30, 0x30, 0x33, 0x35, 0x41, + 0x52, 0x56, 0x20, 0x20, 0x31, 0x33, 0x30, 0x31, 0x31, 0x35, 0x20, 0x20, 0x00, 0x00, 0x00, 0xf9, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + .info = { + "Amphenol ", + "603020003 ", + "APF13020035ARV ", + SFF_40G_BASE_CR4_PROPERTIES, + 0x3 + }, + }, + }, + + { + { + .eeprom = { + 0x03, 0x04, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x46, 0x69, 0x62, 0x65, 0x72, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x40, 0x20, 0x31, 0x30, 0x47, 0x53, 0x46, 0x50, 0x2d, 0x50, + 0x43, 0x2d, 0x33, 0x30, 0x2d, 0x31, 0x20, 0x20, 0x41, 0x30, 0x20, 0x20, 0x00, 0x00, 0x00, 0xd9, + 0x00, 0x00, 0x00, 0x00, 0x46, 0x53, 0x34, 0x30, 0x32, 0x31, 0x32, 0x44, 0x30, 0x31, 0x37, 0x36, + 0x20, 0x20, 0x20, 0x20, 0x31, 0x34, 0x30, 0x32, 0x31, 0x33, 0x20, 0x20, 0x00, 0x00, 0x00, 0x8f, + 0x00, 0x00, 0x11, 0x4b, 0xd4, 0xe4, 0xc5, 0x99, 0xd1, 0xfb, 0xdb, 0x5e, 0xa2, 0xc4, 0x62, 0x0c, + 0xf2, 0x5b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x26, 0xfa, 0x99, + 0x43, 0x4f, 0x50, 0x51, 0x41, 0x41, 0x34, 0x4a, 0x41, 0x41, 0x33, 0x37, 0x2d, 0x30, 0x39, 0x36, + 0x30, 0x2d, 0x30, 0x32, 0x56, 0x30, 0x32, 0x20, 0x01, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0xc9, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x53, 0x46, 0x50, 0x2d, 0x48, 0x31, 0x30, 0x47, 0x42, 0x2d, 0x43, 0x55, 0x31, 0x4d, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x30, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb3, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + .info = { +"FiberStore ", + "10GSFP-PC-30-1 ", + "FS40212D0176 ", + SFF_10G_BASE_CR_PROPERTIES, + 0x1, + }, + }, + }, + + { + { + .eeprom = { + 0x03, 0x04, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x06, 0x67, 0x00, 0x50, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x46, 0x49, 0x4e, 0x49, 0x53, 0x41, 0x52, 0x20, 0x43, 0x4f, 0x52, 0x50, + 0x2e, 0x20, 0x20, 0x20, 0x00, 0x00, 0x90, 0x65, 0x46, 0x54, 0x4c, 0x58, 0x31, 0x38, 0x37, 0x31, + 0x4d, 0x33, 0x42, 0x43, 0x4c, 0x20, 0x20, 0x20, 0x41, 0x20, 0x20, 0x20, 0x06, 0x0e, 0x00, 0x33, + 0x06, 0x1a, 0x00, 0x00, 0x55, 0x50, 0x47, 0x30, 0x31, 0x57, 0x4a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x31, 0x33, 0x30, 0x34, 0x32, 0x39, 0x20, 0x20, 0x68, 0xf0, 0x05, 0xfe, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + .info = { + "FINISAR CORP. ", + "FTLX1871M3BCL ", + "UPG01WJ ", + SFF_10G_BASE_ZR_PROPERTIES, + -1, + }, + }, + }, + + { + { + .eeprom = { + 0x03, 0x04, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x67, 0x00, 0x00, 0x00, + 0x03, 0x01, 0x00, 0x0a, 0x46, 0x49, 0x4e, 0x49, 0x53, 0x41, 0x52, 0x20, 0x43, 0x4f, 0x52, 0x50, + 0x2e, 0x20, 0x20, 0x20, 0x00, 0x00, 0x90, 0x65, 0x46, 0x54, 0x4c, 0x58, 0x38, 0x35, 0x37, 0x30, + 0x44, 0x33, 0x42, 0x43, 0x4c, 0x20, 0x20, 0x20, 0x41, 0x20, 0x20, 0x20, 0x03, 0x52, 0x00, 0x1c, + 0x00, 0x1a, 0x00, 0x00, 0x50, 0x50, 0x34, 0x34, 0x51, 0x56, 0x31, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x31, 0x33, 0x30, 0x32, 0x31, 0x37, 0x20, 0x20, 0x68, 0xf0, 0x03, 0xe3, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + .info = { + "FINISAR CORP. ", + "FTLX8570D3BCL ", + "PP44QV1 ", + SFF_10G_BASE_SRL_PROPERTIES, + -1, + }, + }, + }, + + { + { + .eeprom = { + 0x03, 0x04, 0x07, 0x00, 0x00, 0x00, 0x02, 0x12, 0x10, 0x01, 0x05, 0x01, 0x15, 0x00, 0x0a, 0x64, + 0x00, 0x00, 0x00, 0x00, 0x46, 0x49, 0x4e, 0x49, 0x53, 0x41, 0x52, 0x20, 0x43, 0x4f, 0x52, 0x50, + 0x2e, 0x20, 0x20, 0x20, 0x00, 0x00, 0x90, 0x65, 0x46, 0x54, 0x52, 0x4a, 0x31, 0x33, 0x31, 0x39, + 0x50, 0x31, 0x42, 0x54, 0x4c, 0x2d, 0x4d, 0x44, 0x41, 0x20, 0x20, 0x20, 0x05, 0x1e, 0x00, 0x88, + 0x00, 0x1a, 0x00, 0x00, 0x50, 0x44, 0x42, 0x31, 0x56, 0x51, 0x55, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x30, 0x38, 0x30, 0x33, 0x31, 0x37, 0x20, 0x20, 0x68, 0xb0, 0x01, 0xc9, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + .info = { +"FINISAR CORP. ", + "FTRJ1319P1BTL-MD", + "PDB1VQU ", + SFF_1G_BASE_LX_PROPERTIES, + -1, + }, + }, + }, + + { + { + .eeprom = { + 0x03, 0x04, 0x21, 0x81, 0x00, 0x00, 0x04, 0x41, 0x04, 0x80, 0xd5, 0x00, 0x67, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x54, 0x79, 0x63, 0x6f, 0x20, 0x45, 0x6c, 0x65, 0x63, 0x74, 0x72, 0x6f, + 0x6e, 0x69, 0x63, 0x73, 0x00, 0x00, 0x40, 0x20, 0x32, 0x31, 0x30, 0x30, 0x38, 0x37, 0x30, 0x2d, + 0x31, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x41, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x8a, + 0x00, 0x00, 0x00, 0x00, 0x30, 0x39, 0x33, 0x35, 0x45, 0x30, 0x34, 0x38, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x31, 0x30, 0x30, 0x35, 0x30, 0x39, 0x30, 0x30, 0x00, 0x00, 0x00, 0x41, + 0x37, 0x34, 0x30, 0x2d, 0x30, 0x33, 0x30, 0x30, 0x37, 0x36, 0x20, 0x52, 0x45, 0x56, 0x20, 0x30, + 0x31, 0x20, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + .info = { + "Tyco Electronics", + "2100870-1 ", + "0935E048 ", + SFF_10G_BASE_CR_PROPERTIES, + 1, + }, + }, + }, + + { + { + .eeprom = { + /* 0 */ 0x0d, 0x00, 0x02, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 16 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 32 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 48 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 64 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 80 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 96 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 112 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 128 */ 0x0d, 0xdc, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xce, 0x00, 0x00, 0x32, + /* 144 */ 0x00, 0x00, 0x00, 0x00, 0x43, 0x49, 0x53, 0x43, 0x4f, 0x2d, 0x41, 0x56, 0x41, 0x47, 0x4f, 0x20, + /* 160 */ 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x17, 0x6a, 0x41, 0x46, 0x42, 0x52, 0x2d, 0x37, 0x39, 0x45, + /* 176 */ 0x42, 0x50, 0x5a, 0x2d, 0x43, 0x53, 0x31, 0x20, 0x30, 0x31, 0x42, 0x68, 0x07, 0xd0, 0x46, 0x47, + /* 192 */ 0x00, 0x00, 0x0f, 0xde, 0x41, 0x56, 0x4d, 0x31, 0x38, 0x30, 0x39, 0x53, 0x30, 0x54, 0x47, 0x20, + /* 208 */ 0x20, 0x20, 0x20, 0x20, 0x31, 0x34, 0x30, 0x32, 0x32, 0x35, 0x20, 0x20, 0x08, 0x00, 0xf5, 0xcc, + /* 224 */ 0xf5, 0x00, 0x06, 0xd2, 0x04, 0x9c, 0x47, 0x09, 0xc5, 0xaf, 0xcf, 0xb7, 0x65, 0xd9, 0x72, 0x03, + /* 240 */ 0xea, 0x59, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x45, 0xbd, 0x94, + }, + .info = { +"CISCO-AVAGO ", + "AFBR-79EBPZ-CS1 ", + "AVM1809S0TG ", + SFF_40G_BASE_SR2_PROPERTIES, + -1, + }, + }, + }, + /* Cisco/Finisar 40G QSFP (QuadWire? AOC? Pigtail?) */ + { + { + .eeprom = { + /* 0x0000 */ 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x0010 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0xde, 0x00, 0x00, 0x7f, 0x4d, 0x00, 0x00, 0x00, 0x00, + /* 0x0020 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x0030 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x0040 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x0050 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x0060 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x0070 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + /* 0x0080 */ 0x0d, 0x10, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x67, 0x00, 0x00, 0x32, + /* 0x0090 */ 0x1e, 0x00, 0x0a, 0x00, 0x43, 0x49, 0x53, 0x43, 0x4f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + /* 0x00a0 */ 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x90, 0x65, 0x46, 0x43, 0x42, 0x4e, 0x34, 0x31, 0x30, 0x51, + /* 0x00b0 */ 0x45, 0x32, 0x43, 0x31, 0x30, 0x2d, 0x43, 0x31, 0x41, 0x20, 0x42, 0x68, 0x07, 0xd0, 0x46, 0xaf, + /* 0x00c0 */ 0x00, 0x01, 0x04, 0xd8, 0x46, 0x49, 0x53, 0x31, 0x37, 0x33, 0x31, 0x30, 0x30, 0x35, 0x33, 0x2d, + /* 0x00d0 */ 0x41, 0x20, 0x20, 0x20, 0x31, 0x33, 0x30, 0x37, 0x33, 0x31, 0x20, 0x20, 0x0a, 0x00, 0xf6, 0x90, + /* 0x00e0 */ 0x00, 0x00, 0x02, 0x43, 0x59, 0xd3, 0x68, 0x03, 0x46, 0x83, 0x87, 0x75, 0x1f, 0xee, 0x94, 0x62, + /* 0x00f0 */ 0xb8, 0x98, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5e, 0x75, 0x43, + }, + .info = { + "CISCO ", + "FCBN410QE2C10-C1", + "FIS17310053-A ", + SFF_40G_BASE_SR4_PROPERTIES, + -1, + }, + }, + }, + /* + * Dell/Amphenol 3M copper + * Identifies as intra-enclosure and inter-enclosure + */ + { + { + .eeprom = { + /* 0000 */ 0x03, 0x04, 0x21, 0x01, 0x00, 0x00, 0x00, 0x41, 0x84, 0x80, 0x55, 0x00, 0x67, 0x00, 0x00, 0x00, + /* 0010 */ 0x00, 0x00, 0x03, 0x00, 0x41, 0x6d, 0x70, 0x68, 0x65, 0x6e, 0x6f, 0x6c, 0x20, 0x20, 0x20, 0x20, + /* 0020 */ 0x20, 0x20, 0x20, 0x20, 0x00, 0x78, 0xa7, 0x14, 0x36, 0x31, 0x36, 0x37, 0x34, 0x30, 0x30, 0x30, + /* 0030 */ 0x33, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x43, 0x20, 0x20, 0x20, 0x01, 0x00, 0x00, 0xe3, + /* 0040 */ 0x00, 0x00, 0x00, 0x00, 0x43, 0x4e, 0x30, 0x35, 0x33, 0x48, 0x56, 0x4e, 0x34, 0x34, 0x4c, 0x38, + /* 0050 */ 0x37, 0x59, 0x59, 0x20, 0x31, 0x34, 0x30, 0x34, 0x32, 0x33, 0x20, 0x20, 0x00, 0x00, 0x00, 0x78, + /* 0060 */ 0x0f, 0x10, 0x00, 0xa3, 0x71, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + /* 0070 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + /* 0080 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + /* 0090 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + /* 00a0 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + /* 00b0 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + /* 00c0 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + /* 00d0 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + /* 00e0 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + /* 00f0 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + .info = { + "Amphenol ", + "616740003 ", + "CN053HVN44L87YY ", + SFF_10G_BASE_CR_PROPERTIES, + 3, + }, + }, + }, + /* + * Dell/Amphenol 3M copper + * Identifies as intra-enclosure and inter-enclosure + */ + { + { + .eeprom = { + /* 0x0000 */ 0x03, 0x04, 0x21, 0x02, 0x00, 0x00, 0x04, 0x41, 0x84, 0x80, 0xd5, 0x00, 0x67, 0x00, 0x00, 0x00, + /* 0x0010 */ 0x00, 0x00, 0x03, 0x00, 0x33, 0x4d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + /* 0x0020 */ 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x31, 0x34, 0x31, 0x30, 0x2d, 0x50, 0x31, 0x37, + /* 0x0030 */ 0x2d, 0x30, 0x30, 0x2d, 0x33, 0x2e, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x1c, + /* 0x0040 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x0050 */ 0x00, 0x00, 0x00, 0x00, 0x31, 0x32, 0x30, 0x32, 0x32, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, + /* 0x0060 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x0070 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x0080 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x0090 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x00a0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x00b0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x00c0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x00d0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x00e0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x00f0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + .info = { + "3M ", + "1410-P17-00-3.00", + /* XXX roth -- NULL serial number ??!??111! */ + " ", + SFF_10G_BASE_CR_PROPERTIES, + 3, + }, + }, + }, + { + { + .eeprom = { + 0x0d, 0x03, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, + 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x14, 0x21, 0x00, 0x00, 0x83, 0x2c, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0a, 0x12, 0x48, 0x12, 0x48, 0x12, 0x48, 0x12, 0x48, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, + 0x0c, 0x04, 0x00, 0x00, 0x00, 0x40, 0x40, 0x06, 0x00, 0x05, + 0x64, 0x00, 0x00, 0x32, 0x1e, 0x00, 0x00, 0x00, 0x45, 0x64, + 0x67, 0x65, 0x2d, 0x63, 0x6f, 0x72, 0x45, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x04, 0x70, 0x72, 0xcf, 0x4d, 0x30, + 0x4f, 0x45, 0x43, 0x36, 0x34, 0x30, 0x31, 0x54, 0x30, 0x30, + 0x5a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x42, 0x68, 0x07, 0xd0, + 0x46, 0xb0, 0x00, 0x00, 0x00, 0x12, 0x31, 0x45, 0x37, 0x51, + 0x54, 0x30, 0x30, 0x30, 0x33, 0x30, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x31, 0x34, 0x30, 0x37, 0x32, 0x38, 0x20, 0x20, + 0x08, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + .info = { + "Edge-corE ", + "M0OEC6401T00Z ", + "1E7QT00030 ", + SFF_40G_BASE_SR4_PROPERTIES, + -1, + }, + } + }, + { + { + .eeprom = { + 0x0d, 0x03, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, + 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0x30, 0x00, 0x00, 0x82, 0xa2, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x12, 0x48, 0x12, 0x48, 0x12, 0x48, 0x12, 0x48, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, + 0x0c, 0x04, 0x00, 0x00, 0x00, 0x40, 0x40, 0x06, 0x00, 0x05, + 0x64, 0x00, 0x00, 0x32, 0x1e, 0x00, 0x00, 0x00, 0x45, 0x64, + 0x67, 0x65, 0x2d, 0x63, 0x6f, 0x72, 0x45, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x04, 0x70, 0x72, 0xcf, 0x4d, 0x30, + 0x4f, 0x45, 0x43, 0x36, 0x34, 0x30, 0x31, 0x54, 0x30, 0x30, + 0x5a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x42, 0x68, 0x07, 0xd0, + 0x46, 0xb0, 0x00, 0x00, 0x00, 0x12, 0x31, 0x45, 0x37, 0x51, + 0x54, 0x30, 0x30, 0x30, 0x32, 0x38, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x31, 0x34, 0x30, 0x37, 0x32, 0x38, 0x20, 0x20, + 0x08, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, + .info = { + "Edge-corE ", + "M0OEC6401T00Z ", + "1E7QT00028 ", + SFF_40G_BASE_SR4_PROPERTIES, + -1, + }, + } + }, + { + { + .eeprom = { + 0x0d, 0x03, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x17, 0x9f, 0x00, 0x00, 0x80, 0x29, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x44, 0xd5, 0x44, 0x3a, 0x48, 0xb1, + 0x4d, 0x30, 0x12, 0x48, 0x12, 0x48, 0x12, 0x48, 0x12, 0x48, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x8c, + 0x23, 0x04, 0x00, 0x00, 0x01, 0x40, 0x40, 0x02, 0x00, 0x05, + 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x46, 0x4f, + 0x52, 0x4d, 0x45, 0x52, 0x49, 0x43, 0x41, 0x4f, 0x45, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x04, 0x00, 0x00, 0x00, 0x54, 0x51, + 0x53, 0x2d, 0x51, 0x31, 0x4c, 0x48, 0x38, 0x2d, 0x58, 0x43, + 0x41, 0x31, 0x30, 0x20, 0x00, 0x00, 0x42, 0x68, 0x07, 0xd0, + 0x46, 0x4a, 0x00, 0x00, 0x05, 0x31, 0x39, 0x31, 0x33, 0x33, + 0x32, 0x4c, 0x30, 0x30, 0x30, 0x31, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x31, 0x33, 0x30, 0x38, 0x30, 0x36, 0x20, 0x20, + 0x08, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xef, + 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xf7, 0xf7, 0xf7, + 0xf7, 0xf7, 0xf7, 0xf7, 0xfe, 0xfe, + }, + .info = { + "FORMERICAOE ", + "TQS-Q1LH8-XCA10 ", + "91332L0001 ", + SFF_40G_BASE_SR4_PROPERTIES, + 10, + }, + }, + }, + + { + { + .eeprom = { + /* 0x0000 */ 0x03, 0x04, 0x21, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x06, 0x67, 0x00, 0x00, 0x00, + /* + * ^^^^ copper pigtail + * + * ^^^^ no 10G or IB codes + * + * ^^^^ ^^^^ no SONET (fiber) + * + * identifies as 1000BASE-CX ^^^^ + * + * no FC length code ^^^^ + * + * identifies as SFP+ passive ^^^^ + * + * no FC media, copper or otherwise ^^^^ + * + * no FC speed ^^^^ + * + * nominal bitrate 0x67 --> 10.3GB ^^^^ + */ + /* 0x0010 */ 0x00, 0x00, 0x03, 0x00, 0x49, 0x42, 0x4d, 0x2d, 0x41, 0x6d, 0x70, 0x68, 0x65, 0x6e, 0x6f, 0x6c, + /* + * ^^^^ copper cable length (3m) + */ + /* 0x0020 */ 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x17, 0xef, 0x39, 0x30, 0x59, 0x39, 0x34, 0x32, 0x38, 0x2d, + /* 0x0030 */ 0x4e, 0x32, 0x38, 0x35, 0x30, 0x30, 0x41, 0x20, 0x46, 0x20, 0x20, 0x20, 0x01, 0x00, 0x00, 0x7a, + /* 0x0040 */ 0x00, 0x00, 0x00, 0x00, 0x59, 0x33, 0x35, 0x30, 0x56, 0x54, 0x32, 0x42, 0x52, 0x31, 0x46, 0x47, + /* 0x0050 */ 0x20, 0x20, 0x20, 0x20, 0x31, 0x32, 0x31, 0x31, 0x32, 0x37, 0x20, 0x20, 0x00, 0x00, 0x00, 0x0d, + /* 0x0060 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + /* 0x0070 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + /* 0x0080 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + /* 0x0090 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + /* 0x00a0 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + /* 0x00b0 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + /* 0x00c0 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + /* 0x00d0 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + /* 0x00e0 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + /* 0x00f0 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + .info = { +"IBM-Amphenol ", + "90Y9428-N28500A ", + "Y350VT2BR1FG ", + SFF_10G_BASE_CR_PROPERTIES, + 3, + }, + }, + }, + { + /* Verify string normalization for unprintable characters in the vendor, model, or serial number fields. */ + { + { + /* 0x0000 */ 0x03, 0x04, 0x21, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x06, 0x67, 0x00, 0x00, 0x00, + /* 0x0010 */ 0x00, 0x00, 0x03, 0x00, 0x49, 0x42, 0x4d, 0x2d, 0x41, 0x6d, 0x70, 0x68, 0x65, 0x6e, 0x6f, 0x6c, + /* 0x0020 */ 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x17, 0xef, 0x39, 0x30, 0x59, 0x39, 0x34, 0x32, 0x38, 0xFd, + /* 0x0030 */ 0x4e, 0x32, 0x38, 0x35, 0x30, 0x30, 0x41, 0x20, 0x46, 0x20, 0x20, 0x20, 0x01, 0x00, 0x00, 0x8a, + /* 0x0040 */ 0x00, 0x00, 0x00, 0x00, 0x59, 0x33, 0xF5, 0xF0, 0x56, 0x54, 0x32, 0x42, 0x52, 0x31, 0x46, 0x47, + /* 0x0050 */ 0x20, 0x20, 0x20, 0x20, 0x31, 0x32, 0x31, 0x31, 0x32, 0x37, 0x20, 0x20, 0x00, 0x00, 0x00, 0x8d, + /* 0x0060 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + /* 0x0070 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + /* 0x0080 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + /* 0x0090 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + /* 0x00a0 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + /* 0x00b0 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + /* 0x00c0 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + /* 0x00d0 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + /* 0x00e0 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + /* 0x00f0 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + .info = { + "IBM-Amphenol????", + "90Y9428?N28500A ", + "Y3??VT2BR1FG ", + SFF_10G_BASE_CR_PROPERTIES, + 3, + }, + }, + }, + { + /* + * Finisar 40G AOC breakout cable + */ + { + { + /* 0x0000 */ 0x0d, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x0010 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x9f, 0x00, 0x00, 0x80, 0xc2, 0x00, 0x00, 0x00, 0x00, + /* 0x0020 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x0030 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x0040 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x0050 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x0060 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x0070 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + + /* 0x0080 */ 0x0d, 0x10, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x67, 0x00, 0x00, 0x00, + /* + * ^^^^ QSFP+ + * + * ^^^^ no separable connector (active?) + * + * ^^^^^ no media compliance (*NOT* 40G active) + * + * ^^^^ no SONET compliance + * + * ^^^^ no SAS compliance + * + * ^^^^ no GbE compliance + * + * ^^^^ ^^^^ no FC compliance + * + * ^^^^ no FC media + * + * ^^^^ no FC speed + * + * ^^^^ 64b66b + * + * ^^^^ nominal BR >= 10G + * no SM or OM3 length ^^^^ ^^^^ + */ + /* 0x0090 */ 0x00, 0x00, 0x03, 0x00, 0x46, 0x49, 0x4e, 0x49, 0x53, 0x41, 0x52, 0x20, 0x43, 0x4f, 0x52, 0x50, + /* + * ^^^^ ^^^^ no OM1 or OM2 length + * + * ^^^^ 3M cable (copper or active) + */ + /* 0x00a0 */ 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x90, 0x65, 0x46, 0x43, 0x42, 0x4e, 0x35, 0x31, 0x30, 0x51, + /* 0x00b0 */ 0x45, 0x32, 0x43, 0x30, 0x33, 0x20, 0x20, 0x20, 0x41, 0x20, 0x42, 0x68, 0x07, 0xd0, 0x46, 0x29, + /* + * ^^^^ ^^^^ 850nm + */ + /* 0x00c0 */ 0x00, 0x01, 0x04, 0xd8, 0x44, 0x53, 0x4b, 0x30, 0x34, 0x56, 0x52, 0x20, 0x20, 0x20, 0x20, 0x20, + /* 0x00d0 */ 0x20, 0x20, 0x20, 0x20, 0x31, 0x34, 0x31, 0x31, 0x30, 0x34, 0x20, 0x20, 0x08, 0x00, 0xf6, 0x54, + /* 0x00e0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x00f0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + .info = { + "FINISAR CORP ", + "FCBN510QE2C03 ", + "DSK04VR ", + SFF_40G_BASE_SR4_PROPERTIES, + 3, + }, + }, + }, + { + /* + * Finisar 40G AOC breakout cable, 10G end + */ + { + { + /* 0x0000 */ 0x03, 0x04, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x06, 0x67, 0x00, 0x00, 0x00, + /* + * ^^^^ SFP+ + * + * ^^^^ copper pigtail (ugh) + * + * ^^^^ no 10G or IF compliance + * + * ^^^^ no SONET compliance + * + * ^^^^ no OC length spec + * + * ^^^^ no ethernet compliance + * + * ^^^^ no FC length or tech + * + * ^^^^ active cable, no FC tech + * + * ^^^^ no FC media + * + * ^^^^ no FC speed + * + * ^^^^ 64/66 encoding + * + * nominal BR >= 10G ^^^^ + * + * no SM length ^^^^ ^^^^ + */ + /* 0x0010 */ 0x00, 0x00, 0x01, 0x00, 0x46, 0x49, 0x4e, 0x49, 0x53, 0x41, 0x52, 0x20, 0x43, 0x4f, 0x52, 0x50, + /* + * ^^^^ ^^^^ no MM length + * + * ^^^^ active/copper length 1m + * + * ^^^^ no OM3 length + * + */ + /* 0x0020 */ 0x2e, 0x20, 0x20, 0x20, 0x00, 0x00, 0x90, 0x65, 0x46, 0x43, 0x42, 0x4e, 0x35, 0x31, 0x30, 0x51, + /* 0x0030 */ 0x45, 0x32, 0x43, 0x30, 0x31, 0x20, 0x20, 0x20, 0x41, 0x20, 0x20, 0x20, 0x0c, 0x00, 0x00, 0xa9, + /* + * compliant with FC or SFF limiting ^^^^ ^^^^ + */ + /* 0x0040 */ 0x00, 0x12, 0x00, 0x00, 0x44, 0x53, 0x4a, 0x30, 0x35, 0x39, 0x53, 0x20, 0x20, 0x20, 0x20, 0x20, + /* 0x0050 */ 0x20, 0x20, 0x20, 0x20, 0x31, 0x34, 0x31, 0x30, 0x33, 0x30, 0x20, 0x20, 0x00, 0x00, 0x05, 0x72, + /* 0x0060 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x0070 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x0080 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x0090 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x00a0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x00b0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x00c0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x00d0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x00e0 */ 0x00, 0x7f, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x00f0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, + }, + .info = { + "FINISAR CORP. ", + "FCBN510QE2C01 ", + "DSJ059S ", + SFF_10G_BASE_SR_PROPERTIES, + 1, + }, + }, + }, + + + { + { + .eeprom = { + 0x0d, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x23, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xa0, 0x33, 0x4d, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x07, 0x08, 0x00, 0x21, 0x39, 0x51, 0x41, 0x30, 0x2d, 0x31, 0x31, 0x31, + 0x2d, 0x31, 0x32, 0x2d, 0x31, 0x2e, 0x30, 0x30, 0x30, 0x31, 0x03, 0x05, 0x06, 0x0c, 0x00, 0x56, + 0x00, 0x00, 0x00, 0x00, 0x56, 0x31, 0x30, 0x45, 0x42, 0x30, 0x38, 0x35, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x31, 0x35, 0x31, 0x31, 0x31, 0x30, 0x20, 0x20, 0x00, 0x00, 0x00, 0x44, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + .info = { + "3M Company ", + "9QA0-111-12-1.00", + "V10EB085 ", + SFF_40G_BASE_CR4_PROPERTIES, + 1, + }, + }, + }, + { + { + .eeprom = { + 0x11, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x4f, 0x00, 0x00, 0x7f, 0x3d, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1b, 0x19, 0x1c, 0x87, 0x1a, 0x7c, 0x1b, 0xdd, 0x0e, 0xed, 0x0e, 0xd1, 0x0e, 0xcc, + 0x0f, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x08, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x11, 0xcc, 0x23, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x46, 0x49, 0x4e, 0x49, 0x53, 0x41, 0x52, 0x20, 0x43, 0x4f, 0x52, 0x50, + 0x20, 0x20, 0x20, 0x20, 0x1f, 0x00, 0x90, 0x65, 0x46, 0x43, 0x42, 0x4e, 0x34, 0x32, 0x35, 0x51, + 0x42, 0x31, 0x43, 0x30, 0x33, 0x20, 0x20, 0x20, 0x41, 0x31, 0x00, 0x00, 0x00, 0x00, 0x46, 0xb1, + 0x01, 0x07, 0xff, 0xde, 0x44, 0x55, 0x48, 0x30, 0x30, 0x32, 0x43, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x31, 0x35, 0x31, 0x30, 0x32, 0x31, 0x20, 0x20, 0x08, 0x00, 0x67, 0x94, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + .info = { + "FINISAR CORP ", + "FCBN425QB1C03 ", + "DUH002C ", + SFF_100G_AOC_PROPERTIES, + 3, + }, + }, + }, + { + { + .eeprom = { + 0x0d, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x4f, 0x00, 0x00, 0x81, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x07, 0xd7, 0x06, 0x55, 0x06, 0x41, 0x07, 0xab, 0x4b, 0x1d, 0x45, 0x55, 0x48, 0x45, + 0x44, 0x4a, 0x1f, 0x02, 0x2f, 0x75, 0x32, 0x82, 0x37, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x0d, 0xc0, 0x07, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x67, 0x00, 0x0a, 0x00, + 0x00, 0x00, 0x00, 0x40, 0x46, 0x49, 0x4e, 0x49, 0x53, 0x41, 0x52, 0x20, 0x43, 0x4f, 0x52, 0x50, + 0x2e, 0x20, 0x20, 0x20, 0x00, 0x00, 0x90, 0x65, 0x46, 0x54, 0x4c, 0x34, 0x43, 0x31, 0x51, 0x45, + 0x31, 0x43, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x41, 0x31, 0x65, 0xa4, 0x05, 0x14, 0x46, 0xa1, + 0x00, 0x01, 0x0c, 0xd8, 0x55, 0x51, 0x4b, 0x30, 0x4e, 0x4c, 0x31, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x31, 0x33, 0x31, 0x31, 0x32, 0x30, 0x20, 0x20, 0x08, 0x00, 0x00, 0x61, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + .info = { + "FINISAR CORP. ", + "FTL4C1QE1C ", + "UQK0NL1 ", + SFF_40G_BASE_LR4_PROPERTIES, + -1, + }, + }, + }, + { + { + .eeprom = { + 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xd3, 0x00, 0x00, 0x80, 0x56, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x03, 0x23, 0x03, 0xbc, 0x03, 0x20, 0x06, 0x49, 0x4d, 0x76, 0x4f, 0x6a, 0x54, 0x33, + 0x44, 0xc5, 0x3c, 0xd8, 0x38, 0xc4, 0x3b, 0xe6, 0x36, 0x89, 0x80, 0x51, 0x81, 0x48, 0x7e, 0xe2, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0d, 0xc0, 0x07, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x67, 0x00, 0x0a, 0x00, + 0x00, 0x00, 0x00, 0x40, 0x4a, 0x44, 0x53, 0x55, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x01, 0x9c, 0x4a, 0x51, 0x50, 0x2d, 0x30, 0x34, 0x4c, 0x57, + 0x42, 0x41, 0x32, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x31, 0x66, 0x6c, 0x05, 0x14, 0x46, 0xe5, + 0x00, 0x00, 0x0c, 0x98, 0x46, 0x45, 0x33, 0x34, 0x31, 0x30, 0x38, 0x38, 0x43, 0x30, 0x32, 0x34, + 0x20, 0x20, 0x20, 0x20, 0x31, 0x34, 0x30, 0x38, 0x32, 0x32, 0x20, 0x20, 0x08, 0x00, 0x00, 0x39, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + .info = { + "JDSU ", + "JQP-04LWBA2 ", + "FE341088C024 ", + SFF_40G_BASE_LR4_PROPERTIES, + -1, + }, + }, + }, + { + { + .eeprom = { + 0x0d, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x23, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xa0, 0x33, 0x4d, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x07, 0x08, 0x00, 0x21, 0x39, 0x51, 0x41, 0x30, 0x2d, 0x31, 0x31, 0x31, + 0x2d, 0x31, 0x32, 0x2d, 0x31, 0x2e, 0x30, 0x30, 0x30, 0x31, 0x03, 0x05, 0x06, 0x0c, 0x00, 0x56, + 0x00, 0x00, 0x00, 0x00, 0x56, 0x31, 0x30, 0x42, 0x39, 0x32, 0x30, 0x32, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x31, 0x32, 0x30, 0x39, 0x31, 0x37, 0x20, 0x20, 0x00, 0x00, 0x00, 0x3a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + .info = { + "3M Company ", + "9QA0-111-12-1.00", + "V10B9202 ", + SFF_40G_BASE_CR4_PROPERTIES, + 1, + }, + }, + }, + { + { + .eeprom = { + 0x11, 0x07, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0xa4, 0x00, 0x00, 0x81, 0x43, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x96, 0x1d, 0xe5, 0x28, 0xfc, 0x1e, 0x76, 0x30, 0x05, 0x2e, 0x97, 0x30, 0xaf, + 0x41, 0x07, 0x1f, 0x47, 0x1f, 0x70, 0x20, 0x0c, 0x1d, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x11, 0xcc, 0x07, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0x02, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x60, 0x4c, 0x55, 0x4d, 0x45, 0x4e, 0x54, 0x55, 0x4d, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x01, 0x9c, 0x4c, 0x51, 0x32, 0x31, 0x30, 0x43, 0x52, 0x2d, + 0x43, 0x41, 0x41, 0x31, 0x20, 0x20, 0x20, 0x20, 0x30, 0x31, 0x66, 0x6c, 0x05, 0x14, 0x00, 0x96, + 0x06, 0x0f, 0xff, 0xfa, 0x46, 0x46, 0x34, 0x32, 0x35, 0x30, 0x35, 0x30, 0x30, 0x30, 0x31, 0x39, + 0x2d, 0x51, 0x20, 0x20, 0x31, 0x35, 0x31, 0x32, 0x30, 0x32, 0x20, 0x20, 0x0c, 0x18, 0x67, 0x48, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + .info = { + "LUMENTUM ", + "LQ210CR-CAA1 ", + "FF4250500019-Q ", + SFF_100G_CWDM4_PROPERTIES, + -1, + }, + }, + }, + { + { + .eeprom = { + 0x0d, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x23, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xa0, 0x33, 0x4d, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x07, 0x08, 0x00, 0x21, 0x39, 0x51, 0x41, 0x30, 0x2d, 0x31, 0x31, 0x31, + 0x2d, 0x31, 0x32, 0x2d, 0x31, 0x2e, 0x30, 0x30, 0x30, 0x31, 0x03, 0x05, 0x06, 0x0c, 0x00, 0x56, + 0x00, 0x00, 0x00, 0x00, 0x56, 0x31, 0x30, 0x45, 0x42, 0x30, 0x34, 0x39, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x31, 0x35, 0x31, 0x31, 0x31, 0x30, 0x20, 0x20, 0x00, 0x00, 0x00, 0x44, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + .info = { + "3M Company ", + "9QA0-111-12-1.00", + "V10EB049 ", + SFF_40G_BASE_CR4_PROPERTIES, + 1, + }, + }, + }, + { + { + .eeprom = { + 0x11, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x17, 0x00, 0x00, 0x7f, 0x46, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1e, 0xa9, 0x1c, 0x81, 0x1c, 0x4a, 0x1d, 0xf0, 0x0f, 0xfb, 0x0f, 0x8e, 0x0f, 0x90, + 0x0f, 0xe2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x08, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x11, 0xcc, 0x23, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x00, 0x46, 0x49, 0x4e, 0x49, 0x53, 0x41, 0x52, 0x20, 0x43, 0x4f, 0x52, 0x50, + 0x20, 0x20, 0x20, 0x20, 0x1f, 0x00, 0x90, 0x65, 0x46, 0x43, 0x42, 0x4e, 0x34, 0x32, 0x35, 0x51, + 0x42, 0x31, 0x43, 0x31, 0x30, 0x20, 0x20, 0x20, 0x41, 0x31, 0x00, 0x00, 0x00, 0x00, 0x46, 0xb6, + 0x01, 0x07, 0xff, 0xde, 0x44, 0x55, 0x48, 0x30, 0x30, 0x37, 0x34, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x31, 0x35, 0x31, 0x30, 0x32, 0x34, 0x20, 0x20, 0x08, 0x00, 0x67, 0x8d, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + .info = { + "FINISAR CORP ", + "FCBN425QB1C10 ", + "DUH0074 ", + SFF_100G_AOC_PROPERTIES, + 10, + }, + }, + }, + { + { + .eeprom = { + 0x0d, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x23, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xa0, 0x33, 0x4d, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x07, 0x08, 0x00, 0x21, 0x39, 0x51, 0x41, 0x30, 0x2d, 0x31, 0x31, 0x31, + 0x2d, 0x31, 0x32, 0x2d, 0x31, 0x2e, 0x30, 0x30, 0x30, 0x31, 0x03, 0x05, 0x06, 0x0c, 0x00, 0x56, + 0x00, 0x00, 0x00, 0x00, 0x56, 0x31, 0x30, 0x45, 0x42, 0x30, 0x34, 0x36, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x31, 0x35, 0x31, 0x31, 0x31, 0x30, 0x20, 0x20, 0x00, 0x00, 0x00, 0x41, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + .info = { + "3M Company ", + "9QA0-111-12-1.00", + "V10EB046 ", + SFF_40G_BASE_CR4_PROPERTIES, + 1, + }, + }, + }, + { + { + .eeprom = { + 0x11, 0x07, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x2d, 0x00, 0x00, 0x7f, 0x58, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x12, 0xf8, 0x12, 0x17, 0x17, 0x09, 0x0f, 0x2e, 0x8c, 0x56, 0x79, 0x8a, 0x7e, 0x21, + 0x84, 0xb5, 0x1f, 0x8d, 0x21, 0x25, 0x20, 0xa1, 0x23, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, + 0x11, 0xcd, 0x07, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x64, 0x44, 0x45, 0x4c, 0x4c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x1f, 0x22, 0x33, 0x4d, 0x46, 0x58, 0x47, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x41, 0x30, 0x66, 0x58, 0x01, 0x90, 0x46, 0x7a, + 0x03, 0x0f, 0xff, 0xda, 0x43, 0x4e, 0x30, 0x33, 0x4d, 0x46, 0x58, 0x47, 0x35, 0x36, 0x49, 0x30, + 0x30, 0x30, 0x31, 0x20, 0x31, 0x35, 0x30, 0x36, 0x31, 0x38, 0x20, 0x20, 0x0c, 0x10, 0x67, 0x9e, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xdf, 0x10, 0x01, 0x21, 0x41, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + .info = { + "DELL ", + "3MFXG ", + "CN03MFXG56I0001 ", + SFF_100G_BASE_LR4_PROPERTIES, + -1, + }, + }, + }, + { + { + .eeprom = { + 0x0d, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x23, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xa0, 0x33, 0x4d, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x07, 0x08, 0x00, 0x21, 0x39, 0x51, 0x41, 0x30, 0x2d, 0x31, 0x31, 0x31, + 0x2d, 0x31, 0x32, 0x2d, 0x31, 0x2e, 0x30, 0x30, 0x30, 0x31, 0x03, 0x05, 0x06, 0x0c, 0x00, 0x56, + 0x00, 0x00, 0x00, 0x00, 0x56, 0x31, 0x30, 0x45, 0x42, 0x30, 0x30, 0x31, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x31, 0x35, 0x31, 0x31, 0x31, 0x30, 0x20, 0x20, 0x00, 0x00, 0x00, 0x38, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + .info = { + "3M Company ", + "9QA0-111-12-1.00", + "V10EB001 ", + SFF_40G_BASE_CR4_PROPERTIES, + 1, + }, + }, + }, + { + { + .eeprom = { + 0x0d, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x23, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xa0, 0x33, 0x4d, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x07, 0x08, 0x00, 0x21, 0x39, 0x51, 0x41, 0x30, 0x2d, 0x31, 0x31, 0x31, + 0x2d, 0x31, 0x32, 0x2d, 0x31, 0x2e, 0x30, 0x30, 0x30, 0x31, 0x03, 0x05, 0x06, 0x0c, 0x00, 0x56, + 0x00, 0x00, 0x00, 0x00, 0x56, 0x31, 0x30, 0x42, 0x39, 0x37, 0x36, 0x35, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x31, 0x32, 0x30, 0x39, 0x31, 0x37, 0x20, 0x20, 0x00, 0x00, 0x00, 0x48, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + .info = { + "3M Company ", + "9QA0-111-12-1.00", + "V10B9765 ", + SFF_40G_BASE_CR4_PROPERTIES, + 1, + }, + }, + }, + { + { + .eeprom = { + 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x89, 0x00, 0x00, 0x80, 0xfc, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x2c, 0x7a, 0x2c, 0x51, 0x23, 0x1a, 0x25, 0x43, 0x0d, 0xb3, 0x0d, 0x77, 0x0d, 0xc7, + 0x0d, 0x7f, 0x1a, 0xed, 0x1b, 0x3e, 0x1c, 0xa4, 0x1c, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x0c, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x67, 0x00, 0x00, 0x32, + 0x00, 0x00, 0x00, 0x00, 0x41, 0x56, 0x41, 0x47, 0x4f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x17, 0x6a, 0x41, 0x46, 0x42, 0x52, 0x2d, 0x37, 0x39, 0x45, + 0x51, 0x44, 0x5a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x31, 0x42, 0x68, 0x07, 0xd0, 0x46, 0xbe, + 0x00, 0x00, 0x0f, 0xde, 0x51, 0x44, 0x34, 0x39, 0x30, 0x37, 0x32, 0x38, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x31, 0x33, 0x31, 0x32, 0x30, 0x35, 0x20, 0x20, 0x08, 0x00, 0x00, 0x34, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + .info = { + "AVAGO ", + "AFBR-79EQDZ ", + "QD490728 ", + SFF_40G_BASE_SR4_PROPERTIES, + -1, + }, + }, + }, + { + { + .eeprom = { + 0x11, 0x07, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x08, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x11, 0x00, 0x23, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x03, 0xa0, 0x41, 0x6d, 0x70, 0x68, 0x65, 0x6e, 0x6f, 0x6c, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x1f, 0x78, 0xa7, 0x14, 0x4e, 0x44, 0x41, 0x41, 0x46, 0x46, 0x2d, 0x43, + 0x31, 0x30, 0x33, 0x20, 0x20, 0x20, 0x20, 0x20, 0x41, 0x20, 0x07, 0x0b, 0x0d, 0x13, 0x55, 0x15, + 0x0b, 0x00, 0x00, 0x00, 0x41, 0x50, 0x46, 0x31, 0x35, 0x35, 0x30, 0x31, 0x30, 0x33, 0x34, 0x37, + 0x35, 0x46, 0x20, 0x20, 0x31, 0x35, 0x31, 0x32, 0x30, 0x38, 0x20, 0x20, 0x00, 0x00, 0x67, 0x3f, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + }, + .info = { + "Amphenol ", + "NDAAFF-C103 ", + "APF1550103475F ", + SFF_100G_BASE_CR4_PROPERTIES, + 3, + }, + }, + }, + { + { + .eeprom = { + 0x11, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x68, 0x00, 0x00, 0x7f, 0x42, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x34, 0x0f, 0x1c, 0xf3, 0x34, 0x57, 0x33, 0xcf, 0x0d, 0xd3, 0x0d, 0xf9, 0x0e, 0x03, + 0x0d, 0xdf, 0x26, 0xe6, 0x2d, 0xd3, 0x2d, 0xd8, 0x30, 0xd4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xcc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x11, 0xcc, 0x0c, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0x00, 0x00, 0x23, + 0x00, 0x00, 0x32, 0x00, 0x46, 0x49, 0x4e, 0x49, 0x53, 0x41, 0x52, 0x20, 0x43, 0x4f, 0x52, 0x50, + 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x90, 0x65, 0x46, 0x54, 0x4c, 0x43, 0x39, 0x35, 0x35, 0x31, + 0x52, 0x45, 0x50, 0x4d, 0x20, 0x20, 0x20, 0x20, 0x41, 0x30, 0x42, 0x68, 0x07, 0xd0, 0x00, 0x3c, + 0x02, 0x07, 0xff, 0xde, 0x58, 0x55, 0x39, 0x30, 0x54, 0x52, 0x50, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x31, 0x35, 0x31, 0x30, 0x30, 0x36, 0x20, 0x20, 0x0c, 0x10, 0x67, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + .info = { + "FINISAR CORP ", + "FTLC9551REPM ", + "XU90TRP ", + SFF_100G_BASE_SR4_PROPERTIES, + -1, + }, + }, + }, + { + { + .eeprom = { + 0x11, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x66, 0x00, 0x00, 0x7f, 0x45, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x21, 0x1b, 0x1f, 0x2d, 0x1f, 0xe5, 0x1f, 0xdb, 0x0f, 0x25, 0x0f, 0x19, 0x0f, 0x09, + 0x0e, 0xfa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x08, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x11, 0xcc, 0x23, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x05, 0x00, 0x46, 0x49, 0x4e, 0x49, 0x53, 0x41, 0x52, 0x20, 0x43, 0x4f, 0x52, 0x50, + 0x20, 0x20, 0x20, 0x20, 0x1f, 0x00, 0x90, 0x65, 0x46, 0x43, 0x42, 0x4e, 0x34, 0x32, 0x35, 0x51, + 0x42, 0x31, 0x43, 0x30, 0x35, 0x20, 0x20, 0x20, 0x41, 0x31, 0x00, 0x00, 0x00, 0x00, 0x46, 0xb5, + 0x01, 0x07, 0xff, 0xde, 0x44, 0x55, 0x38, 0x30, 0x30, 0x33, 0x45, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x31, 0x35, 0x30, 0x38, 0x32, 0x31, 0x20, 0x20, 0x08, 0x00, 0x67, 0x8e, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + .info = { + "FINISAR CORP ", + "FCBN425QB1C05 ", + "DU8003E ", + SFF_100G_AOC_PROPERTIES, + 5, + }, + }, + }, + { + { + .eeprom = { + 0x03, 0x04, 0x07, 0x10, 0x00, 0x00, 0x00, 0x20, 0x40, 0x0c, 0x80, 0x06, 0x67, 0x00, 0x00, 0x00, + 0x08, 0x03, 0x00, 0x1e, 0x4a, 0x44, 0x53, 0x55, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x01, 0x9c, 0x50, 0x4c, 0x52, 0x58, 0x50, 0x4c, 0x53, 0x43, + 0x53, 0x34, 0x33, 0x32, 0x32, 0x4e, 0x20, 0x20, 0x32, 0x20, 0x20, 0x20, 0x03, 0x52, 0x00, 0xfe, + 0x00, 0x1a, 0x00, 0x00, 0x43, 0x42, 0x34, 0x35, 0x55, 0x46, 0x30, 0x30, 0x31, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x31, 0x31, 0x31, 0x30, 0x33, 0x31, 0x20, 0x20, 0x68, 0xf0, 0x03, 0xd6, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + .info = { + "JDSU ", + "PLRXPLSCS4322N ", + "CB45UF001 ", + SFF_10G_BASE_SR_PROPERTIES, + -1, + }, + }, + }, + { + { + .eeprom = { + 0x03, 0x04, 0x07, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x67, 0x00, 0x00, 0x00, + 0x08, 0x03, 0x00, 0x1e, 0x46, 0x49, 0x4e, 0x49, 0x53, 0x41, 0x52, 0x20, 0x43, 0x4f, 0x52, 0x50, + 0x2e, 0x20, 0x20, 0x20, 0x00, 0x00, 0x90, 0x65, 0x46, 0x54, 0x4c, 0x58, 0x38, 0x35, 0x37, 0x31, + 0x44, 0x33, 0x42, 0x43, 0x4c, 0x20, 0x20, 0x20, 0x41, 0x20, 0x20, 0x20, 0x03, 0x52, 0x00, 0x48, + 0x00, 0x1a, 0x00, 0x00, 0x4d, 0x54, 0x38, 0x31, 0x54, 0x45, 0x58, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x31, 0x35, 0x30, 0x33, 0x30, 0x34, 0x20, 0x20, 0x68, 0xf0, 0x03, 0xfd, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + .info = { + "FINISAR CORP. ", + "FTLX8571D3BCL ", + "MT81TEX ", + SFF_10G_BASE_SR_PROPERTIES, + -1, + }, + }, + }, + { + { + .eeprom = { + 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa2, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x78, 0x00, 0x00, 0x7f, 0x19, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x89, 0x0d, 0x70, 0xb6, 0x51, 0x1b, 0x7e, 0x8a, 0x51, 0x40, 0x44, 0x62, 0x4f, 0x4f, + 0x4a, 0xe3, 0x46, 0x41, 0x45, 0xc9, 0x49, 0x6e, 0x49, 0xab, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x0d, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x67, 0x00, 0x01, 0x46, + 0x00, 0x00, 0x00, 0x40, 0x46, 0x49, 0x4e, 0x49, 0x53, 0x41, 0x52, 0x20, 0x43, 0x4f, 0x52, 0x50, + 0x2e, 0x20, 0x20, 0x20, 0x00, 0x00, 0x90, 0x65, 0x46, 0x54, 0x4c, 0x34, 0x43, 0x33, 0x51, 0x45, + 0x31, 0x43, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x41, 0x31, 0x65, 0xa4, 0x05, 0x14, 0x46, 0xde, + 0x00, 0x01, 0x0c, 0xd8, 0x55, 0x54, 0x4e, 0x30, 0x51, 0x38, 0x34, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x31, 0x36, 0x30, 0x33, 0x31, 0x30, 0x20, 0x20, 0x08, 0x00, 0x00, 0x5c, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + .info = { + "FINISAR CORP. ", + "FTL4C3QE1C ", + "UTN0Q84 ", + SFF_40G_BASE_LM4_PROPERTIES, + -1, + }, + }, + }, + +#endif /** SFF_CONFIG_INCLUDE_DATABASE */ + }; + +int +sff_db_get(sff_db_entry_t** entries, int* count) +{ + *entries = sff_database__; + *count = AIM_ARRAYSIZE(sff_database__); + return *count; +} + +int +sff_db_get_type(sff_eeprom_t* se, sff_module_type_t type) +{ + int i; + sff_db_entry_t* entry; + for(i = 0; i < AIM_ARRAYSIZE(sff_database__); i++) { + entry = sff_database__ + i; + if(se->info.module_type == type) { + memcpy(se, &entry->se, sizeof(*se)); + return 1; + } + } + return 0; +} + +int +sff_db_entry_struct(sff_eeprom_t* se, aim_pvs_t* pvs) +{ + int i, j; + aim_printf(pvs, " {\n"); + aim_printf(pvs, " {\n"); + aim_printf(pvs, " .eeprom = {\n"); + for(i = 0; i < 16; i++) { + aim_printf(pvs, " "); + for(j = 0; j < 16; j++) { + aim_printf(pvs, "0x%.2x, ", se->eeprom[i*16+j]); + } + aim_printf(pvs, "\n"); + } + aim_printf(pvs, " },\n"); + aim_printf(pvs, " .info = {\n"); + aim_printf(pvs, " \"%s\",\n", se->info.vendor); + aim_printf(pvs, " \"%s\",\n", se->info.model); + aim_printf(pvs, " \"%s\",\n", se->info.serial); + aim_printf(pvs, " SFF_%s_PROPERTIES,\n", + sff_module_type_name(se->info.module_type)); + aim_printf(pvs, " %d,\n", se->info.length); + aim_printf(pvs, " },\n"); + aim_printf(pvs, " },\n"); + aim_printf(pvs, " },\n"); + return 0;} diff --git a/packages/base/any/onlp/src/sff/module/src/sff_enums.c b/packages/base/any/onlp/src/sff/module/src/sff_enums.c index d3a4ed30..d748d162 100644 --- a/packages/base/any/onlp/src/sff/module/src/sff_enums.c +++ b/packages/base/any/onlp/src/sff/module/src/sff_enums.c @@ -137,6 +137,7 @@ aim_map_si_t sff_module_type_map[] = { "40G_BASE_CR4", SFF_MODULE_TYPE_40G_BASE_CR4 }, { "40G_BASE_SR4", SFF_MODULE_TYPE_40G_BASE_SR4 }, { "40G_BASE_LR4", SFF_MODULE_TYPE_40G_BASE_LR4 }, + { "40G_BASE_LM4", SFF_MODULE_TYPE_40G_BASE_LM4 }, { "40G_BASE_ACTIVE", SFF_MODULE_TYPE_40G_BASE_ACTIVE }, { "40G_BASE_CR", SFF_MODULE_TYPE_40G_BASE_CR }, { "40G_BASE_SR2", SFF_MODULE_TYPE_40G_BASE_SR2 }, @@ -168,6 +169,7 @@ aim_map_si_t sff_module_type_desc_map[] = { "40GBASE-CR4", SFF_MODULE_TYPE_40G_BASE_CR4 }, { "40GBASE-SR4", SFF_MODULE_TYPE_40G_BASE_SR4 }, { "40GBASE-LR4", SFF_MODULE_TYPE_40G_BASE_LR4 }, + { "40GBASE-LM4", SFF_MODULE_TYPE_40G_BASE_LM4 }, { "40GBASE-ACTIVE", SFF_MODULE_TYPE_40G_BASE_ACTIVE }, { "40GBASE-CR", SFF_MODULE_TYPE_40G_BASE_CR }, { "40GBASE-SR2", SFF_MODULE_TYPE_40G_BASE_SR2 }, diff --git a/packages/base/any/onlp/src/sff/sff.mk b/packages/base/any/onlp/src/sff/sff.mk index 9770d2c8..cfe22be5 100644 --- a/packages/base/any/onlp/src/sff/sff.mk +++ b/packages/base/any/onlp/src/sff/sff.mk @@ -3,12 +3,12 @@ # # Inclusive Makefile for the sff module. # -# Autogenerated 2016-03-23 18:28:25.869697 +# Autogenerated 2016-05-17 17:43:05.843123 # ############################################################################### sff_BASEDIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) -include $(sff_BASEDIR)/module/make.mk -include $(sff_BASEDIR)/module/auto/make.mk -include $(sff_BASEDIR)/module/src/make.mk -include $(sff_BASEDIR)/utest/_make.mk +include $(sff_BASEDIR)module/make.mk +include $(sff_BASEDIR)module/auto/make.mk +include $(sff_BASEDIR)module/src/make.mk +include $(sff_BASEDIR)utest/_make.mk diff --git a/packages/base/any/onlp/src/sff/utest/main.c b/packages/base/any/onlp/src/sff/utest/main.c index 8152fa9b..acf6593d 100644 --- a/packages/base/any/onlp/src/sff/utest/main.c +++ b/packages/base/any/onlp/src/sff/utest/main.c @@ -10,1044 +10,95 @@ #include #include #include - -typedef struct { - sff_info_t info; -} eeprom_verify_t; - - -static eeprom_verify_t data[] = - { - { - { - { - 0x03, 0x04, 0x07, 0x00, 0x00, 0x00, 0x01, 0x20, 0x40, 0x0c, 0x05, 0x01, 0x15, 0x00, 0x00, 0x00, - 0x1e, 0x0f, 0x00, 0x00, 0x46, 0x49, 0x4e, 0x49, 0x53, 0x41, 0x52, 0x20, 0x43, 0x4f, 0x52, 0x50, - 0x2e, 0x20, 0x20, 0x20, 0x00, 0x00, 0x90, 0x65, 0x46, 0x54, 0x52, 0x4a, 0x38, 0x35, 0x31, 0x39, - 0x50, 0x31, 0x42, 0x4e, 0x4c, 0x20, 0x20, 0x20, 0x41, 0x20, 0x20, 0x20, 0x03, 0x52, 0x00, 0x66, - 0x00, 0x12, 0x00, 0x00, 0x50, 0x38, 0x4a, 0x32, 0x5a, 0x4e, 0x43, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x30, 0x35, 0x31, 0x30, 0x33, 0x31, 0x20, 0x20, 0x58, 0x90, 0x01, 0x74, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - }, - "FINISAR CORP. ", - "FTRJ8519P1BNL ", - "P8J2ZNC ", - SFF_SFP_TYPE_SFP, - "SFP", - SFF_MODULE_TYPE_1G_BASE_SX, - "1GBASE-SX", - SFF_MEDIA_TYPE_FIBER, - "Fiber", - SFF_MODULE_CAPS_F_1G, - -1, - }, - }, - /* Amphenol 10GBASE-CR */ - { - /* sff info */ - { - /* eeprom */ - { - 0x03, 0x04, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x01, 0x00, 0x41, 0x6d, 0x70, 0x68, 0x65, 0x6e, 0x6f, 0x6c, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x00, 0x41, 0x50, 0x48, 0x35, 0x37, 0x31, 0x35, 0x34, 0x30, 0x30, 0x30, - 0x37, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x4b, 0x20, 0x20, 0x20, 0x01, 0x00, 0x00, 0xfa, - 0x00, 0x00, 0x00, 0x00, 0x41, 0x50, 0x46, 0x31, 0x30, 0x30, 0x38, 0x30, 0x30, 0x37, 0x30, 0x31, - 0x34, 0x37, 0x20, 0x20, 0x31, 0x30, 0x30, 0x33, 0x30, 0x32, 0x20, 0x20, 0x00, 0x00, 0x00, 0xa9, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - }, - - "Amphenol ", - "571540007 ", - "APF10080070147 ", - - /* sfp_type */ - SFF_SFP_TYPE_SFP, - "SFP", - - /* module_type */ - SFF_MODULE_TYPE_10G_BASE_CR, - "10GBASE-CR", - - /* media_type */ - SFF_MEDIA_TYPE_COPPER, - "Copper", - - /* caps */ - SFF_MODULE_CAPS_F_10G, - - /* Length */ - 0x1 - }, - }, - /* CISCO-MOLEX */ - { - /* sff_info */ - { - /* eeprom */ - { - 0x03, 0x04, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x01, 0x00, 0x43, 0x49, 0x53, 0x43, 0x4f, 0x2d, 0x4d, 0x4f, 0x4c, 0x45, 0x58, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x09, 0x3a, 0x37, 0x34, 0x37, 0x35, 0x32, 0x2d, 0x39, 0x35, - 0x31, 0x39, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x38, 0x20, 0x20, 0x01, 0x00, 0x00, 0x11, - 0x00, 0x00, 0x00, 0x00, 0x4d, 0x4f, 0x43, 0x31, 0x35, 0x34, 0x37, 0x30, 0x30, 0x30, 0x48, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x31, 0x31, 0x31, 0x31, 0x32, 0x31, 0x20, 0x20, 0x00, 0x00, 0x00, 0x8f, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x69, 0xf9, 0x8e, 0x5a, - 0x43, 0x4f, 0x50, 0x51, 0x41, 0x41, 0x34, 0x4a, 0x41, 0x42, 0x33, 0x37, 0x2d, 0x30, 0x39, 0x36, - 0x30, 0x2d, 0x30, 0x33, 0x56, 0x30, 0x33, 0x20, 0x01, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0xcc, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x53, 0x46, 0x50, 0x2d, 0x48, 0x31, 0x30, 0x47, 0x42, 0x2d, 0x43, 0x55, 0x31, 0x4d, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x30, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb3, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }, - "CISCO-MOLEX ", - "74752-9519 ", - "MOC1547000H ", - - /* sfp_type */ - SFF_SFP_TYPE_SFP, - "SFP", - SFF_MODULE_TYPE_10G_BASE_CR, - "10GBASE-CR", - - SFF_MEDIA_TYPE_COPPER, - "Copper", - SFF_MODULE_CAPS_F_10G, - 0x1, - }, - }, - /* Unknown */ - { - /* sff_info */ - { - /* eeprom */ - { - 0x03, 0x04, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, - 0x00, 0x01, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x43, 0x39, 0x39, 0x39, 0x39, 0x2d, 0x31, 0x4d, - 0x2d, 0x50, 0x2d, 0x4c, 0x43, 0x20, 0x20, 0x20, 0x41, 0x20, 0x20, 0x20, 0x01, 0x00, 0x00, 0xa1, - 0x00, 0x00, 0x00, 0x00, 0x31, 0x33, 0x30, 0x35, 0x33, 0x30, 0x30, 0x30, 0x34, 0x31, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x31, 0x33, 0x30, 0x34, 0x31, 0x33, 0x20, 0x20, 0x00, 0x00, 0x00, 0x1d, - 0x00, 0x00, 0x11, 0xb6, 0x7f, 0x7f, 0x08, 0x96, 0xee, 0x8e, 0x60, 0x37, 0xb4, 0xc8, 0x8b, 0x88, - 0x66, 0x9c, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa3, 0xdd, 0x56, 0xe8, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - }, - " ", - "C9999-1M-P-LC ", - "1305300041 ", - SFF_SFP_TYPE_SFP, - "SFP", - SFF_MODULE_TYPE_10G_BASE_CR, - "10GBASE-CR", - SFF_MEDIA_TYPE_COPPER, - "Copper", - SFF_MODULE_CAPS_F_10G, - 0x0, - }, - }, - /* CISCO-MOLEX */ - { - { - { - 0x03, 0x04, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x03, 0x00, 0x43, 0x49, 0x53, 0x43, 0x4f, 0x2d, 0x4d, 0x4f, 0x4c, 0x45, 0x58, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x09, 0x3a, 0x37, 0x34, 0x37, 0x35, 0x32, 0x2d, 0x39, 0x35, - 0x32, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x38, 0x20, 0x20, 0x01, 0x00, 0x00, 0x0b, - 0x00, 0x00, 0x00, 0x00, 0x4d, 0x4f, 0x43, 0x31, 0x36, 0x30, 0x33, 0x30, 0x42, 0x48, 0x34, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x31, 0x32, 0x30, 0x31, 0x31, 0x39, 0x20, 0x20, 0x00, 0x00, 0x00, 0xa5, - 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x04, 0x3b, 0x5b, - 0x43, 0x4f, 0x50, 0x51, 0x41, 0x41, 0x36, 0x4a, 0x41, 0x42, 0x33, 0x37, 0x2d, 0x30, 0x39, 0x36, - 0x31, 0x2d, 0x30, 0x33, 0x56, 0x30, 0x33, 0x20, 0x01, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0xcf, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x53, 0x46, 0x50, 0x2d, 0x48, 0x31, 0x30, 0x47, 0x42, 0x2d, 0x43, 0x55, 0x33, 0x4d, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x30, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb5, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }, - "CISCO-MOLEX ", - "74752-9520 ", - "MOC16030BH4 ", - SFF_SFP_TYPE_SFP, - "SFP", - SFF_MODULE_TYPE_10G_BASE_CR, - "10GBASE-CR", - SFF_MEDIA_TYPE_COPPER, - "Copper", - SFF_MODULE_CAPS_F_10G, - 0x3 - }, - }, - /* OEM */ - { - { - { - 0x00, 0x80, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, - 0x01, 0x0d, 0x33, 0x0c, 0xcb, 0x0c, 0xcb, 0x0d, 0x33, 0x1b, 0xd5, 0x1b, 0x54, 0x18, 0xcd, 0x1c, - 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x0c, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x03, 0x67, 0x00, 0x00, 0x00, 0x0a, 0x03, 0x00, 0x00, 0x4f, 0x45, 0x4d, 0x20, 0x20, - 0x0d, 0x00, 0x0c, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, 0x67, 0x00, 0x00, 0x00, - 0x0a, 0x03, 0x00, 0x00, 0x4f, 0x45, 0x4d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x07, 0x00, 0x1e, 0x00, 0x51, 0x53, 0x46, 0x50, 0x2d, 0x34, 0x30, 0x47, - 0x2d, 0x53, 0x52, 0x34, 0x20, 0x20, 0x20, 0x20, 0x31, 0x41, 0x42, 0x68, 0x07, 0xd0, 0x46, 0x0c, - 0x00, 0x00, 0x00, 0xde, 0x41, 0x43, 0x52, 0x34, 0x30, 0x47, 0x30, 0x30, 0x34, 0x31, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x31, 0x32, 0x30, 0x38, 0x32, 0x37, 0x31, 0x39, 0x08, 0x00, 0x00, 0x8a, - 0x00, 0x00, 0x11, 0x9d, 0xf1, 0x68, 0x34, 0xac, 0xb2, 0x3d, 0xc6, 0x19, 0x53, 0x0b, 0xbf, 0xf0, - 0x2e, 0xe1, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf7, 0xfe, 0x58, 0x27, - }, - "OEM ", - "QSFP-40G-SR4 ", - "ACR40G0041 ", - SFF_SFP_TYPE_QSFP_PLUS, - "QSFP+", - SFF_MODULE_TYPE_40G_BASE_SR4, - "40GBASE-SR4", - SFF_MEDIA_TYPE_FIBER, - "Fiber", - SFF_MODULE_CAPS_F_40G, - -1, - }, - }, - { - { - { - 0x0d, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0d, 0x00, 0x23, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x03, 0xa0, 0x41, 0x6d, 0x70, 0x68, 0x65, 0x6e, 0x6f, 0x6c, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x00, 0x78, 0xa7, 0x14, 0x36, 0x30, 0x33, 0x30, 0x32, 0x30, 0x30, 0x30, - 0x33, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x42, 0x20, 0x07, 0x0b, 0x00, 0x00, 0x46, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x41, 0x50, 0x46, 0x31, 0x33, 0x30, 0x32, 0x30, 0x30, 0x33, 0x35, 0x41, - 0x52, 0x56, 0x20, 0x20, 0x31, 0x33, 0x30, 0x31, 0x31, 0x35, 0x20, 0x20, 0x00, 0x00, 0x00, 0xf9, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - }, - "Amphenol ", - "603020003 ", - "APF13020035ARV ", - SFF_SFP_TYPE_QSFP_PLUS, - "QSFP+", - SFF_MODULE_TYPE_40G_BASE_CR4, - "40GBASE-CR4", - SFF_MEDIA_TYPE_COPPER, - "Copper", - SFF_MODULE_CAPS_F_40G, - 0x3 - }, - }, - /* Fiberstore */ - { - { - { - 0x03, 0x04, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x01, 0x00, 0x46, 0x69, 0x62, 0x65, 0x72, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x40, 0x20, 0x31, 0x30, 0x47, 0x53, 0x46, 0x50, 0x2d, 0x50, - 0x43, 0x2d, 0x33, 0x30, 0x2d, 0x31, 0x20, 0x20, 0x41, 0x30, 0x20, 0x20, 0x00, 0x00, 0x00, 0xd9, - 0x00, 0x00, 0x00, 0x00, 0x46, 0x53, 0x34, 0x30, 0x32, 0x31, 0x32, 0x44, 0x30, 0x31, 0x37, 0x36, - 0x20, 0x20, 0x20, 0x20, 0x31, 0x34, 0x30, 0x32, 0x31, 0x33, 0x20, 0x20, 0x00, 0x00, 0x00, 0x8f, - 0x00, 0x00, 0x11, 0x4b, 0xd4, 0xe4, 0xc5, 0x99, 0xd1, 0xfb, 0xdb, 0x5e, 0xa2, 0xc4, 0x62, 0x0c, - 0xf2, 0x5b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x26, 0xfa, 0x99, - 0x43, 0x4f, 0x50, 0x51, 0x41, 0x41, 0x34, 0x4a, 0x41, 0x41, 0x33, 0x37, 0x2d, 0x30, 0x39, 0x36, - 0x30, 0x2d, 0x30, 0x32, 0x56, 0x30, 0x32, 0x20, 0x01, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0xc9, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x53, 0x46, 0x50, 0x2d, 0x48, 0x31, 0x30, 0x47, 0x42, 0x2d, 0x43, 0x55, 0x31, 0x4d, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x30, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb3, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }, - "FiberStore ", - "10GSFP-PC-30-1 ", - "FS40212D0176 ", - SFF_SFP_TYPE_SFP, - "SFP", - SFF_MODULE_TYPE_10G_BASE_CR, - "10GBASE-CR", - SFF_MEDIA_TYPE_COPPER, - "Copper", - SFF_MODULE_CAPS_F_10G, - 0x1, - }, - }, - /* - * Finisar FTLX1871M3BCL, see PAN-1005 - * http://www.finisar.com/products/optical-modules/sfp-plus/FTLX1871M3BCL - * http://www.quagwire.com/ftlx1871m3bcl/ - * XXX roth -- from my reading, this is a 10GBASE-ZR module - */ - { - { - { - 0x03, 0x04, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x06, 0x67, 0x00, 0x50, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x46, 0x49, 0x4e, 0x49, 0x53, 0x41, 0x52, 0x20, 0x43, 0x4f, 0x52, 0x50, - 0x2e, 0x20, 0x20, 0x20, 0x00, 0x00, 0x90, 0x65, 0x46, 0x54, 0x4c, 0x58, 0x31, 0x38, 0x37, 0x31, - 0x4d, 0x33, 0x42, 0x43, 0x4c, 0x20, 0x20, 0x20, 0x41, 0x20, 0x20, 0x20, 0x06, 0x0e, 0x00, 0x33, - 0x06, 0x1a, 0x00, 0x00, 0x55, 0x50, 0x47, 0x30, 0x31, 0x57, 0x4a, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x31, 0x33, 0x30, 0x34, 0x32, 0x39, 0x20, 0x20, 0x68, 0xf0, 0x05, 0xfe, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }, - "FINISAR CORP. ", - "FTLX1871M3BCL ", - "UPG01WJ ", - SFF_SFP_TYPE_SFP, - "SFP", - SFF_MODULE_TYPE_10G_BASE_ZR, - "1GBASE-ZR", - SFF_MEDIA_TYPE_FIBER, - "Fiber", - SFF_MODULE_CAPS_F_10G, - -1, - }, - }, - /* - * Finisar FTLX8570D3BCL, see PAN-1006 - * http://www.finisar.com/products/optical-modules/sfp-plus/FTLX1671D3BCL - * http://www.quagwire.com/ftlx8570d3bcl/ - * XXX roth -- from my reading, this is a 10GBASE-SR-lite - */ - { - { - { - 0x03, 0x04, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x67, 0x00, 0x00, 0x00, - 0x03, 0x01, 0x00, 0x0a, 0x46, 0x49, 0x4e, 0x49, 0x53, 0x41, 0x52, 0x20, 0x43, 0x4f, 0x52, 0x50, - 0x2e, 0x20, 0x20, 0x20, 0x00, 0x00, 0x90, 0x65, 0x46, 0x54, 0x4c, 0x58, 0x38, 0x35, 0x37, 0x30, - 0x44, 0x33, 0x42, 0x43, 0x4c, 0x20, 0x20, 0x20, 0x41, 0x20, 0x20, 0x20, 0x03, 0x52, 0x00, 0x1c, - 0x00, 0x1a, 0x00, 0x00, 0x50, 0x50, 0x34, 0x34, 0x51, 0x56, 0x31, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x31, 0x33, 0x30, 0x32, 0x31, 0x37, 0x20, 0x20, 0x68, 0xf0, 0x03, 0xe3, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }, - "FINISAR CORP. ", - "FTLX8570D3BCL ", - "PP44QV1 ", - SFF_SFP_TYPE_SFP, - "SFP", - SFF_MODULE_TYPE_10G_BASE_SRL, - "1GBASE-SRL", - SFF_MEDIA_TYPE_FIBER, - "Fiber", - SFF_MODULE_CAPS_F_10G, - -1, - }, - }, - /* - * Finisar FTRJ1319P1BTL-MD, see PAN-1011 - * http://www.technodirect.com/finisarsfp2125gb1310nm10kmlongwavetransceiverftrj1319p1btl-md.aspx - * XXX roth -- from my reading, this is a 1GBASE-LX optic - * (10km) but it supports 2G FC. - */ - { - { - { - 0x03, 0x04, 0x07, 0x00, 0x00, 0x00, 0x02, 0x12, 0x10, 0x01, 0x05, 0x01, 0x15, 0x00, 0x0a, 0x64, - 0x00, 0x00, 0x00, 0x00, 0x46, 0x49, 0x4e, 0x49, 0x53, 0x41, 0x52, 0x20, 0x43, 0x4f, 0x52, 0x50, - 0x2e, 0x20, 0x20, 0x20, 0x00, 0x00, 0x90, 0x65, 0x46, 0x54, 0x52, 0x4a, 0x31, 0x33, 0x31, 0x39, - 0x50, 0x31, 0x42, 0x54, 0x4c, 0x2d, 0x4d, 0x44, 0x41, 0x20, 0x20, 0x20, 0x05, 0x1e, 0x00, 0x88, - 0x00, 0x1a, 0x00, 0x00, 0x50, 0x44, 0x42, 0x31, 0x56, 0x51, 0x55, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x30, 0x38, 0x30, 0x33, 0x31, 0x37, 0x20, 0x20, 0x68, 0xb0, 0x01, 0xc9, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - }, - "FINISAR CORP. ", - "FTRJ1319P1BTL-MD", - "PDB1VQU ", - SFF_SFP_TYPE_SFP, - "SFP", - SFF_MODULE_TYPE_1G_BASE_LX, - "1GBASE-LR", - SFF_MEDIA_TYPE_FIBER, - "Fiber", - SFF_MODULE_CAPS_F_1G, - -1, - }, - }, - /* - * Juniper/Tyco 10G CR, see PAN-934 - * - */ - { - { - { - 0x03, 0x04, 0x21, 0x81, 0x00, 0x00, 0x04, 0x41, 0x04, 0x80, 0xd5, 0x00, 0x67, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x01, 0x00, 0x54, 0x79, 0x63, 0x6f, 0x20, 0x45, 0x6c, 0x65, 0x63, 0x74, 0x72, 0x6f, - 0x6e, 0x69, 0x63, 0x73, 0x00, 0x00, 0x40, 0x20, 0x32, 0x31, 0x30, 0x30, 0x38, 0x37, 0x30, 0x2d, - 0x31, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x41, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x8a, - 0x00, 0x00, 0x00, 0x00, 0x30, 0x39, 0x33, 0x35, 0x45, 0x30, 0x34, 0x38, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x31, 0x30, 0x30, 0x35, 0x30, 0x39, 0x30, 0x30, 0x00, 0x00, 0x00, 0x41, - 0x37, 0x34, 0x30, 0x2d, 0x30, 0x33, 0x30, 0x30, 0x37, 0x36, 0x20, 0x52, 0x45, 0x56, 0x20, 0x30, - 0x31, 0x20, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - }, - "Tyco Electronics", - "2100870-1 ", - "0935E048 ", - SFF_SFP_TYPE_SFP, - "SFP", - SFF_MODULE_TYPE_10G_BASE_CR, - "10GBASE-CR", - SFF_MEDIA_TYPE_COPPER, - "Copper", - SFF_MODULE_CAPS_F_10G, - 1, - }, - }, - /* - * QSFP+ 40G-bidi - */ - { - { - { - /* 0 */ 0x0d, 0x00, 0x02, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 16 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 32 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 48 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 64 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 80 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 96 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 112 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 128 */ 0x0d, 0xdc, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0xce, 0x00, 0x00, 0x32, - /* 144 */ 0x00, 0x00, 0x00, 0x00, 0x43, 0x49, 0x53, 0x43, 0x4f, 0x2d, 0x41, 0x56, 0x41, 0x47, 0x4f, 0x20, - /* 160 */ 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x17, 0x6a, 0x41, 0x46, 0x42, 0x52, 0x2d, 0x37, 0x39, 0x45, - /* 176 */ 0x42, 0x50, 0x5a, 0x2d, 0x43, 0x53, 0x31, 0x20, 0x30, 0x31, 0x42, 0x68, 0x07, 0xd0, 0x46, 0x47, - /* 192 */ 0x00, 0x00, 0x0f, 0xde, 0x41, 0x56, 0x4d, 0x31, 0x38, 0x30, 0x39, 0x53, 0x30, 0x54, 0x47, 0x20, - /* 208 */ 0x20, 0x20, 0x20, 0x20, 0x31, 0x34, 0x30, 0x32, 0x32, 0x35, 0x20, 0x20, 0x08, 0x00, 0xf5, 0xcc, - /* 224 */ 0xf5, 0x00, 0x06, 0xd2, 0x04, 0x9c, 0x47, 0x09, 0xc5, 0xaf, 0xcf, 0xb7, 0x65, 0xd9, 0x72, 0x03, - /* 240 */ 0xea, 0x59, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x45, 0xbd, 0x94, - }, - "CISCO-AVAGO ", - "AFBR-79EBPZ-CS1 ", - "AVM1809S0TG ", - SFF_SFP_TYPE_QSFP_PLUS, - "QSFP+", - SFF_MODULE_TYPE_40G_BASE_SR2, - "40GBASE-SR2", - SFF_MEDIA_TYPE_FIBER, - "Fiber", - SFF_MODULE_CAPS_F_40G, - -1, - }, - }, - /* Cisco/Finisar 40G QSFP (QuadWire? AOC? Pigtail?) */ - { - { - { - /* 0x0000 */ 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0x0010 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0xde, 0x00, 0x00, 0x7f, 0x4d, 0x00, 0x00, 0x00, 0x00, - /* 0x0020 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0x0030 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0x0040 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0x0050 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0x0060 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0x0070 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, - /* 0x0080 */ 0x0d, 0x10, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x67, 0x00, 0x00, 0x32, - /* 0x0090 */ 0x1e, 0x00, 0x0a, 0x00, 0x43, 0x49, 0x53, 0x43, 0x4f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - /* 0x00a0 */ 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x90, 0x65, 0x46, 0x43, 0x42, 0x4e, 0x34, 0x31, 0x30, 0x51, - /* 0x00b0 */ 0x45, 0x32, 0x43, 0x31, 0x30, 0x2d, 0x43, 0x31, 0x41, 0x20, 0x42, 0x68, 0x07, 0xd0, 0x46, 0xaf, - /* 0x00c0 */ 0x00, 0x01, 0x04, 0xd8, 0x46, 0x49, 0x53, 0x31, 0x37, 0x33, 0x31, 0x30, 0x30, 0x35, 0x33, 0x2d, - /* 0x00d0 */ 0x41, 0x20, 0x20, 0x20, 0x31, 0x33, 0x30, 0x37, 0x33, 0x31, 0x20, 0x20, 0x0a, 0x00, 0xf6, 0x90, - /* 0x00e0 */ 0x00, 0x00, 0x02, 0x43, 0x59, 0xd3, 0x68, 0x03, 0x46, 0x83, 0x87, 0x75, 0x1f, 0xee, 0x94, 0x62, - /* 0x00f0 */ 0xb8, 0x98, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x5e, 0x75, 0x43, - }, - "CISCO ", - "FCBN410QE2C10-C1", - "FIS17310053-A ", - SFF_SFP_TYPE_QSFP_PLUS, - "QSFP+", - /* XXX roth -- FIXME */ - SFF_MODULE_TYPE_40G_BASE_SR4, - "40GBASE-SR4", - SFF_MEDIA_TYPE_FIBER, - "Fiber", - SFF_MODULE_CAPS_F_40G, - -1, - }, - }, - /* - * Dell/Amphenol 3M copper - * Identifies as intra-enclosure and inter-enclosure - */ - { - { - { - /* 0000 */ 0x03, 0x04, 0x21, 0x01, 0x00, 0x00, 0x00, 0x41, 0x84, 0x80, 0x55, 0x00, 0x67, 0x00, 0x00, 0x00, - /* 0010 */ 0x00, 0x00, 0x03, 0x00, 0x41, 0x6d, 0x70, 0x68, 0x65, 0x6e, 0x6f, 0x6c, 0x20, 0x20, 0x20, 0x20, - /* 0020 */ 0x20, 0x20, 0x20, 0x20, 0x00, 0x78, 0xa7, 0x14, 0x36, 0x31, 0x36, 0x37, 0x34, 0x30, 0x30, 0x30, - /* 0030 */ 0x33, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x43, 0x20, 0x20, 0x20, 0x01, 0x00, 0x00, 0xe3, - /* 0040 */ 0x00, 0x00, 0x00, 0x00, 0x43, 0x4e, 0x30, 0x35, 0x33, 0x48, 0x56, 0x4e, 0x34, 0x34, 0x4c, 0x38, - /* 0050 */ 0x37, 0x59, 0x59, 0x20, 0x31, 0x34, 0x30, 0x34, 0x32, 0x33, 0x20, 0x20, 0x00, 0x00, 0x00, 0x78, - /* 0060 */ 0x0f, 0x10, 0x00, 0xa3, 0x71, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /* 0070 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /* 0080 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /* 0090 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /* 00a0 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /* 00b0 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /* 00c0 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /* 00d0 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /* 00e0 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /* 00f0 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - }, - "Amphenol ", - "616740003 ", - "CN053HVN44L87YY ", - SFF_SFP_TYPE_SFP, - "SFP", - SFF_MODULE_TYPE_10G_BASE_CR, - "10GBASE-CR", - SFF_MEDIA_TYPE_COPPER, - "Copper", - SFF_MODULE_CAPS_F_10G, - 3, - }, - }, - /* - * Dell/Amphenol 3M copper - * Identifies as intra-enclosure and inter-enclosure - */ - { - { - { - /* 0x0000 */ 0x03, 0x04, 0x21, 0x02, 0x00, 0x00, 0x04, 0x41, 0x84, 0x80, 0xd5, 0x00, 0x67, 0x00, 0x00, 0x00, - /* 0x0010 */ 0x00, 0x00, 0x03, 0x00, 0x33, 0x4d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - /* 0x0020 */ 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x31, 0x34, 0x31, 0x30, 0x2d, 0x50, 0x31, 0x37, - /* 0x0030 */ 0x2d, 0x30, 0x30, 0x2d, 0x33, 0x2e, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x1c, - /* 0x0040 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0x0050 */ 0x00, 0x00, 0x00, 0x00, 0x31, 0x32, 0x30, 0x32, 0x32, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, - /* 0x0060 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0x0070 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0x0080 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0x0090 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0x00a0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0x00b0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0x00c0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0x00d0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0x00e0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0x00f0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }, - "3M ", - "1410-P17-00-3.00", - /* XXX roth -- NULL serial number ??!??111! */ - " ", - SFF_SFP_TYPE_SFP, - "SFP", - SFF_MODULE_TYPE_10G_BASE_CR, - "10GBASE-CR", - SFF_MEDIA_TYPE_COPPER, - "Copper", - SFF_MODULE_CAPS_F_10G, - 3, - }, - }, - { - { - { - 0x0d, 0x03, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, - 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x14, 0x21, 0x00, 0x00, 0x83, 0x2c, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x0a, 0x12, 0x48, 0x12, 0x48, 0x12, 0x48, 0x12, 0x48, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, - 0x0c, 0x04, 0x00, 0x00, 0x00, 0x40, 0x40, 0x06, 0x00, 0x05, - 0x64, 0x00, 0x00, 0x32, 0x1e, 0x00, 0x00, 0x00, 0x45, 0x64, - 0x67, 0x65, 0x2d, 0x63, 0x6f, 0x72, 0x45, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x04, 0x70, 0x72, 0xcf, 0x4d, 0x30, - 0x4f, 0x45, 0x43, 0x36, 0x34, 0x30, 0x31, 0x54, 0x30, 0x30, - 0x5a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x42, 0x68, 0x07, 0xd0, - 0x46, 0xb0, 0x00, 0x00, 0x00, 0x12, 0x31, 0x45, 0x37, 0x51, - 0x54, 0x30, 0x30, 0x30, 0x33, 0x30, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x31, 0x34, 0x30, 0x37, 0x32, 0x38, 0x20, 0x20, - 0x08, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }, - "Edge-corE ", - "M0OEC6401T00Z ", - "1E7QT00030 ", - SFF_SFP_TYPE_QSFP_PLUS, - "QSFP+", - SFF_MODULE_TYPE_40G_BASE_SR4, - "40GBASE_SR4", - SFF_MEDIA_TYPE_FIBER, - "Fiber", - SFF_MODULE_CAPS_F_40G, - -1, - } - }, - { - { - { - 0x0d, 0x03, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, - 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x0e, 0x30, 0x00, 0x00, 0x82, 0xa2, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x12, 0x48, 0x12, 0x48, 0x12, 0x48, 0x12, 0x48, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, - 0x0c, 0x04, 0x00, 0x00, 0x00, 0x40, 0x40, 0x06, 0x00, 0x05, - 0x64, 0x00, 0x00, 0x32, 0x1e, 0x00, 0x00, 0x00, 0x45, 0x64, - 0x67, 0x65, 0x2d, 0x63, 0x6f, 0x72, 0x45, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x04, 0x70, 0x72, 0xcf, 0x4d, 0x30, - 0x4f, 0x45, 0x43, 0x36, 0x34, 0x30, 0x31, 0x54, 0x30, 0x30, - 0x5a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x42, 0x68, 0x07, 0xd0, - 0x46, 0xb0, 0x00, 0x00, 0x00, 0x12, 0x31, 0x45, 0x37, 0x51, - 0x54, 0x30, 0x30, 0x30, 0x32, 0x38, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x31, 0x34, 0x30, 0x37, 0x32, 0x38, 0x20, 0x20, - 0x08, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }, - "Edge-corE ", - "M0OEC6401T00Z ", - "1E7QT00028 ", - SFF_SFP_TYPE_QSFP_PLUS, - "QSFP+", - SFF_MODULE_TYPE_40G_BASE_SR4, - "40GBASE_SR4", - SFF_MEDIA_TYPE_FIBER, - "Fiber", - SFF_MODULE_CAPS_F_40G, - -1, - } - }, - { - { - { - 0x0d, 0x03, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x17, 0x9f, 0x00, 0x00, 0x80, 0x29, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x44, 0xd5, 0x44, 0x3a, 0x48, 0xb1, - 0x4d, 0x30, 0x12, 0x48, 0x12, 0x48, 0x12, 0x48, 0x12, 0x48, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x8c, - 0x23, 0x04, 0x00, 0x00, 0x01, 0x40, 0x40, 0x02, 0x00, 0x05, - 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x46, 0x4f, - 0x52, 0x4d, 0x45, 0x52, 0x49, 0x43, 0x41, 0x4f, 0x45, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x04, 0x00, 0x00, 0x00, 0x54, 0x51, - 0x53, 0x2d, 0x51, 0x31, 0x4c, 0x48, 0x38, 0x2d, 0x58, 0x43, - 0x41, 0x31, 0x30, 0x20, 0x00, 0x00, 0x42, 0x68, 0x07, 0xd0, - 0x46, 0x4a, 0x00, 0x00, 0x05, 0x31, 0x39, 0x31, 0x33, 0x33, - 0x32, 0x4c, 0x30, 0x30, 0x30, 0x31, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x31, 0x33, 0x30, 0x38, 0x30, 0x36, 0x20, 0x20, - 0x08, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xef, - 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xf7, 0xf7, 0xf7, - 0xf7, 0xf7, 0xf7, 0xf7, 0xfe, 0xfe, - }, - "FORMERICAOE ", - "TQS-Q1LH8-XCA10 ", - "91332L0001 ", - SFF_SFP_TYPE_QSFP_PLUS, - "QSFP+", - SFF_MODULE_TYPE_40G_BASE_SR4, - "40GBASE_SR4", - SFF_MEDIA_TYPE_FIBER, - "Fiber", - SFF_MODULE_CAPS_F_40G, - 10, - }, - }, - { - /* - * PAN-1233 -- 10G IBM-Amphenol cable - */ - { - { - /* 0x0000 */ 0x03, 0x04, 0x21, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x06, 0x67, 0x00, 0x00, 0x00, - /* - * ^^^^ copper pigtail - * - * ^^^^ no 10G or IB codes - * - * ^^^^ ^^^^ no SONET (fiber) - * - * identifies as 1000BASE-CX ^^^^ - * - * no FC length code ^^^^ - * - * identifies as SFP+ passive ^^^^ - * - * no FC media, copper or otherwise ^^^^ - * - * no FC speed ^^^^ - * - * nominal bitrate 0x67 --> 10.3GB ^^^^ - */ - /* 0x0010 */ 0x00, 0x00, 0x03, 0x00, 0x49, 0x42, 0x4d, 0x2d, 0x41, 0x6d, 0x70, 0x68, 0x65, 0x6e, 0x6f, 0x6c, - /* - * ^^^^ copper cable length (3m) - */ - /* 0x0020 */ 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x17, 0xef, 0x39, 0x30, 0x59, 0x39, 0x34, 0x32, 0x38, 0x2d, - /* 0x0030 */ 0x4e, 0x32, 0x38, 0x35, 0x30, 0x30, 0x41, 0x20, 0x46, 0x20, 0x20, 0x20, 0x01, 0x00, 0x00, 0x7a, - /* 0x0040 */ 0x00, 0x00, 0x00, 0x00, 0x59, 0x33, 0x35, 0x30, 0x56, 0x54, 0x32, 0x42, 0x52, 0x31, 0x46, 0x47, - /* 0x0050 */ 0x20, 0x20, 0x20, 0x20, 0x31, 0x32, 0x31, 0x31, 0x32, 0x37, 0x20, 0x20, 0x00, 0x00, 0x00, 0x0d, - /* 0x0060 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /* 0x0070 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /* 0x0080 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /* 0x0090 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /* 0x00a0 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /* 0x00b0 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /* 0x00c0 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /* 0x00d0 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /* 0x00e0 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /* 0x00f0 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - }, - "IBM-Amphenol ", - "90Y9428-N28500A ", - "Y350VT2BR1FG ", - SFF_SFP_TYPE_SFP, - "SFP", - SFF_MODULE_TYPE_10G_BASE_CR, - "10GBASE-CR", - SFF_MEDIA_TYPE_COPPER, - "Copper", - SFF_MODULE_CAPS_F_10G, - 3, - }, - }, - { - /* Verify string normalization for unprintable characters in the vendor, model, or serial number fields. */ - { - { - /* 0x0000 */ 0x03, 0x04, 0x21, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x06, 0x67, 0x00, 0x00, 0x00, - /* 0x0010 */ 0x00, 0x00, 0x03, 0x00, 0x49, 0x42, 0x4d, 0x2d, 0x41, 0x6d, 0x70, 0x68, 0x65, 0x6e, 0x6f, 0x6c, - /* 0x0020 */ 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x17, 0xef, 0x39, 0x30, 0x59, 0x39, 0x34, 0x32, 0x38, 0xFd, - /* 0x0030 */ 0x4e, 0x32, 0x38, 0x35, 0x30, 0x30, 0x41, 0x20, 0x46, 0x20, 0x20, 0x20, 0x01, 0x00, 0x00, 0x8a, - /* 0x0040 */ 0x00, 0x00, 0x00, 0x00, 0x59, 0x33, 0xF5, 0xF0, 0x56, 0x54, 0x32, 0x42, 0x52, 0x31, 0x46, 0x47, - /* 0x0050 */ 0x20, 0x20, 0x20, 0x20, 0x31, 0x32, 0x31, 0x31, 0x32, 0x37, 0x20, 0x20, 0x00, 0x00, 0x00, 0x8d, - /* 0x0060 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /* 0x0070 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /* 0x0080 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /* 0x0090 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /* 0x00a0 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /* 0x00b0 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /* 0x00c0 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /* 0x00d0 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /* 0x00e0 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /* 0x00f0 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - }, - "IBM-Amphenol????", - "90Y9428?N28500A ", - "Y3??VT2BR1FG ", - SFF_SFP_TYPE_SFP, - "SFP", - SFF_MODULE_TYPE_10G_BASE_CR, - "10GBASE-CR", - SFF_MEDIA_TYPE_COPPER, - "Copper", - SFF_MODULE_CAPS_F_10G, - 3, - }, - }, - { - /* - * Finisar 40G AOC breakout cable - */ - { - { - /* 0x0000 */ 0x0d, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0x0010 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x9f, 0x00, 0x00, 0x80, 0xc2, 0x00, 0x00, 0x00, 0x00, - /* 0x0020 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0x0030 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0x0040 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0x0050 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0x0060 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0x0070 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, - - /* 0x0080 */ 0x0d, 0x10, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x67, 0x00, 0x00, 0x00, - /* - * ^^^^ QSFP+ - * - * ^^^^ no separable connector (active?) - * - * ^^^^^ no media compliance (*NOT* 40G active) - * - * ^^^^ no SONET compliance - * - * ^^^^ no SAS compliance - * - * ^^^^ no GbE compliance - * - * ^^^^ ^^^^ no FC compliance - * - * ^^^^ no FC media - * - * ^^^^ no FC speed - * - * ^^^^ 64b66b - * - * ^^^^ nominal BR >= 10G - * no SM or OM3 length ^^^^ ^^^^ - */ - /* 0x0090 */ 0x00, 0x00, 0x03, 0x00, 0x46, 0x49, 0x4e, 0x49, 0x53, 0x41, 0x52, 0x20, 0x43, 0x4f, 0x52, 0x50, - /* - * ^^^^ ^^^^ no OM1 or OM2 length - * - * ^^^^ 3M cable (copper or active) - */ - /* 0x00a0 */ 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x90, 0x65, 0x46, 0x43, 0x42, 0x4e, 0x35, 0x31, 0x30, 0x51, - /* 0x00b0 */ 0x45, 0x32, 0x43, 0x30, 0x33, 0x20, 0x20, 0x20, 0x41, 0x20, 0x42, 0x68, 0x07, 0xd0, 0x46, 0x29, - /* - * ^^^^ ^^^^ 850nm - */ - /* 0x00c0 */ 0x00, 0x01, 0x04, 0xd8, 0x44, 0x53, 0x4b, 0x30, 0x34, 0x56, 0x52, 0x20, 0x20, 0x20, 0x20, 0x20, - /* 0x00d0 */ 0x20, 0x20, 0x20, 0x20, 0x31, 0x34, 0x31, 0x31, 0x30, 0x34, 0x20, 0x20, 0x08, 0x00, 0xf6, 0x54, - /* 0x00e0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0x00f0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }, - "FINISAR CORP ", - "FCBN510QE2C03 ", - "DSK04VR ", - SFF_SFP_TYPE_QSFP_PLUS, - "QSFP+", - SFF_MODULE_TYPE_40G_BASE_SR4, - "40GBASE-SR4", - SFF_MEDIA_TYPE_FIBER, - "Fiber", - SFF_MODULE_CAPS_F_40G, - 3, - }, - }, - { - /* - * Finisar 40G AOC breakout cable, 10G end - */ - { - { - /* 0x0000 */ 0x03, 0x04, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x06, 0x67, 0x00, 0x00, 0x00, - /* - * ^^^^ SFP+ - * - * ^^^^ copper pigtail (ugh) - * - * ^^^^ no 10G or IF compliance - * - * ^^^^ no SONET compliance - * - * ^^^^ no OC length spec - * - * ^^^^ no ethernet compliance - * - * ^^^^ no FC length or tech - * - * ^^^^ active cable, no FC tech - * - * ^^^^ no FC media - * - * ^^^^ no FC speed - * - * ^^^^ 64/66 encoding - * - * nominal BR >= 10G ^^^^ - * - * no SM length ^^^^ ^^^^ - */ - /* 0x0010 */ 0x00, 0x00, 0x01, 0x00, 0x46, 0x49, 0x4e, 0x49, 0x53, 0x41, 0x52, 0x20, 0x43, 0x4f, 0x52, 0x50, - /* - * ^^^^ ^^^^ no MM length - * - * ^^^^ active/copper length 1m - * - * ^^^^ no OM3 length - * - */ - /* 0x0020 */ 0x2e, 0x20, 0x20, 0x20, 0x00, 0x00, 0x90, 0x65, 0x46, 0x43, 0x42, 0x4e, 0x35, 0x31, 0x30, 0x51, - /* 0x0030 */ 0x45, 0x32, 0x43, 0x30, 0x31, 0x20, 0x20, 0x20, 0x41, 0x20, 0x20, 0x20, 0x0c, 0x00, 0x00, 0xa9, - /* - * compliant with FC or SFF limiting ^^^^ ^^^^ - */ - /* 0x0040 */ 0x00, 0x12, 0x00, 0x00, 0x44, 0x53, 0x4a, 0x30, 0x35, 0x39, 0x53, 0x20, 0x20, 0x20, 0x20, 0x20, - /* 0x0050 */ 0x20, 0x20, 0x20, 0x20, 0x31, 0x34, 0x31, 0x30, 0x33, 0x30, 0x20, 0x20, 0x00, 0x00, 0x05, 0x72, - /* 0x0060 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0x0070 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0x0080 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0x0090 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0x00a0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0x00b0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0x00c0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0x00d0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0x00e0 */ 0x00, 0x7f, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* 0x00f0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, - }, - "FINISAR CORP. ", - "FCBN510QE2C01 ", - "DSJ059S ", - SFF_SFP_TYPE_SFP, - "SFP", - SFF_MODULE_TYPE_10G_BASE_SR, - "10GBASE-SR", - SFF_MEDIA_TYPE_FIBER, - "Fiber", - SFF_MODULE_CAPS_F_10G, - 1, - }, - }, - }; - +#include int aim_main(int argc, char* argv[]) { int i; - int first = 0; - int last = AIM_ARRAYSIZE(data)-1; - if(argv[1]) { - first = last = atoi(argv[1]); - } + sff_db_entry_t* entries; + sff_db_entry_t* p; + int count; - for(i = first; i <= last; i++) { + sff_db_get(&entries, &count); + + for(i = 0, p=entries; i < count; i++, p++) { int rv; - sff_info_t info; - eeprom_verify_t* p = data+i; + sff_eeprom_t se; aim_printf(&aim_pvs_stdout, "Verifying entry %d: %s:%s:%s...\n", i, - p->info.vendor, - p->info.model, - p->info.serial); + p->se.info.vendor, + p->se.info.model, + p->se.info.serial); - if( (rv=sff_info_init(&info, p->info.eeprom)) < 0) { - AIM_DIE("index=%d sff_info_init=%d\n", i, rv); + if( (rv=sff_eeprom_parse(&se, p->se.eeprom)) < 0) { + AIM_DIE("index=%d sff_eeprom_parse=%d\n", i, rv); } - if (!info.supported) { - AIM_DIE("index=%d supported=0\n", i); + if (!se.identified) { + AIM_DIE("index=%d identified=0\n", i); } - - if(strcmp(info.vendor, p->info.vendor)) { + if(strcmp(se.info.vendor, p->se.info.vendor)) { AIM_DIE("index=%d vendor expected '%s' got '%s'", - i, p->info.vendor, info.vendor); + i, p->se.info.vendor, se.info.vendor); } - if(strcmp(info.model, p->info.model)) { + if(strcmp(se.info.model, p->se.info.model)) { AIM_DIE("index=%d model expected '%s' got '%s'", - i, p->info.model, info.model); + i, p->se.info.model, se.info.model); } - if(strcmp(info.serial, p->info.serial)) { + if(strcmp(se.info.serial, p->se.info.serial)) { AIM_DIE("index=%d serial expected '%s' got '%s'", - i, p->info.serial, info.serial); + i, p->se.info.serial, se.info.serial); } - if(info.sfp_type != p->info.sfp_type) { + if(se.info.sfp_type != p->se.info.sfp_type) { AIM_DIE("index=%d sfp_type expected '%{sff_sfp_type}' got '%{sff_sfp_type}'", - i, p->info.sfp_type, info.sfp_type); + i, p->se.info.sfp_type, se.info.sfp_type); } - if(strcmp(info.sfp_type_name, p->info.sfp_type_name)) { + if(strcmp(se.info.sfp_type_name, p->se.info.sfp_type_name)) { AIM_DIE("index=%d type_name expected '%s' got '%s'", - i, p->info.sfp_type, info.sfp_type); + i, p->se.info.sfp_type, se.info.sfp_type); } - if(info.module_type != p->info.module_type) { + if(se.info.module_type != p->se.info.module_type) { AIM_DIE("index=%d module_type expected '%{sff_module_type}' got '%{sff_module_type}'", - i, p->info.module_type, info.module_type); + i, p->se.info.module_type, se.info.module_type); } - if(info.media_type != p->info.media_type) { + if(se.info.media_type != p->se.info.media_type) { AIM_DIE("index=%d media_type expected '%{sff_media_type}' got '%{sff_media_type}'\n", - i, p->info.media_type, info.media_type); + i, p->se.info.media_type, se.info.media_type); } - if(strcmp(info.media_type_name, p->info.media_type_name)) { + if(strcmp(se.info.media_type_name, p->se.info.media_type_name)) { AIM_DIE("index=%d media_type_name expected '%s' got '%s'", - i, p->info.media_type_name, info.media_type_name); + i, p->se.info.media_type_name, se.info.media_type_name); } - - if (info.caps != p->info.caps) { + if (se.info.caps != p->se.info.caps) { AIM_DIE("index=%d caps expected '%{sff_module_caps}' got '%{sff_module_caps}'", - i, p->info.caps, info.caps); + i, p->se.info.caps, se.info.caps); } - if(info.length != p->info.length) { + if(se.info.length != p->se.info.length) { AIM_DIE("index=%d length expected %d got %d", - i, p->info.length, info.length); + i, p->se.info.length, se.info.length); } - - if(info.length == -1 && info.length_desc[0]) { + if(se.info.length == -1 && se.info.length_desc[0]) { AIM_DIE("index=%d length_desc expected '%s' got '%s'", - i, '\0', info.length_desc); + i, '\0', se.info.length_desc); } - else if(info.length != -1) { + else if(se.info.length != -1) { char tmp[32]; - snprintf(tmp, sizeof(tmp), "%dm", info.length); - if(strcmp(tmp, info.length_desc)) { + snprintf(tmp, sizeof(tmp), "%dm", se.info.length); + if(strcmp(tmp, se.info.length_desc)) { AIM_DIE("index=%d length_desc expected '%s' got '%s'", - i, tmp, info.length_desc); + i, tmp, se.info.length_desc); } } aim_printf(&aim_pvs_stdout, "Verifying entry %d: %s:%s:%s...PASSED\n", i, - p->info.vendor, - p->info.model, - p->info.serial); + p->se.info.vendor, + p->se.info.model, + p->se.info.serial); } return 0; From 0477d8d90dfc7464d47c0125aafdccafd160444a Mon Sep 17 00:00:00 2001 From: Jeffrey Townsend Date: Tue, 17 May 2016 12:47:28 -0700 Subject: [PATCH 066/113] Init at INFO. --- tools/onlpm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/onlpm.py b/tools/onlpm.py index a3ff9a0c..d45b2e29 100755 --- a/tools/onlpm.py +++ b/tools/onlpm.py @@ -24,7 +24,7 @@ import lsb_release g_dist_codename = lsb_release.get_distro_information().get('CODENAME') -logger = onlu.init_logging('onlpm') +logger = onlu.init_logging('onlpm', logging.INFO) class OnlPackageError(Exception): """General Package Error Exception From b92897252179e6aa2e92c5cbea7e067f19557b9c Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Tue, 17 May 2016 19:20:58 -0700 Subject: [PATCH 067/113] Initialize /etc/fw_env.config from OnlPlatform data --- .../vendor-config-onl/src/bin/initubootenv | 3 ++ .../src/python/onl/uboot/InitUbootApp.py | 53 +++++++++++++++++++ .../src/python/onl/uboot/__init__.py | 3 ++ 3 files changed, 59 insertions(+) create mode 100755 packages/base/all/vendor-config-onl/src/bin/initubootenv create mode 100644 packages/base/all/vendor-config-onl/src/python/onl/uboot/InitUbootApp.py create mode 100644 packages/base/all/vendor-config-onl/src/python/onl/uboot/__init__.py diff --git a/packages/base/all/vendor-config-onl/src/bin/initubootenv b/packages/base/all/vendor-config-onl/src/bin/initubootenv new file mode 100755 index 00000000..e3b47ea1 --- /dev/null +++ b/packages/base/all/vendor-config-onl/src/bin/initubootenv @@ -0,0 +1,3 @@ +#!/usr/bin/python +from onl.uboot import InitUbootApp +InitUbootApp.main() diff --git a/packages/base/all/vendor-config-onl/src/python/onl/uboot/InitUbootApp.py b/packages/base/all/vendor-config-onl/src/python/onl/uboot/InitUbootApp.py new file mode 100644 index 00000000..1311d6bb --- /dev/null +++ b/packages/base/all/vendor-config-onl/src/python/onl/uboot/InitUbootApp.py @@ -0,0 +1,53 @@ +"""InitUbootApp.py + +Initialize the fw_env.config file + +See +https://developer.ridgerun.com/wiki/index.php/Setting_up_fw_printenv_to_modify_u-boot_environment_variables + +""" + +PATH = "/etc/fw_env.config" + +import sys +import onl.platform.current + +platform = onl.platform.current.OnlPlatform() + +d = platform.platform_config +if 'flat_image_tree' not in d: + raise ValueError("missing flat_image_tree section, probably not U-Boot") +d = d.get('loader', {}) +d = d.get('environment', []) +if not d: + raise ValueError("missing or empty loader.environment config") + +with open(PATH, "w") as fd: + fd.write("# device env_offset env_size sector_size sector_count\n") + for m in d: + + dev = m.get('device', None) + if not dev: + raise ValueError("missing device key in environment settings") + + off = m.get('env_offset', None) + if off is None: + raise ValueError("missing env_offset key in environment settings") + + sz = m.get('env_size', None) + if not sz: + raise ValueError("missing env_size key in environment settings") + + ssz = m.get('sector_size', None) + if not ssz: + raise ValueError("missing sector_size key in environment settings") + + ns = m.get('sector_count', None) + if ns is None: + ns = sz / ssz + if ns == 0: ns = 1 + + fd.write("%s 0x%x 0x%x 0x%x %d\n" + % (dev, off, sz, ssz, ns,)) + +sys.exit(0) diff --git a/packages/base/all/vendor-config-onl/src/python/onl/uboot/__init__.py b/packages/base/all/vendor-config-onl/src/python/onl/uboot/__init__.py new file mode 100644 index 00000000..9a2cd3e0 --- /dev/null +++ b/packages/base/all/vendor-config-onl/src/python/onl/uboot/__init__.py @@ -0,0 +1,3 @@ +"""__init__.py + +""" From 6f5361ca9def47967b726381cf819ecebfcdc061 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Tue, 17 May 2016 19:21:25 -0700 Subject: [PATCH 068/113] Canonicalize ma1 based on OnlPlatform data --- .../all/vendor-config-onl/src/bin/initnetdev | 3 + .../src/python/onl/network/MdevApp.py | 68 +++++++++++++++++++ .../src/python/onl/network/__init__.py | 3 + 3 files changed, 74 insertions(+) create mode 100755 packages/base/all/vendor-config-onl/src/bin/initnetdev create mode 100644 packages/base/all/vendor-config-onl/src/python/onl/network/MdevApp.py create mode 100644 packages/base/all/vendor-config-onl/src/python/onl/network/__init__.py diff --git a/packages/base/all/vendor-config-onl/src/bin/initnetdev b/packages/base/all/vendor-config-onl/src/bin/initnetdev new file mode 100755 index 00000000..5f04f395 --- /dev/null +++ b/packages/base/all/vendor-config-onl/src/bin/initnetdev @@ -0,0 +1,3 @@ +#!/usr/bin/python +from onl.network import MdevApp +MdevApp.main() diff --git a/packages/base/all/vendor-config-onl/src/python/onl/network/MdevApp.py b/packages/base/all/vendor-config-onl/src/python/onl/network/MdevApp.py new file mode 100644 index 00000000..48eb1da3 --- /dev/null +++ b/packages/base/all/vendor-config-onl/src/python/onl/network/MdevApp.py @@ -0,0 +1,68 @@ +"""MdevApp.py + +busybox mdev handler for network devices + +""" + +import os, sys +import onl.platform.current +import subprocess + +import logging +logger = None + +def do_add(device): + + platform = onl.platform.current.OnlPlatform() + d = platform.platform_config + d = d.get('network', {}) + d = d.get('interfaces', {}) + + syspath = None + src = "/sys/class/net/%s/device" % device + dst = os.path.realpath(src) + if dst.startswith("/sys/devices/"): + syspath = dst[13:] + + tgtname = None + for intf, idata in d.items(): + + n = idata.get('name', None) + if n is not None and n == device: + sys.stdout.write("found interface name alias %s --> %s\n" + % (device, intf,)) + tgtname = intf + break + + p = idata.get('syspath', None) + if p is not None and p == syspath: + sys.stdout.write("found interface sysfs alias %s --> %s\n" + % (syspath, intf,)) + tgtname = intf + break + + if tgtname is not None: + src = "/sys/class/net/%s/device" % tgtname + if not os.path.exists(src): + sys.stdout.write("remapping interface %s --> %s\n" + % (device, tgtname,)) + cmd = ('ip', 'link', 'set', device, 'name', tgtname,) + subprocess.check_call(cmd) + + return 0 + +def main(): + + args = list(sys.argv) + args.pop(0) + device = args.pop(0) + action = args.pop(0) + + if action == 'add': + sys.exit(do_add(device)) + + sys.stderr.write("*** invalid action %s\n" % action) + sys.exit(1) + +if __name__ == "__main__": + main() diff --git a/packages/base/all/vendor-config-onl/src/python/onl/network/__init__.py b/packages/base/all/vendor-config-onl/src/python/onl/network/__init__.py new file mode 100644 index 00000000..9a2cd3e0 --- /dev/null +++ b/packages/base/all/vendor-config-onl/src/python/onl/network/__init__.py @@ -0,0 +1,3 @@ +"""__init__.py + +""" From 4946198b5e5e87d2aca0d2f0e0b311dce5fcfbea Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Tue, 17 May 2016 19:21:47 -0700 Subject: [PATCH 069/113] Include initnetdev and initubootenv in loader init --- .../base/all/initrds/loader-initrd-files/src/bin/sysinit | 5 +++++ packages/base/all/vendor-config-onl/PKG.yml | 2 ++ 2 files changed, 7 insertions(+) diff --git a/packages/base/all/initrds/loader-initrd-files/src/bin/sysinit b/packages/base/all/initrds/loader-initrd-files/src/bin/sysinit index 07b1f2e3..59c00ae0 100755 --- a/packages/base/all/initrds/loader-initrd-files/src/bin/sysinit +++ b/packages/base/all/initrds/loader-initrd-files/src/bin/sysinit @@ -72,6 +72,11 @@ if [ ! -f /etc/onl/abort ]; then # Initialize platform mounts initmounts -q + # Initialize U-Boot environment + if [ -s /proc/device-tree/model ]; then + initubootenv + fi + if [ -f /etc/issue ]; then cat /etc/issue fi diff --git a/packages/base/all/vendor-config-onl/PKG.yml b/packages/base/all/vendor-config-onl/PKG.yml index d2544bab..025517c9 100644 --- a/packages/base/all/vendor-config-onl/PKG.yml +++ b/packages/base/all/vendor-config-onl/PKG.yml @@ -26,6 +26,8 @@ packages: files: src/python/onl : /usr/lib/python2.7/dist-packages/onl src/bin/initmounts : /bin/initmounts + src/bin/initubootenv : /bin/initubootenv + src/bin/initnetdev : /bin/initnetdev src/bin/pki : /sbin/pki changelog: Changes From c5febda73d18f002e6b81598dd7bbb5cc18bba74 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Tue, 17 May 2016 19:23:31 -0700 Subject: [PATCH 070/113] Include sample configs for fw_env.config and interface name mappings - default mapping (eth0 --> ma1) should just work --- .../lib/platform-config-defaults-uboot.yml | 25 +++++++++++++++++++ .../lib/platform-config-defaults-x86-64.yml | 15 +++++++++++ 2 files changed, 40 insertions(+) diff --git a/packages/base/all/vendor-config-onl/src/lib/platform-config-defaults-uboot.yml b/packages/base/all/vendor-config-onl/src/lib/platform-config-defaults-uboot.yml index 4343389e..e2c03f68 100644 --- a/packages/base/all/vendor-config-onl/src/lib/platform-config-defaults-uboot.yml +++ b/packages/base/all/vendor-config-onl/src/lib/platform-config-defaults-uboot.yml @@ -113,6 +113,15 @@ default: nos_bootcmds: *ide_bootcmds + # Configure the fw_env.config file, + # based on board settings (no defaults here) + # XXX NOTE that you will need to define this for each platform! + ##environment: + ##- device: /dev/mtd3 + ## env_offset: 0x00000000 + ## env_size: 0x00002000 + ## sector_size: 0x00020000 + # Default partitioning scheme # boot, config --> 128MiB (ext2) # images --> 1GiB @@ -134,3 +143,19 @@ default: - ONL-DATA: =: 100% format: ext4 + + network: + + # remap interface names on boot (loader only) + # make sure you have a valid 'ma1' entry in your platform config... + + interfaces: + + # this should work for most systems + ma1: + name: eth0 + + # for other wierd corner cases + ##ma1: + ## name: ~ + ## syspath: SOME-PATH diff --git a/packages/base/all/vendor-config-onl/src/lib/platform-config-defaults-x86-64.yml b/packages/base/all/vendor-config-onl/src/lib/platform-config-defaults-x86-64.yml index 2b188f5c..c3f416bf 100644 --- a/packages/base/all/vendor-config-onl/src/lib/platform-config-defaults-x86-64.yml +++ b/packages/base/all/vendor-config-onl/src/lib/platform-config-defaults-x86-64.yml @@ -104,3 +104,18 @@ default: ##- ONL-IMAGES: 384MiB ##- ONL-DATA: 100% + network: + + # remap interface names on boot (loader only) + # make sure you have a valid 'ma1' entry in your platform config... + + interfaces: + + # this should work for most systems + ma1: + name: eth0 + + # for other wierd corner cases + ##ma1: + ## name: ~ + ## syspath: SOME-PATH From 10cd3f6abd440f14112b06b3707041e4887e2662 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Tue, 17 May 2016 19:25:05 -0700 Subject: [PATCH 071/113] Include u-boot and interface configs for all platforms --- .../r0/src/lib/arm-accton-as4610-54-r0.yml | 7 +++++++ .../r0/src/lib/powerpc-accton-as4600-54t-r0.yml | 12 ++++++++++++ .../r0/src/lib/powerpc-accton-as5610-52x-r0.yml | 12 ++++++++++++ .../r0/src/lib/powerpc-accton-as5710-54x-r0.yml | 12 ++++++++++++ .../r0b/src/lib/powerpc-accton-as5710-54x-r0b.yml | 11 +++++++++++ .../r0/src/lib/powerpc-accton-as6700-32x-r0.yml | 11 +++++++++++ .../r1/src/lib/powerpc-accton-as6700-32x-r1.yml | 11 +++++++++++ .../r0/src/lib/x86-64-accton-as5712-54x-r0.yml | 6 +++++- .../r0/src/lib/x86-64-accton-as5812-54t-r0.yml | 6 ++++++ .../r0/src/lib/x86-64-accton-as5812-54x-r0.yml | 6 ++++++ .../r0/src/lib/x86-64-accton-as6712-32x-r0.yml | 6 ++++++ .../r0/src/lib/x86-64-accton-as6812-32x-r0.yml | 5 +++++ .../r0/src/lib/x86-64-accton-as7512-32x-r0.yml | 6 ++++++ .../r0/src/lib/x86-64-accton-as7712-32x-r0.yml | 6 ++++++ .../r0/src/lib/x86-64-accton-as7716-32x-r0.yml | 6 ++++++ .../r0/src/lib/x86-64-accton-wedge-16x-r0.yml | 6 ++++++ .../r0/src/lib/x86-64-cel-redstone-xp-r0.yml | 6 ++++++ .../r0/src/lib/x86-64-kvm-x86-64-r0.yml | 7 ++++++- .../r0/src/lib/arm-qemu-armv7a-r0.yml | 8 ++++++++ .../r0/src/lib/powerpc-quanta-lb9-r0.yml | 12 ++++++++++++ .../r0/src/lib/powerpc-quanta-ly2-r0.yml | 12 ++++++++++++ .../r0/src/lib/x86-64-quanta-ly6-rangeley-r0.yml | 7 ++++++- .../r0/src/lib/x86-64-quanta-ly8-rangeley-r0.yml | 7 ++++++- 23 files changed, 184 insertions(+), 4 deletions(-) diff --git a/packages/platforms/accton/armel/arm-accton-as4610-54/platform-config/r0/src/lib/arm-accton-as4610-54-r0.yml b/packages/platforms/accton/armel/arm-accton-as4610-54/platform-config/r0/src/lib/arm-accton-as4610-54-r0.yml index 010c3b7d..b4f66c4d 100644 --- a/packages/platforms/accton/armel/arm-accton-as4610-54/platform-config/r0/src/lib/arm-accton-as4610-54-r0.yml +++ b/packages/platforms/accton/armel/arm-accton-as4610-54/platform-config/r0/src/lib/arm-accton-as4610-54-r0.yml @@ -21,3 +21,10 @@ arm-accton-as4610-54-r0: ##partition: /dev/sda1 loadaddr: 0x70000000 nos_bootcmds: *usb2_bootcmds + + environment: + - device: /dev/mtd2 + env_offset: 0x00000000 + env_size: 0x00002000 + sector_size: 0x00010000 + \ No newline at end of file diff --git a/packages/platforms/accton/powerpc/powerpc-accton-as4600-54t/platform-config/r0/src/lib/powerpc-accton-as4600-54t-r0.yml b/packages/platforms/accton/powerpc/powerpc-accton-as4600-54t/platform-config/r0/src/lib/powerpc-accton-as4600-54t-r0.yml index b147cb47..1e8f0c60 100644 --- a/packages/platforms/accton/powerpc/powerpc-accton-as4600-54t/platform-config/r0/src/lib/powerpc-accton-as4600-54t-r0.yml +++ b/packages/platforms/accton/powerpc/powerpc-accton-as4600-54t/platform-config/r0/src/lib/powerpc-accton-as4600-54t-r0.yml @@ -19,6 +19,12 @@ powerpc-accton-as4600-54t-r0: ##partition: /dev/sda1 nos_bootcmds: *usb_bootcmds + environment: + - device: /dev/mtd2 + env_offset: 0x00000000 + env_size: 0x00010000 + sector_size: 0x00010000 + installer: - ONL-BOOT: =: 32MiB @@ -32,3 +38,9 @@ powerpc-accton-as4600-54t-r0: - ONL-DATA: =: 100% format: ext4 + + network: + interfaces: + ma1: + name: ~ + syspath: soc.0/ff725000.ethernet diff --git a/packages/platforms/accton/powerpc/powerpc-accton-as5610-52x/platform-config/r0/src/lib/powerpc-accton-as5610-52x-r0.yml b/packages/platforms/accton/powerpc/powerpc-accton-as5610-52x/platform-config/r0/src/lib/powerpc-accton-as5610-52x-r0.yml index a02ae482..d81acd37 100644 --- a/packages/platforms/accton/powerpc/powerpc-accton-as5610-52x/platform-config/r0/src/lib/powerpc-accton-as5610-52x-r0.yml +++ b/packages/platforms/accton/powerpc/powerpc-accton-as5610-52x/platform-config/r0/src/lib/powerpc-accton-as5610-52x-r0.yml @@ -20,6 +20,12 @@ powerpc-accton-as5610-52x-r0: ##partition: /dev/sda1 nos_bootcmds: *usb_bootcmds + environment: + - device: /dev/mtd1 + env_offset: 0x00000000 + env_size: 0x00010000 + sector_size: 0x00010000 + installer: - ONL-BOOT: =: 128MiB @@ -33,3 +39,9 @@ powerpc-accton-as5610-52x-r0: - ONL-DATA: =: 100% format: ext4 + + network: + interfaces: + ma1: + name: ~ + syspath: soc.0/ff724000.ethernet diff --git a/packages/platforms/accton/powerpc/powerpc-accton-as5710-54x/platform-config/r0/src/lib/powerpc-accton-as5710-54x-r0.yml b/packages/platforms/accton/powerpc/powerpc-accton-as5710-54x/platform-config/r0/src/lib/powerpc-accton-as5710-54x-r0.yml index 91c166c8..3f610df6 100644 --- a/packages/platforms/accton/powerpc/powerpc-accton-as5710-54x/platform-config/r0/src/lib/powerpc-accton-as5710-54x-r0.yml +++ b/packages/platforms/accton/powerpc/powerpc-accton-as5710-54x/platform-config/r0/src/lib/powerpc-accton-as5710-54x-r0.yml @@ -19,6 +19,12 @@ powerpc-accton-as5710-54x-r0: device: /dev/sda nos_bootcmds: *usb_bootcmds + environment: + - device: /dev/mtd6 + env_offset: 0x00000000 + env_size: 0x00002000 + sector_size: 0x00020000 + installer: - ONL-BOOT: =: 128MiB @@ -33,3 +39,9 @@ powerpc-accton-as5710-54x-r0: - ONL-DATA: =: 100% format: ext4 + + network: + interfaces: + ma1: + name: ~ + syspath: fsl,dpaa.16/ethernet.17 diff --git a/packages/platforms/accton/powerpc/powerpc-accton-as5710-54x/platform-config/r0b/src/lib/powerpc-accton-as5710-54x-r0b.yml b/packages/platforms/accton/powerpc/powerpc-accton-as5710-54x/platform-config/r0b/src/lib/powerpc-accton-as5710-54x-r0b.yml index 72b71b5d..ca2a066c 100644 --- a/packages/platforms/accton/powerpc/powerpc-accton-as5710-54x/platform-config/r0b/src/lib/powerpc-accton-as5710-54x-r0b.yml +++ b/packages/platforms/accton/powerpc/powerpc-accton-as5710-54x/platform-config/r0b/src/lib/powerpc-accton-as5710-54x-r0b.yml @@ -15,7 +15,18 @@ powerpc-accton-as5710-54x-r0b: =: powerpc-accton-as5710-54x-r0b.dtb <<: *e500mc-kernel-package + environment: + - device: /dev/mtd6 + env_offset: 0x00000000 + env_size: 0x00002000 + sector_size: 0x00020000 + loader: device: /dev/sda nos_bootcmds: *usb_bootcmds + network: + interfaces: + ma1: + name: ~ + syspath: fsl,dpaa.16/ethernet.17 diff --git a/packages/platforms/accton/powerpc/powerpc-accton-as6700-32x/platform-config/r0/src/lib/powerpc-accton-as6700-32x-r0.yml b/packages/platforms/accton/powerpc/powerpc-accton-as6700-32x/platform-config/r0/src/lib/powerpc-accton-as6700-32x-r0.yml index 58f15076..570843ec 100644 --- a/packages/platforms/accton/powerpc/powerpc-accton-as6700-32x/platform-config/r0/src/lib/powerpc-accton-as6700-32x-r0.yml +++ b/packages/platforms/accton/powerpc/powerpc-accton-as6700-32x/platform-config/r0/src/lib/powerpc-accton-as6700-32x-r0.yml @@ -20,6 +20,12 @@ powerpc-accton-as6700-32x-r0: ##partition: /dev/sda1 nos_bootcmds: *usb_bootcmds + environment: + - device: /dev/mtd1 + env_offset: 0x00000000 + env_size: 0x00002000 + sector_size: 0x00010000 + installer: - ONL-BOOT: =: 128MiB @@ -34,3 +40,8 @@ powerpc-accton-as6700-32x-r0: =: 100% format: ext4 + network: + interfaces: + ma1: + name: ~ + syspath: fsl,dpaa.16/ethernet.18 diff --git a/packages/platforms/accton/powerpc/powerpc-accton-as6700-32x/platform-config/r1/src/lib/powerpc-accton-as6700-32x-r1.yml b/packages/platforms/accton/powerpc/powerpc-accton-as6700-32x/platform-config/r1/src/lib/powerpc-accton-as6700-32x-r1.yml index f35a9391..f6d5c232 100644 --- a/packages/platforms/accton/powerpc/powerpc-accton-as6700-32x/platform-config/r1/src/lib/powerpc-accton-as6700-32x-r1.yml +++ b/packages/platforms/accton/powerpc/powerpc-accton-as6700-32x/platform-config/r1/src/lib/powerpc-accton-as6700-32x-r1.yml @@ -20,6 +20,12 @@ powerpc-accton-as6700-32x-r1: ##partition: /dev/sda1 nos_bootcmds: *usb_bootcmds + environment: + - device: /dev/mtd1 + env_offset: 0x00000000 + env_size: 0x00002000 + sector_size: 0x00040000 + installer: - ONL-BOOT: =: 128MiB @@ -34,3 +40,8 @@ powerpc-accton-as6700-32x-r1: =: 100% format: ext4 + network: + interfaces: + ma1: + name: ~ + syspath: fsl,dpaa.16/ethernet.18 diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as5712-54x/platform-config/r0/src/lib/x86-64-accton-as5712-54x-r0.yml b/packages/platforms/accton/x86-64/x86-64-accton-as5712-54x/platform-config/r0/src/lib/x86-64-accton-as5712-54x-r0.yml index 7820c773..29ce9bef 100644 --- a/packages/platforms/accton/x86-64/x86-64-accton-as5712-54x/platform-config/r0/src/lib/x86-64-accton-as5712-54x-r0.yml +++ b/packages/platforms/accton/x86-64/x86-64-accton-as5712-54x/platform-config/r0/src/lib/x86-64-accton-as5712-54x-r0.yml @@ -24,4 +24,8 @@ x86-64-accton-as5712-54x-r0: nopat console=ttyS1,115200n8 - \ No newline at end of file + network + interfaces: + ma1: + name: ~ + syspath: pci0000:00/0000:00:14.0 diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as5812-54t/platform-config/r0/src/lib/x86-64-accton-as5812-54t-r0.yml b/packages/platforms/accton/x86-64/x86-64-accton-as5812-54t/platform-config/r0/src/lib/x86-64-accton-as5812-54t-r0.yml index 35fdeeda..4bfc8909 100644 --- a/packages/platforms/accton/x86-64/x86-64-accton-as5812-54t/platform-config/r0/src/lib/x86-64-accton-as5812-54t-r0.yml +++ b/packages/platforms/accton/x86-64/x86-64-accton-as5812-54t/platform-config/r0/src/lib/x86-64-accton-as5812-54t-r0.yml @@ -23,3 +23,9 @@ x86-64-accton-as5812-54t-r0: args: >- nopat console=ttyS1,115200n8 + + network + interfaces: + ma1: + name: ~ + syspath: pci0000:00/0000:00:14.0 diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as5812-54x/platform-config/r0/src/lib/x86-64-accton-as5812-54x-r0.yml b/packages/platforms/accton/x86-64/x86-64-accton-as5812-54x/platform-config/r0/src/lib/x86-64-accton-as5812-54x-r0.yml index b9f49b96..23aa9df0 100644 --- a/packages/platforms/accton/x86-64/x86-64-accton-as5812-54x/platform-config/r0/src/lib/x86-64-accton-as5812-54x-r0.yml +++ b/packages/platforms/accton/x86-64/x86-64-accton-as5812-54x/platform-config/r0/src/lib/x86-64-accton-as5812-54x-r0.yml @@ -21,3 +21,9 @@ x86-64-accton-as5812-54x-r0: args: >- nopat console=ttyS1,115200n8 + + network + interfaces: + ma1: + name: ~ + syspath: pci0000:00/0000:00:14.0 diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as6712-32x/platform-config/r0/src/lib/x86-64-accton-as6712-32x-r0.yml b/packages/platforms/accton/x86-64/x86-64-accton-as6712-32x/platform-config/r0/src/lib/x86-64-accton-as6712-32x-r0.yml index e6274083..7d358255 100644 --- a/packages/platforms/accton/x86-64/x86-64-accton-as6712-32x/platform-config/r0/src/lib/x86-64-accton-as6712-32x-r0.yml +++ b/packages/platforms/accton/x86-64/x86-64-accton-as6712-32x/platform-config/r0/src/lib/x86-64-accton-as6712-32x-r0.yml @@ -23,3 +23,9 @@ x86-64-accton-as6712-32x-r0: args: >- nopat console=ttyS1,115200n8 + + network + interfaces: + ma1: + name: ~ + syspath: pci0000:00/0000:00:14.0 diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as6812-32x/platform-config/r0/src/lib/x86-64-accton-as6812-32x-r0.yml b/packages/platforms/accton/x86-64/x86-64-accton-as6812-32x/platform-config/r0/src/lib/x86-64-accton-as6812-32x-r0.yml index 6a6c75d0..3eccc8bf 100644 --- a/packages/platforms/accton/x86-64/x86-64-accton-as6812-32x/platform-config/r0/src/lib/x86-64-accton-as6812-32x-r0.yml +++ b/packages/platforms/accton/x86-64/x86-64-accton-as6812-32x/platform-config/r0/src/lib/x86-64-accton-as6812-32x-r0.yml @@ -24,3 +24,8 @@ x86-64-accton-as6812-32x-r0: nopat console=ttyS1,115200n8 + network + interfaces: + ma1: + name: ~ + syspath: pci0000:00/0000:00:14.0 diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as7512-32x/platform-config/r0/src/lib/x86-64-accton-as7512-32x-r0.yml b/packages/platforms/accton/x86-64/x86-64-accton-as7512-32x/platform-config/r0/src/lib/x86-64-accton-as7512-32x-r0.yml index 2c83eb0d..319e4db2 100644 --- a/packages/platforms/accton/x86-64/x86-64-accton-as7512-32x/platform-config/r0/src/lib/x86-64-accton-as7512-32x-r0.yml +++ b/packages/platforms/accton/x86-64/x86-64-accton-as7512-32x/platform-config/r0/src/lib/x86-64-accton-as7512-32x-r0.yml @@ -23,3 +23,9 @@ x86-64-accton-as5712-32x-r0: args: >- nopat console=ttyS1,115200n8 + + network + interfaces: + ma1: + name: ~ + syspath: pci0000:00/0000:00:14.0 diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as7712-32x/platform-config/r0/src/lib/x86-64-accton-as7712-32x-r0.yml b/packages/platforms/accton/x86-64/x86-64-accton-as7712-32x/platform-config/r0/src/lib/x86-64-accton-as7712-32x-r0.yml index 9630c73f..83e1d05d 100644 --- a/packages/platforms/accton/x86-64/x86-64-accton-as7712-32x/platform-config/r0/src/lib/x86-64-accton-as7712-32x-r0.yml +++ b/packages/platforms/accton/x86-64/x86-64-accton-as7712-32x/platform-config/r0/src/lib/x86-64-accton-as7712-32x-r0.yml @@ -23,3 +23,9 @@ x86-64-accton-as7712-32x-r0: args: >- nopat console=ttyS1,115200n8 + + network + interfaces: + ma1: + name: ~ + syspath: pci0000:00/0000:00:14.0 diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as7716-32x/platform-config/r0/src/lib/x86-64-accton-as7716-32x-r0.yml b/packages/platforms/accton/x86-64/x86-64-accton-as7716-32x/platform-config/r0/src/lib/x86-64-accton-as7716-32x-r0.yml index c528084b..f88f0e06 100644 --- a/packages/platforms/accton/x86-64/x86-64-accton-as7716-32x/platform-config/r0/src/lib/x86-64-accton-as7716-32x-r0.yml +++ b/packages/platforms/accton/x86-64/x86-64-accton-as7716-32x/platform-config/r0/src/lib/x86-64-accton-as7716-32x-r0.yml @@ -23,3 +23,9 @@ x86-64-accton-as7716-32x-r0: args: >- nopat console=ttyS0,115200n8 + + ##network: + ## interfaces: + ## ma1: + ## name: ~ + ## syspath: pci0000:00/0000:00:1c.0/0000:0a:00.0 diff --git a/packages/platforms/accton/x86-64/x86-64-accton-wedge-16x/platform-config/r0/src/lib/x86-64-accton-wedge-16x-r0.yml b/packages/platforms/accton/x86-64/x86-64-accton-wedge-16x/platform-config/r0/src/lib/x86-64-accton-wedge-16x-r0.yml index bc55cd86..dc009fbb 100644 --- a/packages/platforms/accton/x86-64/x86-64-accton-wedge-16x/platform-config/r0/src/lib/x86-64-accton-wedge-16x-r0.yml +++ b/packages/platforms/accton/x86-64/x86-64-accton-wedge-16x/platform-config/r0/src/lib/x86-64-accton-wedge-16x-r0.yml @@ -26,3 +26,9 @@ x86-64-accton-wedge-16x-r0: rd_NO_MD rd_NO_LUKS intel_iommu=off + + network + interfaces: + ma1: + name: ~ + syspath: pci0000:00/0000:00:14.0 diff --git a/packages/platforms/celestica/x86-64/x86-64-cel-redstone-xp/platform-config/r0/src/lib/x86-64-cel-redstone-xp-r0.yml b/packages/platforms/celestica/x86-64/x86-64-cel-redstone-xp/platform-config/r0/src/lib/x86-64-cel-redstone-xp-r0.yml index 69652363..b3efd7ec 100644 --- a/packages/platforms/celestica/x86-64/x86-64-cel-redstone-xp/platform-config/r0/src/lib/x86-64-cel-redstone-xp-r0.yml +++ b/packages/platforms/celestica/x86-64/x86-64-cel-redstone-xp/platform-config/r0/src/lib/x86-64-cel-redstone-xp-r0.yml @@ -23,3 +23,9 @@ x86-64-cel-redstone-xp-r0: args: >- nopat console=ttyS0,115200n8 + + network: + interfaces: + ma1: + name: ~ + syspath: pci0000:00/0000:00:14.0 diff --git a/packages/platforms/kvm/x86-64/x86-64-kvm-x86-64/platform-config/r0/src/lib/x86-64-kvm-x86-64-r0.yml b/packages/platforms/kvm/x86-64/x86-64-kvm-x86-64/platform-config/r0/src/lib/x86-64-kvm-x86-64-r0.yml index 83133bce..9f7a641c 100644 --- a/packages/platforms/kvm/x86-64/x86-64-kvm-x86-64/platform-config/r0/src/lib/x86-64-kvm-x86-64-r0.yml +++ b/packages/platforms/kvm/x86-64/x86-64-kvm-x86-64/platform-config/r0/src/lib/x86-64-kvm-x86-64-r0.yml @@ -23,4 +23,9 @@ x86-64-kvm-x86-64-r0: args: >- nopat console=ttyS0,115200n8 - \ No newline at end of file + + network + interfaces: + ma1: + name: ~ + syspath: pci0000:00/0000:00:03.0 diff --git a/packages/platforms/qemu/arm/arm-qemu-armv7a/platform-config/r0/src/lib/arm-qemu-armv7a-r0.yml b/packages/platforms/qemu/arm/arm-qemu-armv7a/platform-config/r0/src/lib/arm-qemu-armv7a-r0.yml index dd31aaad..0620cb71 100644 --- a/packages/platforms/qemu/arm/arm-qemu-armv7a/platform-config/r0/src/lib/arm-qemu-armv7a-r0.yml +++ b/packages/platforms/qemu/arm/arm-qemu-armv7a/platform-config/r0/src/lib/arm-qemu-armv7a-r0.yml @@ -16,3 +16,11 @@ arm-qemu-armv7a-r0: <<: *arm-iproc-kernel-package itb: <<: *arm-itb + + loader: + + environment: + - device: /dev/mtd1 + env_offset: 0x00000000 + env_size: 0x00002000 + sector_size: 0x00040000 diff --git a/packages/platforms/quanta/powerpc/powerpc-quanta-lb9/platform-config/r0/src/lib/powerpc-quanta-lb9-r0.yml b/packages/platforms/quanta/powerpc/powerpc-quanta-lb9/platform-config/r0/src/lib/powerpc-quanta-lb9-r0.yml index e21363f2..170b83a9 100644 --- a/packages/platforms/quanta/powerpc/powerpc-quanta-lb9/platform-config/r0/src/lib/powerpc-quanta-lb9-r0.yml +++ b/packages/platforms/quanta/powerpc/powerpc-quanta-lb9/platform-config/r0/src/lib/powerpc-quanta-lb9-r0.yml @@ -19,3 +19,15 @@ powerpc-quanta-lb9-r0: loader: device: /dev/sda nos_bootcmds: *ide_bootcmds + + environment: + - device: /dev/mtd3 + env_offset: 0x00000000 + env_size: 0x00002000 + sector_size: 0x00020000 + + network: + interfaces: + ma1: + name: ~ + syspath: e0000000.soc8541/e0024000.ethernet diff --git a/packages/platforms/quanta/powerpc/powerpc-quanta-ly2/platform-config/r0/src/lib/powerpc-quanta-ly2-r0.yml b/packages/platforms/quanta/powerpc/powerpc-quanta-ly2/platform-config/r0/src/lib/powerpc-quanta-ly2-r0.yml index 80af8e38..29626424 100644 --- a/packages/platforms/quanta/powerpc/powerpc-quanta-ly2/platform-config/r0/src/lib/powerpc-quanta-ly2-r0.yml +++ b/packages/platforms/quanta/powerpc/powerpc-quanta-ly2/platform-config/r0/src/lib/powerpc-quanta-ly2-r0.yml @@ -19,3 +19,15 @@ powerpc-quanta-ly2-r0: device: /dev/mmcblk0 ##partition: /dev/mmcblk0p1 nos_bootcmds: *mmc_bootcmds + + environment: + - device: /dev/mtd2 + env_offset: 0x00000000 + env_size: 0x00002000 + sector_size: 0x00020000 + + network + interfaces: + ma1: + name: ~ + syspath: soc.0/ffe24000.ethernet diff --git a/packages/platforms/quanta/x86-64/x86-64-quanta-ly6-rangeley/platform-config/r0/src/lib/x86-64-quanta-ly6-rangeley-r0.yml b/packages/platforms/quanta/x86-64/x86-64-quanta-ly6-rangeley/platform-config/r0/src/lib/x86-64-quanta-ly6-rangeley-r0.yml index cf0815d2..ecd6b139 100644 --- a/packages/platforms/quanta/x86-64/x86-64-quanta-ly6-rangeley/platform-config/r0/src/lib/x86-64-quanta-ly6-rangeley-r0.yml +++ b/packages/platforms/quanta/x86-64/x86-64-quanta-ly6-rangeley/platform-config/r0/src/lib/x86-64-quanta-ly6-rangeley-r0.yml @@ -22,4 +22,9 @@ x86-64-quanta-ly6-rangeley-r0: args: >- console=ttyS1,115200n8 - \ No newline at end of file + + network: + interfaces: + ma1: + name: ~ + syspath: pci0000:00/0000:00:14.0 diff --git a/packages/platforms/quanta/x86-64/x86-64-quanta-ly8-rangeley/platform-config/r0/src/lib/x86-64-quanta-ly8-rangeley-r0.yml b/packages/platforms/quanta/x86-64/x86-64-quanta-ly8-rangeley/platform-config/r0/src/lib/x86-64-quanta-ly8-rangeley-r0.yml index 2fa1247a..24bd1298 100644 --- a/packages/platforms/quanta/x86-64/x86-64-quanta-ly8-rangeley/platform-config/r0/src/lib/x86-64-quanta-ly8-rangeley-r0.yml +++ b/packages/platforms/quanta/x86-64/x86-64-quanta-ly8-rangeley/platform-config/r0/src/lib/x86-64-quanta-ly8-rangeley-r0.yml @@ -22,4 +22,9 @@ x86-64-quanta-ly8-rangeley-r0: args: >- console=ttyS1,115200n8 - \ No newline at end of file + + network: + interfaces: + ma1: + name: ~ + syspath: pci0000:00/0000:00:14.0 From 5624b49d506099ef2c9f70fd4cc7d4f422a23571 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Tue, 17 May 2016 19:26:01 -0700 Subject: [PATCH 072/113] Deprecate /etc/onl/net, /etc/onl/mounts, /etc/fw_env.config --- .../r0/src/lib/boot/arm-accton-as4610-54-r0 | 10 +++++----- .../r0/src/lib/boot/powerpc-accton-as4600-54t-r0 | 7 ------- .../r0/src/lib/boot/powerpc-accton-as5610-52x-r0 | 7 ------- .../r0/src/lib/boot/powerpc-accton-as5710-54x-r0 | 7 ------- .../src/lib/boot/powerpc-accton-as5710-54x-r0b | 7 ------- .../r0/src/lib/boot/powerpc-accton-as6700-32x-r0 | 10 ---------- .../r1/src/lib/boot/powerpc-accton-as6700-32x-r1 | 7 ------- .../r0/src/lib/boot/x86-64-accton-as5512-54x-r0 | 8 ++++++++ .../r0/src/lib/boot/x86-64-accton-as5712-54x-r0 | 9 +++++---- .../r0/src/lib/boot/x86-64-accton-as5812-54t-r0 | 9 +++++---- .../r0/src/lib/boot/x86-64-accton-as5812-54x-r0 | 9 +++++---- .../r0/src/lib/boot/x86-64-accton-as6712-32x-r0 | 3 --- .../r0/src/lib/boot/x86-64-accton-as6812-32x-r0 | 9 +++++---- .../r0/src/lib/boot/x86-64-accton-as7512-32x-r0 | 10 +++++----- .../r0/src/lib/boot/x86-64-accton-as7712-32x-r0 | 10 +++++----- .../r0/src/lib/boot/x86-64-accton-as7716-32x-r0 | 11 +++++------ .../r0/src/lib/boot/x86-64-accton-wedge-16x-r0 | 10 +++++----- .../r0/src/lib/boot/x86-64-cel-redstone-xp-r0 | 9 +++++---- .../r0/src/lib/boot/x86-64-kvm-x86-64-r0 | 15 +++++---------- .../r0/src/lib/boot/arm-qemu-armv7a-r0 | 13 +++++-------- .../r0/src/lib/boot/powerpc-quanta-lb9-r0 | 7 ------- .../r0/src/lib/boot/powerpc-quanta-ly2-r0 | 7 ------- .../r0/src/lib/boot/x86-64-quanta-ly6-rangeley-r0 | 8 +++++--- .../r0/src/lib/boot/x86-64-quanta-ly8-rangeley-r0 | 8 +++++--- 24 files changed, 78 insertions(+), 132 deletions(-) diff --git a/packages/platforms/accton/armel/arm-accton-as4610-54/platform-config/r0/src/lib/boot/arm-accton-as4610-54-r0 b/packages/platforms/accton/armel/arm-accton-as4610-54/platform-config/r0/src/lib/boot/arm-accton-as4610-54-r0 index 1edfdf27..f00ff42d 100644 --- a/packages/platforms/accton/armel/arm-accton-as4610-54/platform-config/r0/src/lib/boot/arm-accton-as4610-54-r0 +++ b/packages/platforms/accton/armel/arm-accton-as4610-54/platform-config/r0/src/lib/boot/arm-accton-as4610-54-r0 @@ -1,6 +1,6 @@ -ip link set dev eth0 name ma1 -echo "block/sda sda2 flash" > /etc/onl/mounts -echo "block/sda sda3 flash2" >> /etc/onl/mounts +############################## +# +# arm-accton-as4610-54-r0 +# +############################## -echo "# MTD device name Device offset Env. size Flash sector size" > /etc/fw_env.config -echo "/dev/mtd2 0x00000000 0x00002000 0x00010000" >> /etc/fw_env.config diff --git a/packages/platforms/accton/powerpc/powerpc-accton-as4600-54t/platform-config/r0/src/lib/boot/powerpc-accton-as4600-54t-r0 b/packages/platforms/accton/powerpc/powerpc-accton-as4600-54t/platform-config/r0/src/lib/boot/powerpc-accton-as4600-54t-r0 index 395fe8e9..e569ba60 100644 --- a/packages/platforms/accton/powerpc/powerpc-accton-as4600-54t/platform-config/r0/src/lib/boot/powerpc-accton-as4600-54t-r0 +++ b/packages/platforms/accton/powerpc/powerpc-accton-as4600-54t/platform-config/r0/src/lib/boot/powerpc-accton-as4600-54t-r0 @@ -2,10 +2,3 @@ # powerpc-accton-as4600-54t-r0 ############################################################ -echo "soc.0/ff725000.ethernet ma1" > /etc/onl/net -echo "block/sda sda2 flash" > /etc/onl/mounts -echo "block/sda sda3 flash2" >> /etc/onl/mounts - -echo "# MTD device name Device offset Env. size Flash sector size" >> /etc/fw_env.config -echo "/dev/mtd2 0x00000000 0x00010000 0x00010000" >> /etc/fw_env.config - diff --git a/packages/platforms/accton/powerpc/powerpc-accton-as5610-52x/platform-config/r0/src/lib/boot/powerpc-accton-as5610-52x-r0 b/packages/platforms/accton/powerpc/powerpc-accton-as5610-52x/platform-config/r0/src/lib/boot/powerpc-accton-as5610-52x-r0 index a17562d0..6601b373 100644 --- a/packages/platforms/accton/powerpc/powerpc-accton-as5610-52x/platform-config/r0/src/lib/boot/powerpc-accton-as5610-52x-r0 +++ b/packages/platforms/accton/powerpc/powerpc-accton-as5610-52x/platform-config/r0/src/lib/boot/powerpc-accton-as5610-52x-r0 @@ -1,10 +1,3 @@ ############################################################ # powerpc-accton-as5610-52x-r0 ############################################################ - -echo "soc.0/ff724000.ethernet ma1" >/etc/onl/net -echo "block/sda sda2 flash" > /etc/onl/mounts -echo "block/sda sda3 flash2" >> /etc/onl/mounts - -echo "# MTD device name Device offset Env. size Flash sector size" > /etc/fw_env.config -echo "/dev/mtd1 0x00000000 0x00010000 0x00010000" >> /etc/fw_env.config \ No newline at end of file diff --git a/packages/platforms/accton/powerpc/powerpc-accton-as5710-54x/platform-config/r0/src/lib/boot/powerpc-accton-as5710-54x-r0 b/packages/platforms/accton/powerpc/powerpc-accton-as5710-54x/platform-config/r0/src/lib/boot/powerpc-accton-as5710-54x-r0 index 47478956..c4f271d3 100644 --- a/packages/platforms/accton/powerpc/powerpc-accton-as5710-54x/platform-config/r0/src/lib/boot/powerpc-accton-as5710-54x-r0 +++ b/packages/platforms/accton/powerpc/powerpc-accton-as5710-54x/platform-config/r0/src/lib/boot/powerpc-accton-as5710-54x-r0 @@ -2,12 +2,5 @@ # powerpc-accton-as5710-54x-r0 ############################################################ -echo "fsl,dpaa.16/ethernet.17 ma1" > /etc/onl/net -echo "block/sda sda2 flash" > /etc/onl/mounts -echo "block/sda sda3 flash2" >> /etc/onl/mounts - -echo "# MTD device name Device offset Env. size Flash sector size" > /etc/fw_env.config -echo "/dev/mtd6 0x00000000 0x00002000 0x00020000" >> /etc/fw_env.config - diff --git a/packages/platforms/accton/powerpc/powerpc-accton-as5710-54x/platform-config/r0b/src/lib/boot/powerpc-accton-as5710-54x-r0b b/packages/platforms/accton/powerpc/powerpc-accton-as5710-54x/platform-config/r0b/src/lib/boot/powerpc-accton-as5710-54x-r0b index 011e60f6..17e54a7d 100644 --- a/packages/platforms/accton/powerpc/powerpc-accton-as5710-54x/platform-config/r0b/src/lib/boot/powerpc-accton-as5710-54x-r0b +++ b/packages/platforms/accton/powerpc/powerpc-accton-as5710-54x/platform-config/r0b/src/lib/boot/powerpc-accton-as5710-54x-r0b @@ -2,12 +2,5 @@ # powerpc-accton-as5710-54x-r0b ############################################################ -echo "fsl,dpaa.16/ethernet.17 ma1" > /etc/onl/net -echo "block/sda sda2 flash" > /etc/onl/mounts -echo "block/sda sda3 flash2" >> /etc/onl/mounts - -echo "# MTD device name Device offset Env. size Flash sector size" > /etc/fw_env.config -echo "/dev/mtd6 0x00000000 0x00002000 0x00020000" >> /etc/fw_env.config - diff --git a/packages/platforms/accton/powerpc/powerpc-accton-as6700-32x/platform-config/r0/src/lib/boot/powerpc-accton-as6700-32x-r0 b/packages/platforms/accton/powerpc/powerpc-accton-as6700-32x/platform-config/r0/src/lib/boot/powerpc-accton-as6700-32x-r0 index 942441bf..209a1851 100644 --- a/packages/platforms/accton/powerpc/powerpc-accton-as6700-32x/platform-config/r0/src/lib/boot/powerpc-accton-as6700-32x-r0 +++ b/packages/platforms/accton/powerpc/powerpc-accton-as6700-32x/platform-config/r0/src/lib/boot/powerpc-accton-as6700-32x-r0 @@ -2,16 +2,6 @@ # powerpc-accton-as6700-32x-r0 ############################################################ -echo "fsl,dpaa.16/ethernet.18 ma1" > /etc/onl/net -echo "# MTD device name Device offset Env. size Flash sector size" > /etc/fw_env.config -echo "/dev/mtd1 0x00000000 0x00002000 0x00010000" >> /etc/fw_env.config - -echo "block/sda sda2 flash" > /etc/onl/mounts -echo "block/sda sda3 flash2" >> /etc/onl/mounts - -# echo "block/mmcblk0 mmcblk0p2 flash" > /etc/onl/mounts -# echo "block/mmcblk0 mmcblk0p3 flash2" >> /etc/onl/mounts - diff --git a/packages/platforms/accton/powerpc/powerpc-accton-as6700-32x/platform-config/r1/src/lib/boot/powerpc-accton-as6700-32x-r1 b/packages/platforms/accton/powerpc/powerpc-accton-as6700-32x/platform-config/r1/src/lib/boot/powerpc-accton-as6700-32x-r1 index 1ded5bc5..f9325723 100644 --- a/packages/platforms/accton/powerpc/powerpc-accton-as6700-32x/platform-config/r1/src/lib/boot/powerpc-accton-as6700-32x-r1 +++ b/packages/platforms/accton/powerpc/powerpc-accton-as6700-32x/platform-config/r1/src/lib/boot/powerpc-accton-as6700-32x-r1 @@ -2,13 +2,6 @@ # powerpc-accton-as6700-32x-r1 ############################################################ -echo "fsl,dpaa.16/ethernet.18 ma1" > /etc/onl/net -echo "block/sda sda2 flash" > /etc/onl/mounts -echo "block/sda sda3 flash2" >> /etc/onl/mounts - -echo "# MTD device name Device offset Env. size Flash sector size" > /etc/fw_env.config -echo "/dev/mtd1 0x00000000 0x00002000 0x00040000" >> /etc/fw_env.config - diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as5512-54x/platform-config/r0/src/lib/boot/x86-64-accton-as5512-54x-r0 b/packages/platforms/accton/x86-64/x86-64-accton-as5512-54x/platform-config/r0/src/lib/boot/x86-64-accton-as5512-54x-r0 index 1d035c23..bbeeded1 100644 --- a/packages/platforms/accton/x86-64/x86-64-accton-as5512-54x/platform-config/r0/src/lib/boot/x86-64-accton-as5512-54x-r0 +++ b/packages/platforms/accton/x86-64/x86-64-accton-as5512-54x/platform-config/r0/src/lib/boot/x86-64-accton-as5512-54x-r0 @@ -1,3 +1,11 @@ +############################## +# +# x86-64-accton-as5512-54x-r0 +# +# XXX missing YML platform config +# +############################## + echo "pci0000:00/0000:00:14.0 ma1" >/etc/onl/net echo "LABEL=FLASH * flash" > /etc/onl/mounts diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as5712-54x/platform-config/r0/src/lib/boot/x86-64-accton-as5712-54x-r0 b/packages/platforms/accton/x86-64/x86-64-accton-as5712-54x/platform-config/r0/src/lib/boot/x86-64-accton-as5712-54x-r0 index 1d035c23..e476f767 100644 --- a/packages/platforms/accton/x86-64/x86-64-accton-as5712-54x/platform-config/r0/src/lib/boot/x86-64-accton-as5712-54x-r0 +++ b/packages/platforms/accton/x86-64/x86-64-accton-as5712-54x/platform-config/r0/src/lib/boot/x86-64-accton-as5712-54x-r0 @@ -1,7 +1,8 @@ -echo "pci0000:00/0000:00:14.0 ma1" >/etc/onl/net - -echo "LABEL=FLASH * flash" > /etc/onl/mounts -echo "LABEL=FLASH2 * flash2" >> /etc/onl/mounts +############################## +# +# x86-64-accton-as5712-54x-r0 +# +############################## diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as5812-54t/platform-config/r0/src/lib/boot/x86-64-accton-as5812-54t-r0 b/packages/platforms/accton/x86-64/x86-64-accton-as5812-54t/platform-config/r0/src/lib/boot/x86-64-accton-as5812-54t-r0 index 1d035c23..1675e4b5 100644 --- a/packages/platforms/accton/x86-64/x86-64-accton-as5812-54t/platform-config/r0/src/lib/boot/x86-64-accton-as5812-54t-r0 +++ b/packages/platforms/accton/x86-64/x86-64-accton-as5812-54t/platform-config/r0/src/lib/boot/x86-64-accton-as5812-54t-r0 @@ -1,7 +1,8 @@ -echo "pci0000:00/0000:00:14.0 ma1" >/etc/onl/net - -echo "LABEL=FLASH * flash" > /etc/onl/mounts -echo "LABEL=FLASH2 * flash2" >> /etc/onl/mounts +############################## +# +# x86-64-accton-as5812-54t-r0 +# +############################## diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as5812-54x/platform-config/r0/src/lib/boot/x86-64-accton-as5812-54x-r0 b/packages/platforms/accton/x86-64/x86-64-accton-as5812-54x/platform-config/r0/src/lib/boot/x86-64-accton-as5812-54x-r0 index 1d035c23..746de4fb 100644 --- a/packages/platforms/accton/x86-64/x86-64-accton-as5812-54x/platform-config/r0/src/lib/boot/x86-64-accton-as5812-54x-r0 +++ b/packages/platforms/accton/x86-64/x86-64-accton-as5812-54x/platform-config/r0/src/lib/boot/x86-64-accton-as5812-54x-r0 @@ -1,7 +1,8 @@ -echo "pci0000:00/0000:00:14.0 ma1" >/etc/onl/net - -echo "LABEL=FLASH * flash" > /etc/onl/mounts -echo "LABEL=FLASH2 * flash2" >> /etc/onl/mounts +############################## +# +# x86-64-accton-as5812-54x-r0 +# +############################## diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as6712-32x/platform-config/r0/src/lib/boot/x86-64-accton-as6712-32x-r0 b/packages/platforms/accton/x86-64/x86-64-accton-as6712-32x/platform-config/r0/src/lib/boot/x86-64-accton-as6712-32x-r0 index a096ce1d..d84f6aab 100644 --- a/packages/platforms/accton/x86-64/x86-64-accton-as6712-32x/platform-config/r0/src/lib/boot/x86-64-accton-as6712-32x-r0 +++ b/packages/platforms/accton/x86-64/x86-64-accton-as6712-32x/platform-config/r0/src/lib/boot/x86-64-accton-as6712-32x-r0 @@ -3,9 +3,6 @@ # x86-64-accton-as6712-32x-r0 # ############################################################ -echo "pci0000:00/0000:00:14.0 ma1" >/etc/onl/net -echo "LABEL=FLASH * flash" > /etc/onl/mounts -echo "LABEL=FLASH2 * flash2" >> /etc/onl/mounts diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as6812-32x/platform-config/r0/src/lib/boot/x86-64-accton-as6812-32x-r0 b/packages/platforms/accton/x86-64/x86-64-accton-as6812-32x/platform-config/r0/src/lib/boot/x86-64-accton-as6812-32x-r0 index b5f75d44..90ddefcb 100644 --- a/packages/platforms/accton/x86-64/x86-64-accton-as6812-32x/platform-config/r0/src/lib/boot/x86-64-accton-as6812-32x-r0 +++ b/packages/platforms/accton/x86-64/x86-64-accton-as6812-32x/platform-config/r0/src/lib/boot/x86-64-accton-as6812-32x-r0 @@ -1,6 +1,7 @@ -echo "pci0000:00/0000:00:14.0 ma1" >/etc/onl/net - -echo "LABEL=FLASH * flash" >> /etc/onl/mounts -echo "LABEL=FLASH2 * flash2" >> /etc/onl/mounts +############################## +# +# x86-64-accton-as6812-32x-r0 +# +############################## diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as7512-32x/platform-config/r0/src/lib/boot/x86-64-accton-as7512-32x-r0 b/packages/platforms/accton/x86-64/x86-64-accton-as7512-32x/platform-config/r0/src/lib/boot/x86-64-accton-as7512-32x-r0 index f01ffc67..8e758e9a 100644 --- a/packages/platforms/accton/x86-64/x86-64-accton-as7512-32x/platform-config/r0/src/lib/boot/x86-64-accton-as7512-32x-r0 +++ b/packages/platforms/accton/x86-64/x86-64-accton-as7512-32x/platform-config/r0/src/lib/boot/x86-64-accton-as7512-32x-r0 @@ -1,5 +1,5 @@ -echo "pci0000:00/0000:00:14.0 ma1" >/etc/onl/net - -cp /dev/null /etc/onl/mounts -echo "LABEL=FLASH * flash" >> /etc/onl/mounts -echo "LABEL=FLASH2 * flash2" >> /etc/onl/mounts +############################## +# +# x86-64-accton-as7512-32x-r0 +# +############################## diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as7712-32x/platform-config/r0/src/lib/boot/x86-64-accton-as7712-32x-r0 b/packages/platforms/accton/x86-64/x86-64-accton-as7712-32x/platform-config/r0/src/lib/boot/x86-64-accton-as7712-32x-r0 index f01ffc67..90c3d11f 100644 --- a/packages/platforms/accton/x86-64/x86-64-accton-as7712-32x/platform-config/r0/src/lib/boot/x86-64-accton-as7712-32x-r0 +++ b/packages/platforms/accton/x86-64/x86-64-accton-as7712-32x/platform-config/r0/src/lib/boot/x86-64-accton-as7712-32x-r0 @@ -1,5 +1,5 @@ -echo "pci0000:00/0000:00:14.0 ma1" >/etc/onl/net - -cp /dev/null /etc/onl/mounts -echo "LABEL=FLASH * flash" >> /etc/onl/mounts -echo "LABEL=FLASH2 * flash2" >> /etc/onl/mounts +############################## +# +# x86-64-accton-as7712-32x-r0 +# +############################## diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as7716-32x/platform-config/r0/src/lib/boot/x86-64-accton-as7716-32x-r0 b/packages/platforms/accton/x86-64/x86-64-accton-as7716-32x/platform-config/r0/src/lib/boot/x86-64-accton-as7716-32x-r0 index cd87988e..7231a049 100644 --- a/packages/platforms/accton/x86-64/x86-64-accton-as7716-32x/platform-config/r0/src/lib/boot/x86-64-accton-as7716-32x-r0 +++ b/packages/platforms/accton/x86-64/x86-64-accton-as7716-32x/platform-config/r0/src/lib/boot/x86-64-accton-as7716-32x-r0 @@ -1,6 +1,5 @@ -#echo "pci0000:00/0000:00:1c.0/0000:0a:00.0" > /etc/onl/net -ip link set dev eth0 name ma1 - -cp /dev/null /etc/onl/mounts -echo "LABEL=FLASH * flash" >> /etc/onl/mounts -echo "LABEL=FLASH2 * flash2" >> /etc/onl/mounts +############################## +# +# x86-64-accton-as7716-32x-r0 +# +############################## diff --git a/packages/platforms/accton/x86-64/x86-64-accton-wedge-16x/platform-config/r0/src/lib/boot/x86-64-accton-wedge-16x-r0 b/packages/platforms/accton/x86-64/x86-64-accton-wedge-16x/platform-config/r0/src/lib/boot/x86-64-accton-wedge-16x-r0 index 92132f72..b562e433 100644 --- a/packages/platforms/accton/x86-64/x86-64-accton-wedge-16x/platform-config/r0/src/lib/boot/x86-64-accton-wedge-16x-r0 +++ b/packages/platforms/accton/x86-64/x86-64-accton-wedge-16x/platform-config/r0/src/lib/boot/x86-64-accton-wedge-16x-r0 @@ -1,7 +1,7 @@ -echo "pci0000:00/0000:00:14.0 ma1" >/etc/onl/net - -cp /dev/null /etc/onl/mounts -echo "LABEL=FLASH * flash" >> /etc/onl/mounts -echo "LABEL=FLASH2 * flash2" >> /etc/onl/mounts +############################## +# +# x86-64-accton-wedge-16x-r0 +# +############################## diff --git a/packages/platforms/celestica/x86-64/x86-64-cel-redstone-xp/platform-config/r0/src/lib/boot/x86-64-cel-redstone-xp-r0 b/packages/platforms/celestica/x86-64/x86-64-cel-redstone-xp/platform-config/r0/src/lib/boot/x86-64-cel-redstone-xp-r0 index 72689103..09c12df9 100644 --- a/packages/platforms/celestica/x86-64/x86-64-cel-redstone-xp/platform-config/r0/src/lib/boot/x86-64-cel-redstone-xp-r0 +++ b/packages/platforms/celestica/x86-64/x86-64-cel-redstone-xp/platform-config/r0/src/lib/boot/x86-64-cel-redstone-xp-r0 @@ -1,6 +1,7 @@ -echo "pci0000:00/0000:00:14.0 ma1" > /etc/onl/net - -echo "LABEL=FLASH * flash" > /etc/onl/mounts -echo "LABEL=FLASH2 * flash2" >> /etc/onl/mounts +############################## +# +# x86-64-cel-redstone-xp-r0 +# +############################## diff --git a/packages/platforms/kvm/x86-64/x86-64-kvm-x86-64/platform-config/r0/src/lib/boot/x86-64-kvm-x86-64-r0 b/packages/platforms/kvm/x86-64/x86-64-kvm-x86-64/platform-config/r0/src/lib/boot/x86-64-kvm-x86-64-r0 index ae44e205..c869975b 100644 --- a/packages/platforms/kvm/x86-64/x86-64-kvm-x86-64/platform-config/r0/src/lib/boot/x86-64-kvm-x86-64-r0 +++ b/packages/platforms/kvm/x86-64/x86-64-kvm-x86-64/platform-config/r0/src/lib/boot/x86-64-kvm-x86-64-r0 @@ -1,11 +1,6 @@ -echo "pci0000:00/0000:00:03.0 ma1" >/etc/onl/net - -cp /dev/null /etc/onl/mounts -echo "block/sda sda flash" >> /etc/onl/mounts -echo "block/vda vda flash" >> /etc/onl/mounts -echo "LABEL=FLASH * flash" >> /etc/onl/mounts - -echo "block/sdb sdb flash2" >> /etc/onl/mounts -echo "block/vdb vdb flash2" >> /etc/onl/mounts -echo "LABEL=FLASH2 * flash2" >> /etc/onl/mounts +############################## +# +# x86-64-kvm-x86-64-r0 +# +############################## diff --git a/packages/platforms/qemu/arm/arm-qemu-armv7a/platform-config/r0/src/lib/boot/arm-qemu-armv7a-r0 b/packages/platforms/qemu/arm/arm-qemu-armv7a/platform-config/r0/src/lib/boot/arm-qemu-armv7a-r0 index a0ef10f3..05edaafd 100644 --- a/packages/platforms/qemu/arm/arm-qemu-armv7a/platform-config/r0/src/lib/boot/arm-qemu-armv7a-r0 +++ b/packages/platforms/qemu/arm/arm-qemu-armv7a/platform-config/r0/src/lib/boot/arm-qemu-armv7a-r0 @@ -1,8 +1,5 @@ -ip link set dev eth0 name ma1 - -cp /dev/null /etc/onl/mounts -echo "block/mmcblk0 mmcblk0p2 flash" > /etc/onl/mounts -echo "block/mmcblk0 mmcblk0p3 flash2" >> /etc/onl/mounts - -echo "# MTD device name Device offset Env. size Flash sector size" > /etc/fw_env.config -echo "/dev/mtd1 0x00000000 0x00002000 0x00040000" >> /etc/fw_env.config +############################## +# +# arm-qemu-armv7a-r0 +# +############################## diff --git a/packages/platforms/quanta/powerpc/powerpc-quanta-lb9/platform-config/r0/src/lib/boot/powerpc-quanta-lb9-r0 b/packages/platforms/quanta/powerpc/powerpc-quanta-lb9/platform-config/r0/src/lib/boot/powerpc-quanta-lb9-r0 index f8611386..93588a96 100644 --- a/packages/platforms/quanta/powerpc/powerpc-quanta-lb9/platform-config/r0/src/lib/boot/powerpc-quanta-lb9-r0 +++ b/packages/platforms/quanta/powerpc/powerpc-quanta-lb9/platform-config/r0/src/lib/boot/powerpc-quanta-lb9-r0 @@ -3,10 +3,3 @@ # powerpc-quanta-lb9-r0 # ############################################################ - -echo "e0000000.soc8541/e0024000.ethernet ma1" >/etc/onl/net -echo "block/sda sda2 flash" > /etc/onl/mounts -echo "block/sda sda3 flash2" >> /etc/onl/mounts - -echo "# MTD device name Device offset Env. size Flash sector size" > /etc/fw_env.config -echo "/dev/mtd3 0x00000000 0x00002000 0x00020000" >> /etc/fw_env.config diff --git a/packages/platforms/quanta/powerpc/powerpc-quanta-ly2/platform-config/r0/src/lib/boot/powerpc-quanta-ly2-r0 b/packages/platforms/quanta/powerpc/powerpc-quanta-ly2/platform-config/r0/src/lib/boot/powerpc-quanta-ly2-r0 index 4f0f57e7..4687f72c 100644 --- a/packages/platforms/quanta/powerpc/powerpc-quanta-ly2/platform-config/r0/src/lib/boot/powerpc-quanta-ly2-r0 +++ b/packages/platforms/quanta/powerpc/powerpc-quanta-ly2/platform-config/r0/src/lib/boot/powerpc-quanta-ly2-r0 @@ -23,10 +23,3 @@ # powerpc-quanta-ly2-r0 # ############################################################ - -echo "soc.0/ffe24000.ethernet ma1" >/etc/onl/net -echo "block/mmcblk0 mmcblk0p2 flash" > /etc/onl/mounts -echo "block/mmcblk0 mmcblk0p3 flash2" >> /etc/onl/mounts - -echo "# MTD device name Device offset Env. size Flash sector size" > /etc/fw_env.config -echo "/dev/mtd2 0x00000000 0x00002000 0x00020000" >> /etc/fw_env.config diff --git a/packages/platforms/quanta/x86-64/x86-64-quanta-ly6-rangeley/platform-config/r0/src/lib/boot/x86-64-quanta-ly6-rangeley-r0 b/packages/platforms/quanta/x86-64/x86-64-quanta-ly6-rangeley/platform-config/r0/src/lib/boot/x86-64-quanta-ly6-rangeley-r0 index 7c120d46..0cba156d 100644 --- a/packages/platforms/quanta/x86-64/x86-64-quanta-ly6-rangeley/platform-config/r0/src/lib/boot/x86-64-quanta-ly6-rangeley-r0 +++ b/packages/platforms/quanta/x86-64/x86-64-quanta-ly6-rangeley/platform-config/r0/src/lib/boot/x86-64-quanta-ly6-rangeley-r0 @@ -1,3 +1,5 @@ -echo "pci0000:00/0000:00:14.0 ma1" >/etc/onl/net -echo "LABEL=FLASH * flash" > /etc/onl/mounts -echo "LABEL=FLASH2 * flash2" >> /etc/onl/mounts +############################## +# +# x86-64-quanta-ly6-rangely-r0 +# +############################## diff --git a/packages/platforms/quanta/x86-64/x86-64-quanta-ly8-rangeley/platform-config/r0/src/lib/boot/x86-64-quanta-ly8-rangeley-r0 b/packages/platforms/quanta/x86-64/x86-64-quanta-ly8-rangeley/platform-config/r0/src/lib/boot/x86-64-quanta-ly8-rangeley-r0 index 39db2b55..385ab67e 100644 --- a/packages/platforms/quanta/x86-64/x86-64-quanta-ly8-rangeley/platform-config/r0/src/lib/boot/x86-64-quanta-ly8-rangeley-r0 +++ b/packages/platforms/quanta/x86-64/x86-64-quanta-ly8-rangeley/platform-config/r0/src/lib/boot/x86-64-quanta-ly8-rangeley-r0 @@ -1,4 +1,6 @@ -echo "pci0000:00/0000:00:14.0 ma1" >/etc/onl/net -echo "LABEL=FLASH * flash" > /etc/onl/mounts -echo "LABEL=FLASH2 * flash2" >> /etc/onl/mounts +############################## +# +# x86-64-quanta-ly8-rangely-r0 +# +############################## From bef2556d611143399b29bf2ee1537a50cbbd09db Mon Sep 17 00:00:00 2001 From: Jeffrey Townsend Date: Wed, 18 May 2016 18:08:53 +0000 Subject: [PATCH 073/113] Use ONLPM_OPTION_REPO as the base local repository. --- builds/any/rootfs/jessie/standard/standard.yml | 4 ++-- builds/any/rootfs/wheezy/standard/standard.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/builds/any/rootfs/jessie/standard/standard.yml b/builds/any/rootfs/jessie/standard/standard.yml index 4586c93f..7266fa7d 100644 --- a/builds/any/rootfs/jessie/standard/standard.yml +++ b/builds/any/rootfs/jessie/standard/standard.yml @@ -43,11 +43,11 @@ Multistrap: omitdebsrc: true Local-All: - source: ${ONL}/REPO/${ONL_DEBIAN_SUITE}/packages/binary-all + source: ${ONLPM_OPTION_REPO}/${ONL_DEBIAN_SUITE}/packages/binary-all omitdebsrc: true Local-Arch: - source: ${ONL}/REPO/${ONL_DEBIAN_SUITE}/packages/binary-${ARCH} + source: ${ONLPM_OPTION_REPO}/${ONL_DEBIAN_SUITE}/packages/binary-${ARCH} omitdebsrc: true Configure: diff --git a/builds/any/rootfs/wheezy/standard/standard.yml b/builds/any/rootfs/wheezy/standard/standard.yml index 2ec2902d..f7f04c32 100644 --- a/builds/any/rootfs/wheezy/standard/standard.yml +++ b/builds/any/rootfs/wheezy/standard/standard.yml @@ -43,11 +43,11 @@ Multistrap: omitdebsrc: true Local-All: - source: ${ONL}/REPO/${ONL_DEBIAN_SUITE}/packages/binary-all + source: ${ONLPM_OPTION_REPO}/${ONL_DEBIAN_SUITE}/packages/binary-all omitdebsrc: true Local-Arch: - source: ${ONL}/REPO/${ONL_DEBIAN_SUITE}/packages/binary-${ARCH} + source: ${ONLPM_OPTION_REPO}/${ONL_DEBIAN_SUITE}/packages/binary-${ARCH} omitdebsrc: true Configure: From f7965da994e1d5875b31958eb118a4e47ebef5cf Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Wed, 18 May 2016 12:39:35 -0700 Subject: [PATCH 074/113] Fixed broken config for AS5812 --- .../platform-config/r0/src/lib/x86-64-accton-as5812-54x-r0.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as5812-54x/platform-config/r0/src/lib/x86-64-accton-as5812-54x-r0.yml b/packages/platforms/accton/x86-64/x86-64-accton-as5812-54x/platform-config/r0/src/lib/x86-64-accton-as5812-54x-r0.yml index 23aa9df0..7e4f4230 100644 --- a/packages/platforms/accton/x86-64/x86-64-accton-as5812-54x/platform-config/r0/src/lib/x86-64-accton-as5812-54x-r0.yml +++ b/packages/platforms/accton/x86-64/x86-64-accton-as5812-54x/platform-config/r0/src/lib/x86-64-accton-as5812-54x-r0.yml @@ -8,6 +8,8 @@ x86-64-accton-as5812-54x-r0: + grub: + serial: >- --port=0x2f8 --speed=115200 From 8e1fd141c14f12ac3d40e26e92e8985813dbfb14 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Wed, 18 May 2016 12:39:53 -0700 Subject: [PATCH 075/113] Added proper YML config for AS5512 --- .../src/lib/boot/x86-64-accton-as5512-54x-r0 | 7 ----- .../src/lib/x86-64-accton-as5512-54x-r0.yml | 31 +++++++++++++++++++ 2 files changed, 31 insertions(+), 7 deletions(-) create mode 100644 packages/platforms/accton/x86-64/x86-64-accton-as5512-54x/platform-config/r0/src/lib/x86-64-accton-as5512-54x-r0.yml diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as5512-54x/platform-config/r0/src/lib/boot/x86-64-accton-as5512-54x-r0 b/packages/platforms/accton/x86-64/x86-64-accton-as5512-54x/platform-config/r0/src/lib/boot/x86-64-accton-as5512-54x-r0 index bbeeded1..98eccc32 100644 --- a/packages/platforms/accton/x86-64/x86-64-accton-as5512-54x/platform-config/r0/src/lib/boot/x86-64-accton-as5512-54x-r0 +++ b/packages/platforms/accton/x86-64/x86-64-accton-as5512-54x/platform-config/r0/src/lib/boot/x86-64-accton-as5512-54x-r0 @@ -2,14 +2,7 @@ # # x86-64-accton-as5512-54x-r0 # -# XXX missing YML platform config -# ############################## -echo "pci0000:00/0000:00:14.0 ma1" >/etc/onl/net - -echo "LABEL=FLASH * flash" > /etc/onl/mounts -echo "LABEL=FLASH2 * flash2" >> /etc/onl/mounts - diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as5512-54x/platform-config/r0/src/lib/x86-64-accton-as5512-54x-r0.yml b/packages/platforms/accton/x86-64/x86-64-accton-as5512-54x/platform-config/r0/src/lib/x86-64-accton-as5512-54x-r0.yml new file mode 100644 index 00000000..0cdb6fca --- /dev/null +++ b/packages/platforms/accton/x86-64/x86-64-accton-as5512-54x/platform-config/r0/src/lib/x86-64-accton-as5512-54x-r0.yml @@ -0,0 +1,31 @@ +--- + +###################################################################### +# +# platform-config for AS5512 +# +###################################################################### + +x86-64-accton-as5512-54x-r0: + + grub: + + serial: >- + --port=0x2f8 + --speed=115200 + --word=8 + --parity=no + --stop=1 + + kernel: + <<: *kernel-3-2 + + args: >- + nopat + console=ttyS1,115200n8 + + network + interfaces: + ma1: + name: ~ + syspath: pci0000:00/0000:00:14.0 From ea201e872955a2cfabeaa56658c2e803fdd0d08e Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Wed, 18 May 2016 12:51:46 -0700 Subject: [PATCH 076/113] Deprecated in favor of onl-vendor-config-onl versions --- .../loader-initrd-files/src/bin/initmounts | 275 ------------------ .../loader-initrd-files/src/bin/initnetdev | 52 ---- 2 files changed, 327 deletions(-) delete mode 100755 packages/base/all/initrds/loader-initrd-files/src/bin/initmounts delete mode 100755 packages/base/all/initrds/loader-initrd-files/src/bin/initnetdev diff --git a/packages/base/all/initrds/loader-initrd-files/src/bin/initmounts b/packages/base/all/initrds/loader-initrd-files/src/bin/initmounts deleted file mode 100755 index 6f4f0ff0..00000000 --- a/packages/base/all/initrds/loader-initrd-files/src/bin/initmounts +++ /dev/null @@ -1,275 +0,0 @@ -#!/bin/sh -############################################################ -# -# -# Copyright 2013, 2014 BigSwitch Networks, Inc. -# -# -# -# -############################################################ -# -# initmounts -# -# Mount all mount points listed in /etc/onl/mounts -# -# Each line in /etc/onl/mounts is in the following syntax: -# -# /dev/sda sda mount-point -# - wait for /dev/sda to appear, -# then mount /dev/sda as /mnt/mount-point -# -# /dev/sda * mount-point -# - wait for block device /dev/sda to appear, -# then mount /dev/sda as /mnt/mount-point -# (infer /dev/sda from the left-hand path specification) -# -# block/sda sda mount-point -# block/sda * mount-point -# SYSDEV=block/sda sda mount-point -# SYSDEV=block/sda * mount-point -# - wait for /sys/block/sda to appear, -# then mount /mnt/sda as /mnt/mnt-point -# -# LABEL=MYDEV * mount-point -# LABEL="MYDEV" * mount-point -# - wait for a partition with the given label to appear -# (via polling 'blkid') -# then mount as /mnt/mnt-point -# -# UUID=some-uuid * mount-point -# UUID="some-uuid" * mount-point -# - wait for a partition with the given UUID to appear -# (via polling 'blkid') -# then mount as /mnt/mnt-point -# -# - multiple lines mapping to the same mount point can -# be listed in /etc/onl/mounts, the first one that -# is valid wins -# -# - initmounts exits with code zero (success) -# if each mount point is mounted once -# -# - initmounts exits with non-zero (failure) -# if un-mounted mount points are still remaining after 10s -# -############################################################ -exec 9<$0 -flock -x 9 - -CR=" -" -PATH=$PATH:/sbin:/usr/sbin - -recover="fsck" - -try_mount_block() -{ - local dev devpart mount - dev=$1; shift - devpart=$1; shift - mount=$1; shift - - if test -b "$dev"; then - - if test "$devpart" = "*"; then - devpart=`echo "$dev" | sed -e 's/^.*[/]//' ` - fi - - test -d /mnt/$mount || mkdir -p /mnt/$mount - if test "$recover" = "fsck"; then - if dosfsck -a /dev/$devpart; then - : - else - dosfsck -n /dev/$devpart || return - fi - else - dosfsck -n /dev/$devpart || return - fi - mount -o noatime /dev/$devpart /mnt/$mount || return - echo "mounted /dev/$devpart --> /mnt/$mount" - - fi -} - -try_mount_sysdev() -{ - local syspath devpart mount - syspath=$1; shift - devpart=$1; shift - mount=$1; shift - - if test -e /sys/$syspath; then - - if test "$devpart" = "*"; then - devpart=`echo "$syspath" | sed -e 's/^.*[/]//' ` - fi - - test -d /mnt/$mount || mkdir -p /mnt/$mount - if test "$recover" = "fsck"; then - if dosfsck -a /dev/$devpart; then - : - else - dosfsck -n /dev/$devpart || return - fi - else - dosfsck -n /dev/$devpart || return - fi - mount -o noatime /dev/$devpart /mnt/$mount || return - echo "mounted /dev/$devpart --> /mnt/$mount" - - fi -} - -try_mount_label() -{ - local label devpart mount - label=$1; shift - devpart=$1; shift - mount=$1; shift - - local ifs dummy line dev - ifs=$IFS; IFS=$CR - for line in `blkid`; do - IFS=$ifs - case " $line " in - *" LABEL=${label} "*) - dev=`echo "$line" | sed -e 's/:.*//'` - break - ;; - *" LABEL=\"${label}\" "*) - dev=`echo "$line" | sed -e 's/:.*//'` - break - ;; - esac - done - IFS=$ifs - - if test "$dev"; then - try_mount_block "$dev" "$devpart" "$mount" - fi -} - -try_mount_uuid() -{ - local uuid devpart mount - uuid=$1; shift - devpart=$1; shift - mount=$1; shift - - local ifs dummy line dev - ifs=$IFS; IFS=$CR - for line in `blkid`; do - IFS=$ifs - case " $line " in - *" UUID=${uuid} "*) - dev=`echo "$line" | sed -e 's/:.*//'` - break - ;; - *" UUID=\"${label}\" "*) - dev=`echo "$uuid" | sed -e 's/:.*//'` - break - ;; - esac - done - IFS=$ifs - - if test "$dev"; then - try_mount_block "$dev" "$devpart" "$mount" - fi -} - -try_mount() -{ - local devspec devpart mount - devspec=$1; shift - devpart=$1; shift - mount=$1; shift - - if grep " /mnt/$mount " /proc/mounts 1>/dev/null; then - return - fi - - local sysdev label uuid - - case "$devspec" in - /dev/*) - try_mount_block "$devspec" "$devpart" "$mount" - ;; - block/*) - try_mount_sysdev "$devspec" "$devpart" "$mount" - ;; - SYSDEV=\"*\") - sysdev=`echo "$devspec" | sed -e 's/SYSDEV=\"\(.*\)\"/\1/'` - try_mount_sysdev "$sysdev" "$devpart" "$mount" - ;; - SYSDEV=*) - sysdev=`echo "$devspec" | sed -e 's/SYSDEV=\(.*\)/\1/'` - try_mount_sysdev "$sysdev" "$devpart" "$mount" - ;; - LABEL=\"*\") - label=`echo "$devspec" | sed -e 's/LABEL=\"\(.*\)\"/\1/'` - try_mount_label "$label" "$devpart" "$mount" - ;; - LABEL=*) - label=`echo "$devspec" | sed -e 's/LABEL=\(.*\)/\1/'` - try_mount_label "$label" "$devpart" "$mount" - ;; - UUID=\"*\") - uuid=`echo "$devspec" | sed -e 's/UUID=\"\(.*\)\"/\1/'` - try_mount_uuid "$uuid" "$devpart" "$mount" - ;; - UUID=*) - uuid=`echo "$devspec" | sed -e 's/UUID=\(.*\)/\1/'` - try_mount_uuid "$uuid" "$devpart" "$mount" - ;; - *) - echo "*** invalid block specifier: $devspec" 1>&2 - ;; - esac -} - -visit_onl_mounts() -{ - local fn rest - fn=$1; shift - rest="$@" - - local ifs dummy line remain - remain=0 - ifs=$IFS; IFS=$CR - for line in $(cat /etc/onl/mounts); do - IFS=$ifs - - set -f - set dummy $line; shift - devspec=$1; shift - devpart=$1; shift - mount=$1; shift - - grep " /mnt/$mount " /proc/mounts 1>/dev/null && continue - remain=1 - eval $fn "$devspec" "$devpart" "$mount" $rest - - set +f - done - IFS=$ifs - - return $remain -} - -if test -f /etc/onl/mounts; then - timeout=10 - while test $timeout -gt 0; do - if visit_onl_mounts try_mount; then - echo "Found all mounts." - exit 0 - fi - sleep 1 - timeout=$(( $timeout - 1 )) - done - if test "$timeout" -eq 0; then - echo "Timed out waiting for block devices" - exit 1 - fi -fi diff --git a/packages/base/all/initrds/loader-initrd-files/src/bin/initnetdev b/packages/base/all/initrds/loader-initrd-files/src/bin/initnetdev deleted file mode 100755 index 95744fcc..00000000 --- a/packages/base/all/initrds/loader-initrd-files/src/bin/initnetdev +++ /dev/null @@ -1,52 +0,0 @@ -#!/bin/sh -############################################################ -# -# -# Copyright 2013, 2014 BigSwitch Networks, Inc. -# -# Licensed under the Eclipse Public License, Version 1.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.eclipse.org/legal/epl-v10.html -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, -# either express or implied. See the License for the specific -# language governing permissions and limitations under the -# License. -# -# -############################################################ -# -# initnetdev -# -# Initialize management interfaces specified in /etc/onl/net -# -# This maps the platform's management interface to well-known -# interface names (such as ma1) -# -############################################################ -set -e -exec 9<$0 -flock -x 9 -case $2 in - add) - dev=$1 - devid= - if [ -e /sys/class/net/${dev}/device ]; then - eval $(realpath /sys/class/net/${dev}/device | sed 's#/sys/devices/\(.*\)#devid=\1#') - fi - while read i n; do - expr match "$i" "#" >/dev/null && continue || : - [ -n "${devid}" ] && expr match "${devid}" "$i" >/dev/null && name=$n && break || : - expr match "@${dev}" "$i" >/dev/null && name=$n && break || : - done &1 > /dev/null; then - ip link set dev ${dev} name ${name} - fi - ;; -esac From 27c18755db113d3561b6c2e52586c05ca616a46f Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Wed, 18 May 2016 12:52:17 -0700 Subject: [PATCH 077/113] Deprecated /etc/onl/mounts, /etc/onl/net - also make the platform boot hooks optional --- .../all/initrds/loader-initrd-files/src/lib/platform-detect | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/base/all/initrds/loader-initrd-files/src/lib/platform-detect b/packages/base/all/initrds/loader-initrd-files/src/lib/platform-detect index 446b3c5c..3c1d43d8 100644 --- a/packages/base/all/initrds/loader-initrd-files/src/lib/platform-detect +++ b/packages/base/all/initrds/loader-initrd-files/src/lib/platform-detect @@ -69,17 +69,15 @@ if [ ! -f /etc/onl/platform ]; then echo "unknown" > /etc/onl/platform fi -touch /etc/onl/net /etc/onl/block /etc/onl/mounts +touch /etc/onl/block platform="$(cat /etc/onl/platform)" if [ -d /lib/platform-config/${platform} ]; then - # Grab and source the platform boot configuration file + # Optionally source a platform boot configuration file x=/lib/platform-config/${platform}/onl/boot/${platform} if [ -f $x ]; then . $x - else - echo "The platform boot configuration for the current platform is broken, invalid, or missing." > /etc/onl/abort fi else echo "The current platform (${platform}) is not supported in this version." > /etc/onl/abort From 19bdb4d72e9ca8ca69eb764df5a07d1ac41a6141 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Wed, 18 May 2016 12:59:58 -0700 Subject: [PATCH 078/113] Deprecated per-platform grub.cfg, boot shell hooks, legacy install config --- .../platform-config/r0/src/lib/boot/grub.cfg | 21 ------------------ .../src/lib/boot/x86-64-accton-as5512-54x-r0 | 8 ------- .../install/x86-64-accton-as5512-54x-r0.sh | 15 ------------- .../platform-config/r0/src/lib/boot/grub.cfg | 21 ------------------ .../src/lib/boot/x86-64-accton-as5712-54x-r0 | 8 ------- .../install/x86-64-accton-as5712-54x-r0.sh | 15 ------------- .../platform-config/r0/src/lib/boot/grub.cfg | 21 ------------------ .../src/lib/boot/x86-64-accton-as5812-54t-r0 | 8 ------- .../install/x86-64-accton-as5812-54t-r0.sh | 15 ------------- .../platform-config/r0/src/lib/boot/grub.cfg | 21 ------------------ .../src/lib/boot/x86-64-accton-as5812-54x-r0 | 8 ------- .../install/x86-64-accton-as5812-54x-r0.sh | 15 ------------- .../platform-config/r0/src/lib/boot/grub.cfg | 22 ------------------- .../src/lib/boot/x86-64-accton-as6712-32x-r0 | 8 ------- .../install/x86-64-accton-as6712-32x-r0.sh | 15 ------------- .../platform-config/r0/src/lib/boot/grub.cfg | 21 ------------------ .../src/lib/boot/x86-64-accton-as6812-32x-r0 | 7 ------ .../install/x86-64-accton-as6812-32x-r0.sh | 15 ------------- .../platform-config/r0/src/lib/boot/grub.cfg | 21 ------------------ .../src/lib/boot/x86-64-accton-as7512-32x-r0 | 5 ----- .../install/x86-64-accton-as7512-32x-r0.sh | 15 ------------- .../platform-config/r0/src/lib/boot/grub.cfg | 21 ------------------ .../src/lib/boot/x86-64-accton-as7712-32x-r0 | 5 ----- .../install/x86-64-accton-as7712-32x-r0.sh | 15 ------------- .../platform-config/r0/src/lib/boot/grub.cfg | 21 ------------------ .../src/lib/boot/x86-64-accton-as7716-32x-r0 | 5 ----- .../install/x86-64-accton-as7716-32x-r0.sh | 15 ------------- .../platform-config/r0/src/lib/boot/grub.cfg | 22 ------------------- .../src/lib/boot/x86-64-accton-wedge-16x-r0 | 7 ------ .../lib/install/x86-64-accton-wedge-16x-r0.sh | 15 ------------- .../platform-config/r0/src/lib/boot/grub.cfg | 21 ------------------ .../r0/src/lib/boot/x86-64-cel-redstone-xp-r0 | 7 ------ .../lib/install/x86-64-cel-redstone-xp-r0.sh | 15 ------------- .../platform-config/r0/src/lib/boot/grub.cfg | 21 ------------------ .../r0/src/lib/boot/x86-64-kvm-x86-64-r0 | 6 ----- .../src/lib/install/x86-64-kvm-x86-64-r0.sh | 15 ------------- .../platform-config/r0/src/lib/boot/grub.cfg | 21 ------------------ .../lib/boot/x86-64-quanta-ly6-rangeley-r0 | 5 ----- .../install/x86-64-quanta-ly6-rangeley-r0.sh | 16 -------------- .../platform-config/r0/src/lib/boot/grub.cfg | 21 ------------------ .../lib/boot/x86-64-quanta-ly8-rangeley-r0 | 6 ----- .../install/x86-64-quanta-ly8-rangeley-r0.sh | 16 -------------- 42 files changed, 601 deletions(-) delete mode 100644 packages/platforms/accton/x86-64/x86-64-accton-as5512-54x/platform-config/r0/src/lib/boot/grub.cfg delete mode 100644 packages/platforms/accton/x86-64/x86-64-accton-as5512-54x/platform-config/r0/src/lib/boot/x86-64-accton-as5512-54x-r0 delete mode 100644 packages/platforms/accton/x86-64/x86-64-accton-as5512-54x/platform-config/r0/src/lib/install/x86-64-accton-as5512-54x-r0.sh delete mode 100644 packages/platforms/accton/x86-64/x86-64-accton-as5712-54x/platform-config/r0/src/lib/boot/grub.cfg delete mode 100644 packages/platforms/accton/x86-64/x86-64-accton-as5712-54x/platform-config/r0/src/lib/boot/x86-64-accton-as5712-54x-r0 delete mode 100644 packages/platforms/accton/x86-64/x86-64-accton-as5712-54x/platform-config/r0/src/lib/install/x86-64-accton-as5712-54x-r0.sh delete mode 100644 packages/platforms/accton/x86-64/x86-64-accton-as5812-54t/platform-config/r0/src/lib/boot/grub.cfg delete mode 100644 packages/platforms/accton/x86-64/x86-64-accton-as5812-54t/platform-config/r0/src/lib/boot/x86-64-accton-as5812-54t-r0 delete mode 100644 packages/platforms/accton/x86-64/x86-64-accton-as5812-54t/platform-config/r0/src/lib/install/x86-64-accton-as5812-54t-r0.sh delete mode 100644 packages/platforms/accton/x86-64/x86-64-accton-as5812-54x/platform-config/r0/src/lib/boot/grub.cfg delete mode 100644 packages/platforms/accton/x86-64/x86-64-accton-as5812-54x/platform-config/r0/src/lib/boot/x86-64-accton-as5812-54x-r0 delete mode 100644 packages/platforms/accton/x86-64/x86-64-accton-as5812-54x/platform-config/r0/src/lib/install/x86-64-accton-as5812-54x-r0.sh delete mode 100644 packages/platforms/accton/x86-64/x86-64-accton-as6712-32x/platform-config/r0/src/lib/boot/grub.cfg delete mode 100644 packages/platforms/accton/x86-64/x86-64-accton-as6712-32x/platform-config/r0/src/lib/boot/x86-64-accton-as6712-32x-r0 delete mode 100644 packages/platforms/accton/x86-64/x86-64-accton-as6712-32x/platform-config/r0/src/lib/install/x86-64-accton-as6712-32x-r0.sh delete mode 100644 packages/platforms/accton/x86-64/x86-64-accton-as6812-32x/platform-config/r0/src/lib/boot/grub.cfg delete mode 100644 packages/platforms/accton/x86-64/x86-64-accton-as6812-32x/platform-config/r0/src/lib/boot/x86-64-accton-as6812-32x-r0 delete mode 100644 packages/platforms/accton/x86-64/x86-64-accton-as6812-32x/platform-config/r0/src/lib/install/x86-64-accton-as6812-32x-r0.sh delete mode 100644 packages/platforms/accton/x86-64/x86-64-accton-as7512-32x/platform-config/r0/src/lib/boot/grub.cfg delete mode 100644 packages/platforms/accton/x86-64/x86-64-accton-as7512-32x/platform-config/r0/src/lib/boot/x86-64-accton-as7512-32x-r0 delete mode 100644 packages/platforms/accton/x86-64/x86-64-accton-as7512-32x/platform-config/r0/src/lib/install/x86-64-accton-as7512-32x-r0.sh delete mode 100644 packages/platforms/accton/x86-64/x86-64-accton-as7712-32x/platform-config/r0/src/lib/boot/grub.cfg delete mode 100644 packages/platforms/accton/x86-64/x86-64-accton-as7712-32x/platform-config/r0/src/lib/boot/x86-64-accton-as7712-32x-r0 delete mode 100644 packages/platforms/accton/x86-64/x86-64-accton-as7712-32x/platform-config/r0/src/lib/install/x86-64-accton-as7712-32x-r0.sh delete mode 100644 packages/platforms/accton/x86-64/x86-64-accton-as7716-32x/platform-config/r0/src/lib/boot/grub.cfg delete mode 100644 packages/platforms/accton/x86-64/x86-64-accton-as7716-32x/platform-config/r0/src/lib/boot/x86-64-accton-as7716-32x-r0 delete mode 100644 packages/platforms/accton/x86-64/x86-64-accton-as7716-32x/platform-config/r0/src/lib/install/x86-64-accton-as7716-32x-r0.sh delete mode 100644 packages/platforms/accton/x86-64/x86-64-accton-wedge-16x/platform-config/r0/src/lib/boot/grub.cfg delete mode 100644 packages/platforms/accton/x86-64/x86-64-accton-wedge-16x/platform-config/r0/src/lib/boot/x86-64-accton-wedge-16x-r0 delete mode 100644 packages/platforms/accton/x86-64/x86-64-accton-wedge-16x/platform-config/r0/src/lib/install/x86-64-accton-wedge-16x-r0.sh delete mode 100644 packages/platforms/celestica/x86-64/x86-64-cel-redstone-xp/platform-config/r0/src/lib/boot/grub.cfg delete mode 100644 packages/platforms/celestica/x86-64/x86-64-cel-redstone-xp/platform-config/r0/src/lib/boot/x86-64-cel-redstone-xp-r0 delete mode 100644 packages/platforms/celestica/x86-64/x86-64-cel-redstone-xp/platform-config/r0/src/lib/install/x86-64-cel-redstone-xp-r0.sh delete mode 100644 packages/platforms/kvm/x86-64/x86-64-kvm-x86-64/platform-config/r0/src/lib/boot/grub.cfg delete mode 100644 packages/platforms/kvm/x86-64/x86-64-kvm-x86-64/platform-config/r0/src/lib/boot/x86-64-kvm-x86-64-r0 delete mode 100644 packages/platforms/kvm/x86-64/x86-64-kvm-x86-64/platform-config/r0/src/lib/install/x86-64-kvm-x86-64-r0.sh delete mode 100644 packages/platforms/quanta/x86-64/x86-64-quanta-ly6-rangeley/platform-config/r0/src/lib/boot/grub.cfg delete mode 100644 packages/platforms/quanta/x86-64/x86-64-quanta-ly6-rangeley/platform-config/r0/src/lib/boot/x86-64-quanta-ly6-rangeley-r0 delete mode 100644 packages/platforms/quanta/x86-64/x86-64-quanta-ly6-rangeley/platform-config/r0/src/lib/install/x86-64-quanta-ly6-rangeley-r0.sh delete mode 100644 packages/platforms/quanta/x86-64/x86-64-quanta-ly8-rangeley/platform-config/r0/src/lib/boot/grub.cfg delete mode 100644 packages/platforms/quanta/x86-64/x86-64-quanta-ly8-rangeley/platform-config/r0/src/lib/boot/x86-64-quanta-ly8-rangeley-r0 delete mode 100644 packages/platforms/quanta/x86-64/x86-64-quanta-ly8-rangeley/platform-config/r0/src/lib/install/x86-64-quanta-ly8-rangeley-r0.sh diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as5512-54x/platform-config/r0/src/lib/boot/grub.cfg b/packages/platforms/accton/x86-64/x86-64-accton-as5512-54x/platform-config/r0/src/lib/boot/grub.cfg deleted file mode 100644 index 40105eaf..00000000 --- a/packages/platforms/accton/x86-64/x86-64-accton-as5512-54x/platform-config/r0/src/lib/boot/grub.cfg +++ /dev/null @@ -1,21 +0,0 @@ -serial --port=0x2f8 --speed=115200 --word=8 --parity=no --stop=1 -terminal_input serial -terminal_output serial -set timeout=5 - -# boot switch light -menuentry OpenNetworkLinux { - search --no-floppy --label --set=root ONL-BOOT - echo 'Loading Open Network Linux ...' - insmod gzio - insmod part_msdos - linux /kernel-3.2-deb7-x86_64-all nopat console=ttyS1,115200n8 onl_platform=x86-64-accton-as5512-54x-r0 - initrd /initrd-amd64 -} - -# Menu entry to chainload ONIE -menuentry ONIE { - search --no-floppy --label --set=root ONIE-BOOT - echo 'Loading ONIE ...' - chainloader +1 -} diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as5512-54x/platform-config/r0/src/lib/boot/x86-64-accton-as5512-54x-r0 b/packages/platforms/accton/x86-64/x86-64-accton-as5512-54x/platform-config/r0/src/lib/boot/x86-64-accton-as5512-54x-r0 deleted file mode 100644 index 98eccc32..00000000 --- a/packages/platforms/accton/x86-64/x86-64-accton-as5512-54x/platform-config/r0/src/lib/boot/x86-64-accton-as5512-54x-r0 +++ /dev/null @@ -1,8 +0,0 @@ -############################## -# -# x86-64-accton-as5512-54x-r0 -# -############################## - - - diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as5512-54x/platform-config/r0/src/lib/install/x86-64-accton-as5512-54x-r0.sh b/packages/platforms/accton/x86-64/x86-64-accton-as5512-54x/platform-config/r0/src/lib/install/x86-64-accton-as5512-54x-r0.sh deleted file mode 100644 index e62ede0a..00000000 --- a/packages/platforms/accton/x86-64/x86-64-accton-as5512-54x/platform-config/r0/src/lib/install/x86-64-accton-as5512-54x-r0.sh +++ /dev/null @@ -1,15 +0,0 @@ -############################################################ -# -# -# Copyright 2013, 2014 BigSwitch Networks, Inc. -# -# -# -# -############################################################ -# Platform data goes here. - -platform_installer() { - # Standard isntallation to an available GPT partition - installer_standard_gpt_install /dev/sda -} diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as5712-54x/platform-config/r0/src/lib/boot/grub.cfg b/packages/platforms/accton/x86-64/x86-64-accton-as5712-54x/platform-config/r0/src/lib/boot/grub.cfg deleted file mode 100644 index a39bae8c..00000000 --- a/packages/platforms/accton/x86-64/x86-64-accton-as5712-54x/platform-config/r0/src/lib/boot/grub.cfg +++ /dev/null @@ -1,21 +0,0 @@ -serial --port=0x2f8 --speed=115200 --word=8 --parity=no --stop=1 -terminal_input serial -terminal_output serial -set timeout=5 - -# boot switch light -menuentry OpenNetworkLinux { - search --no-floppy --label --set=root ONL-BOOT - echo 'Loading Open Network Linux ...' - insmod gzio - insmod part_msdos - linux /kernel-3.2-deb7-x86_64-all nopat console=ttyS1,115200n8 onl_platform=x86-64-accton-as5712-54x-r0 - initrd /initrd-amd64 -} - -# Menu entry to chainload ONIE -menuentry ONIE { - search --no-floppy --label --set=root ONIE-BOOT - echo 'Loading ONIE ...' - chainloader +1 -} diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as5712-54x/platform-config/r0/src/lib/boot/x86-64-accton-as5712-54x-r0 b/packages/platforms/accton/x86-64/x86-64-accton-as5712-54x/platform-config/r0/src/lib/boot/x86-64-accton-as5712-54x-r0 deleted file mode 100644 index e476f767..00000000 --- a/packages/platforms/accton/x86-64/x86-64-accton-as5712-54x/platform-config/r0/src/lib/boot/x86-64-accton-as5712-54x-r0 +++ /dev/null @@ -1,8 +0,0 @@ -############################## -# -# x86-64-accton-as5712-54x-r0 -# -############################## - - - diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as5712-54x/platform-config/r0/src/lib/install/x86-64-accton-as5712-54x-r0.sh b/packages/platforms/accton/x86-64/x86-64-accton-as5712-54x/platform-config/r0/src/lib/install/x86-64-accton-as5712-54x-r0.sh deleted file mode 100644 index e62ede0a..00000000 --- a/packages/platforms/accton/x86-64/x86-64-accton-as5712-54x/platform-config/r0/src/lib/install/x86-64-accton-as5712-54x-r0.sh +++ /dev/null @@ -1,15 +0,0 @@ -############################################################ -# -# -# Copyright 2013, 2014 BigSwitch Networks, Inc. -# -# -# -# -############################################################ -# Platform data goes here. - -platform_installer() { - # Standard isntallation to an available GPT partition - installer_standard_gpt_install /dev/sda -} diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as5812-54t/platform-config/r0/src/lib/boot/grub.cfg b/packages/platforms/accton/x86-64/x86-64-accton-as5812-54t/platform-config/r0/src/lib/boot/grub.cfg deleted file mode 100644 index f0446db5..00000000 --- a/packages/platforms/accton/x86-64/x86-64-accton-as5812-54t/platform-config/r0/src/lib/boot/grub.cfg +++ /dev/null @@ -1,21 +0,0 @@ -serial --port=0x2f8 --speed=115200 --word=8 --parity=no --stop=1 -terminal_input serial -terminal_output serial -set timeout=5 - -# boot switch light -menuentry OpenNetworkLinux { - search --no-floppy --label --set=root ONL-BOOT - echo 'Loading Open Network Linux ...' - insmod gzio - insmod part_msdos - linux /kernel-3.2-deb7-x86_64-all nopat console=ttyS1,115200n8 onl_platform=x86-64-accton-as5812-54t-r0 - initrd /initrd-amd64 -} - -# Menu entry to chainload ONIE -menuentry ONIE { - search --no-floppy --label --set=root ONIE-BOOT - echo 'Loading ONIE ...' - chainloader +1 -} diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as5812-54t/platform-config/r0/src/lib/boot/x86-64-accton-as5812-54t-r0 b/packages/platforms/accton/x86-64/x86-64-accton-as5812-54t/platform-config/r0/src/lib/boot/x86-64-accton-as5812-54t-r0 deleted file mode 100644 index 1675e4b5..00000000 --- a/packages/platforms/accton/x86-64/x86-64-accton-as5812-54t/platform-config/r0/src/lib/boot/x86-64-accton-as5812-54t-r0 +++ /dev/null @@ -1,8 +0,0 @@ -############################## -# -# x86-64-accton-as5812-54t-r0 -# -############################## - - - diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as5812-54t/platform-config/r0/src/lib/install/x86-64-accton-as5812-54t-r0.sh b/packages/platforms/accton/x86-64/x86-64-accton-as5812-54t/platform-config/r0/src/lib/install/x86-64-accton-as5812-54t-r0.sh deleted file mode 100644 index e62ede0a..00000000 --- a/packages/platforms/accton/x86-64/x86-64-accton-as5812-54t/platform-config/r0/src/lib/install/x86-64-accton-as5812-54t-r0.sh +++ /dev/null @@ -1,15 +0,0 @@ -############################################################ -# -# -# Copyright 2013, 2014 BigSwitch Networks, Inc. -# -# -# -# -############################################################ -# Platform data goes here. - -platform_installer() { - # Standard isntallation to an available GPT partition - installer_standard_gpt_install /dev/sda -} diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as5812-54x/platform-config/r0/src/lib/boot/grub.cfg b/packages/platforms/accton/x86-64/x86-64-accton-as5812-54x/platform-config/r0/src/lib/boot/grub.cfg deleted file mode 100644 index 37ee3ba1..00000000 --- a/packages/platforms/accton/x86-64/x86-64-accton-as5812-54x/platform-config/r0/src/lib/boot/grub.cfg +++ /dev/null @@ -1,21 +0,0 @@ -serial --port=0x2f8 --speed=115200 --word=8 --parity=no --stop=1 -terminal_input serial -terminal_output serial -set timeout=5 - -# boot switch light -menuentry OpenNetworkLinux { - search --no-floppy --label --set=root ONL-BOOT - echo 'Loading Open Network Linux ...' - insmod gzio - insmod part_msdos - linux /kernel-3.2-deb7-x86_64-all nopat console=ttyS1,115200n8 onl_platform=x86-64-accton-as5812-54x-r0 - initrd /initrd-amd64 -} - -# Menu entry to chainload ONIE -menuentry ONIE { - search --no-floppy --label --set=root ONIE-BOOT - echo 'Loading ONIE ...' - chainloader +1 -} diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as5812-54x/platform-config/r0/src/lib/boot/x86-64-accton-as5812-54x-r0 b/packages/platforms/accton/x86-64/x86-64-accton-as5812-54x/platform-config/r0/src/lib/boot/x86-64-accton-as5812-54x-r0 deleted file mode 100644 index 746de4fb..00000000 --- a/packages/platforms/accton/x86-64/x86-64-accton-as5812-54x/platform-config/r0/src/lib/boot/x86-64-accton-as5812-54x-r0 +++ /dev/null @@ -1,8 +0,0 @@ -############################## -# -# x86-64-accton-as5812-54x-r0 -# -############################## - - - diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as5812-54x/platform-config/r0/src/lib/install/x86-64-accton-as5812-54x-r0.sh b/packages/platforms/accton/x86-64/x86-64-accton-as5812-54x/platform-config/r0/src/lib/install/x86-64-accton-as5812-54x-r0.sh deleted file mode 100644 index e62ede0a..00000000 --- a/packages/platforms/accton/x86-64/x86-64-accton-as5812-54x/platform-config/r0/src/lib/install/x86-64-accton-as5812-54x-r0.sh +++ /dev/null @@ -1,15 +0,0 @@ -############################################################ -# -# -# Copyright 2013, 2014 BigSwitch Networks, Inc. -# -# -# -# -############################################################ -# Platform data goes here. - -platform_installer() { - # Standard isntallation to an available GPT partition - installer_standard_gpt_install /dev/sda -} diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as6712-32x/platform-config/r0/src/lib/boot/grub.cfg b/packages/platforms/accton/x86-64/x86-64-accton-as6712-32x/platform-config/r0/src/lib/boot/grub.cfg deleted file mode 100644 index c0b3d9c0..00000000 --- a/packages/platforms/accton/x86-64/x86-64-accton-as6712-32x/platform-config/r0/src/lib/boot/grub.cfg +++ /dev/null @@ -1,22 +0,0 @@ -serial --port=0x2f8 --speed=115200 --word=8 --parity=no --stop=1 -terminal_input serial -terminal_output serial -set timeout=5 - -# boot switch light -menuentry OpenNetworkLinux { - search --no-floppy --label --set=root ONL-BOOT - echo 'Loading Open Network Linux ...' - insmod gzio - insmod part_msdos - linux /kernel-3.2-deb7-x86_64-all nopat console=ttyS1,115200n8 onl_platform=x86-64-accton-as6712-32x-r0 - initrd /initrd-amd64 -} - -# Menu entry to chainload ONIE -menuentry ONIE { - search --no-floppy --label --set=root ONIE-BOOT - echo 'Loading ONIE ...' - chainloader +1 -} - diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as6712-32x/platform-config/r0/src/lib/boot/x86-64-accton-as6712-32x-r0 b/packages/platforms/accton/x86-64/x86-64-accton-as6712-32x/platform-config/r0/src/lib/boot/x86-64-accton-as6712-32x-r0 deleted file mode 100644 index d84f6aab..00000000 --- a/packages/platforms/accton/x86-64/x86-64-accton-as6712-32x/platform-config/r0/src/lib/boot/x86-64-accton-as6712-32x-r0 +++ /dev/null @@ -1,8 +0,0 @@ -############################################################ -# -# x86-64-accton-as6712-32x-r0 -# -############################################################ - - - diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as6712-32x/platform-config/r0/src/lib/install/x86-64-accton-as6712-32x-r0.sh b/packages/platforms/accton/x86-64/x86-64-accton-as6712-32x/platform-config/r0/src/lib/install/x86-64-accton-as6712-32x-r0.sh deleted file mode 100644 index e62ede0a..00000000 --- a/packages/platforms/accton/x86-64/x86-64-accton-as6712-32x/platform-config/r0/src/lib/install/x86-64-accton-as6712-32x-r0.sh +++ /dev/null @@ -1,15 +0,0 @@ -############################################################ -# -# -# Copyright 2013, 2014 BigSwitch Networks, Inc. -# -# -# -# -############################################################ -# Platform data goes here. - -platform_installer() { - # Standard isntallation to an available GPT partition - installer_standard_gpt_install /dev/sda -} diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as6812-32x/platform-config/r0/src/lib/boot/grub.cfg b/packages/platforms/accton/x86-64/x86-64-accton-as6812-32x/platform-config/r0/src/lib/boot/grub.cfg deleted file mode 100644 index d45f87bf..00000000 --- a/packages/platforms/accton/x86-64/x86-64-accton-as6812-32x/platform-config/r0/src/lib/boot/grub.cfg +++ /dev/null @@ -1,21 +0,0 @@ -serial --port=0x2f8 --speed=115200 --word=8 --parity=no --stop=1 -terminal_input serial -terminal_output serial -set timeout=5 - -# boot onl -menuentry OpenNetworkLinux { - search --no-floppy --label --set=root ONL-BOOT - echo 'Loading Open Network Linux ...' - insmod gzio - insmod part_msdos - linux /kernel-3.2-deb7-x86_64-all nopat console=ttyS1,115200n8 onl_platform=x86-64-accton-as6812-32x-r0 - initrd /initrd-amd64 -} - -# Menu entry to chainload ONIE -menuentry ONIE { - search --no-floppy --label --set=root ONIE-BOOT - echo 'Loading ONIE ...' - chainloader +1 -} diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as6812-32x/platform-config/r0/src/lib/boot/x86-64-accton-as6812-32x-r0 b/packages/platforms/accton/x86-64/x86-64-accton-as6812-32x/platform-config/r0/src/lib/boot/x86-64-accton-as6812-32x-r0 deleted file mode 100644 index 90ddefcb..00000000 --- a/packages/platforms/accton/x86-64/x86-64-accton-as6812-32x/platform-config/r0/src/lib/boot/x86-64-accton-as6812-32x-r0 +++ /dev/null @@ -1,7 +0,0 @@ -############################## -# -# x86-64-accton-as6812-32x-r0 -# -############################## - - diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as6812-32x/platform-config/r0/src/lib/install/x86-64-accton-as6812-32x-r0.sh b/packages/platforms/accton/x86-64/x86-64-accton-as6812-32x/platform-config/r0/src/lib/install/x86-64-accton-as6812-32x-r0.sh deleted file mode 100644 index 1c7108fa..00000000 --- a/packages/platforms/accton/x86-64/x86-64-accton-as6812-32x/platform-config/r0/src/lib/install/x86-64-accton-as6812-32x-r0.sh +++ /dev/null @@ -1,15 +0,0 @@ -############################################################ -# -# -# Copyright 2013, 2014 BigSwitch Networks, Inc. -# -# -# -# -############################################################ -# Platform data goes here. - -platform_installer() { - # Standard isntallation to an available GPT partition - installer_standard_gpt_install /dev/sda -} diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as7512-32x/platform-config/r0/src/lib/boot/grub.cfg b/packages/platforms/accton/x86-64/x86-64-accton-as7512-32x/platform-config/r0/src/lib/boot/grub.cfg deleted file mode 100644 index f3152ac3..00000000 --- a/packages/platforms/accton/x86-64/x86-64-accton-as7512-32x/platform-config/r0/src/lib/boot/grub.cfg +++ /dev/null @@ -1,21 +0,0 @@ -serial --port=0x2f8 --speed=115200 --word=8 --parity=no --stop=1 -terminal_input serial -terminal_output serial -set timeout=5 - -# boot onl -menuentry OpenNetworkLinux { - search --no-floppy --label --set=root ONL-BOOT - echo 'Loading Open Network Linux ...' - insmod gzio - insmod part_msdos - linux /kernel-3.2-deb7-x86_64-all nopat console=ttyS1,115200n8 onl_platform=x86-64-accton-as7512-32x-r0 - initrd /initrd-amd64 -} - -# Menu entry to chainload ONIE -menuentry ONIE { - search --no-floppy --label --set=root ONIE-BOOT - echo 'Loading ONIE ...' - chainloader +1 -} diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as7512-32x/platform-config/r0/src/lib/boot/x86-64-accton-as7512-32x-r0 b/packages/platforms/accton/x86-64/x86-64-accton-as7512-32x/platform-config/r0/src/lib/boot/x86-64-accton-as7512-32x-r0 deleted file mode 100644 index 8e758e9a..00000000 --- a/packages/platforms/accton/x86-64/x86-64-accton-as7512-32x/platform-config/r0/src/lib/boot/x86-64-accton-as7512-32x-r0 +++ /dev/null @@ -1,5 +0,0 @@ -############################## -# -# x86-64-accton-as7512-32x-r0 -# -############################## diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as7512-32x/platform-config/r0/src/lib/install/x86-64-accton-as7512-32x-r0.sh b/packages/platforms/accton/x86-64/x86-64-accton-as7512-32x/platform-config/r0/src/lib/install/x86-64-accton-as7512-32x-r0.sh deleted file mode 100644 index 1c7108fa..00000000 --- a/packages/platforms/accton/x86-64/x86-64-accton-as7512-32x/platform-config/r0/src/lib/install/x86-64-accton-as7512-32x-r0.sh +++ /dev/null @@ -1,15 +0,0 @@ -############################################################ -# -# -# Copyright 2013, 2014 BigSwitch Networks, Inc. -# -# -# -# -############################################################ -# Platform data goes here. - -platform_installer() { - # Standard isntallation to an available GPT partition - installer_standard_gpt_install /dev/sda -} diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as7712-32x/platform-config/r0/src/lib/boot/grub.cfg b/packages/platforms/accton/x86-64/x86-64-accton-as7712-32x/platform-config/r0/src/lib/boot/grub.cfg deleted file mode 100644 index cd5cc7a6..00000000 --- a/packages/platforms/accton/x86-64/x86-64-accton-as7712-32x/platform-config/r0/src/lib/boot/grub.cfg +++ /dev/null @@ -1,21 +0,0 @@ -serial --port=0x2f8 --speed=115200 --word=8 --parity=no --stop=1 -terminal_input serial -terminal_output serial -set timeout=5 - -# boot onl -menuentry OpenNetworkLinux { - search --no-floppy --label --set=root ONL-BOOT - echo 'Loading Open Network Linux ...' - insmod gzio - insmod part_msdos - linux /kernel-3.2-deb7-x86_64-all nopat console=ttyS1,115200n8 onl_platform=x86-64-accton-as7712-32x-r0 - initrd /initrd-amd64 -} - -# Menu entry to chainload ONIE -menuentry ONIE { - search --no-floppy --label --set=root ONIE-BOOT - echo 'Loading ONIE ...' - chainloader +1 -} diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as7712-32x/platform-config/r0/src/lib/boot/x86-64-accton-as7712-32x-r0 b/packages/platforms/accton/x86-64/x86-64-accton-as7712-32x/platform-config/r0/src/lib/boot/x86-64-accton-as7712-32x-r0 deleted file mode 100644 index 90c3d11f..00000000 --- a/packages/platforms/accton/x86-64/x86-64-accton-as7712-32x/platform-config/r0/src/lib/boot/x86-64-accton-as7712-32x-r0 +++ /dev/null @@ -1,5 +0,0 @@ -############################## -# -# x86-64-accton-as7712-32x-r0 -# -############################## diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as7712-32x/platform-config/r0/src/lib/install/x86-64-accton-as7712-32x-r0.sh b/packages/platforms/accton/x86-64/x86-64-accton-as7712-32x/platform-config/r0/src/lib/install/x86-64-accton-as7712-32x-r0.sh deleted file mode 100644 index f30823a2..00000000 --- a/packages/platforms/accton/x86-64/x86-64-accton-as7712-32x/platform-config/r0/src/lib/install/x86-64-accton-as7712-32x-r0.sh +++ /dev/null @@ -1,15 +0,0 @@ -############################################################ -# -# -# Copyright 2013, 2014 BigSwitch Networks, Inc. -# -# -# -# -############################################################ -# Platform data goes here. - -platform_installer() { - # Standard isntallation to an available GPT partition - installer_standard_gpt_install -} diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as7716-32x/platform-config/r0/src/lib/boot/grub.cfg b/packages/platforms/accton/x86-64/x86-64-accton-as7716-32x/platform-config/r0/src/lib/boot/grub.cfg deleted file mode 100644 index ef2b5f5c..00000000 --- a/packages/platforms/accton/x86-64/x86-64-accton-as7716-32x/platform-config/r0/src/lib/boot/grub.cfg +++ /dev/null @@ -1,21 +0,0 @@ -serial --port=0x3f8 --speed=115200 --word=8 --parity=no --stop=1 -terminal_input serial -terminal_output serial -set timeout=5 - -# boot onl -menuentry OpenNetworkLinux { - search --no-floppy --label --set=root ONL-BOOT - echo 'Loading Open Network Linux ...' - insmod gzio - insmod part_msdos - linux /kernel-3.2-deb7-x86_64-all nopat console=ttyS0,115200n8 onl_platform=x86-64-accton-as7716-32x-r0 - initrd /initrd-amd64 -} - -# Menu entry to chainload ONIE -menuentry ONIE { - search --no-floppy --label --set=root ONIE-BOOT - echo 'Loading ONIE ...' - chainloader +1 -} diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as7716-32x/platform-config/r0/src/lib/boot/x86-64-accton-as7716-32x-r0 b/packages/platforms/accton/x86-64/x86-64-accton-as7716-32x/platform-config/r0/src/lib/boot/x86-64-accton-as7716-32x-r0 deleted file mode 100644 index 7231a049..00000000 --- a/packages/platforms/accton/x86-64/x86-64-accton-as7716-32x/platform-config/r0/src/lib/boot/x86-64-accton-as7716-32x-r0 +++ /dev/null @@ -1,5 +0,0 @@ -############################## -# -# x86-64-accton-as7716-32x-r0 -# -############################## diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as7716-32x/platform-config/r0/src/lib/install/x86-64-accton-as7716-32x-r0.sh b/packages/platforms/accton/x86-64/x86-64-accton-as7716-32x/platform-config/r0/src/lib/install/x86-64-accton-as7716-32x-r0.sh deleted file mode 100644 index f30823a2..00000000 --- a/packages/platforms/accton/x86-64/x86-64-accton-as7716-32x/platform-config/r0/src/lib/install/x86-64-accton-as7716-32x-r0.sh +++ /dev/null @@ -1,15 +0,0 @@ -############################################################ -# -# -# Copyright 2013, 2014 BigSwitch Networks, Inc. -# -# -# -# -############################################################ -# Platform data goes here. - -platform_installer() { - # Standard isntallation to an available GPT partition - installer_standard_gpt_install -} diff --git a/packages/platforms/accton/x86-64/x86-64-accton-wedge-16x/platform-config/r0/src/lib/boot/grub.cfg b/packages/platforms/accton/x86-64/x86-64-accton-wedge-16x/platform-config/r0/src/lib/boot/grub.cfg deleted file mode 100644 index 44a99ece..00000000 --- a/packages/platforms/accton/x86-64/x86-64-accton-wedge-16x/platform-config/r0/src/lib/boot/grub.cfg +++ /dev/null @@ -1,22 +0,0 @@ -serial --unit=0 --speed=57600 --word=8 --parity=0 --stop=1 -terminal_input serial -terminal_output serial -set timeout=5 - -# boot onl -menuentry OpenNetworkLinux { - search --no-floppy --label --set=root ONL-BOOT - echo 'Loading Open Network Linux ...' - insmod gzio - insmod part_msdos - # grub options copied from Wedge's grub.conf; did not verify which were necessary - linux /kernel-3.2-deb7-x86_64-all nopat console=ttyS1,57600n8 onl_platform=x86-64-accton-wedge-16x-r0 rd_NO_MD rd_NO_LUKS intel_iommu=off - initrd /initrd-amd64 -} - -# Menu entry to chainload ONIE -menuentry ONIE { - search --no-floppy --label --set=root ONIE-BOOT - echo 'Loading ONIE ...' - chainloader +1 -} diff --git a/packages/platforms/accton/x86-64/x86-64-accton-wedge-16x/platform-config/r0/src/lib/boot/x86-64-accton-wedge-16x-r0 b/packages/platforms/accton/x86-64/x86-64-accton-wedge-16x/platform-config/r0/src/lib/boot/x86-64-accton-wedge-16x-r0 deleted file mode 100644 index b562e433..00000000 --- a/packages/platforms/accton/x86-64/x86-64-accton-wedge-16x/platform-config/r0/src/lib/boot/x86-64-accton-wedge-16x-r0 +++ /dev/null @@ -1,7 +0,0 @@ -############################## -# -# x86-64-accton-wedge-16x-r0 -# -############################## - - diff --git a/packages/platforms/accton/x86-64/x86-64-accton-wedge-16x/platform-config/r0/src/lib/install/x86-64-accton-wedge-16x-r0.sh b/packages/platforms/accton/x86-64/x86-64-accton-wedge-16x/platform-config/r0/src/lib/install/x86-64-accton-wedge-16x-r0.sh deleted file mode 100644 index 1c7108fa..00000000 --- a/packages/platforms/accton/x86-64/x86-64-accton-wedge-16x/platform-config/r0/src/lib/install/x86-64-accton-wedge-16x-r0.sh +++ /dev/null @@ -1,15 +0,0 @@ -############################################################ -# -# -# Copyright 2013, 2014 BigSwitch Networks, Inc. -# -# -# -# -############################################################ -# Platform data goes here. - -platform_installer() { - # Standard isntallation to an available GPT partition - installer_standard_gpt_install /dev/sda -} diff --git a/packages/platforms/celestica/x86-64/x86-64-cel-redstone-xp/platform-config/r0/src/lib/boot/grub.cfg b/packages/platforms/celestica/x86-64/x86-64-cel-redstone-xp/platform-config/r0/src/lib/boot/grub.cfg deleted file mode 100644 index f1dfa037..00000000 --- a/packages/platforms/celestica/x86-64/x86-64-cel-redstone-xp/platform-config/r0/src/lib/boot/grub.cfg +++ /dev/null @@ -1,21 +0,0 @@ -serial --port=0x3f8 --speed=115200 --word=8 --parity=no --stop=1 -terminal_input serial -terminal_output serial -set timeout=5 - -menuentry OpenNetworkLinux { - search --no-floppy --label --set=root ONL-BOOT - echo 'Loading Open Network Linux ...' - insmod gzio - insmod part_msdos - linux /kernel-3.2-deb7-x86_64-all nopat console=ttyS0,115200n8 onl_platform=x86-64-cel-redstone-xp-r0 - initrd /initrd-amd64 -} - -# Menu entry to chainload ONIE -menuentry ONIE { - search --no-floppy --label --set=root ONIE-BOOT - echo 'Loading ONIE ...' - chainloader +1 -} - diff --git a/packages/platforms/celestica/x86-64/x86-64-cel-redstone-xp/platform-config/r0/src/lib/boot/x86-64-cel-redstone-xp-r0 b/packages/platforms/celestica/x86-64/x86-64-cel-redstone-xp/platform-config/r0/src/lib/boot/x86-64-cel-redstone-xp-r0 deleted file mode 100644 index 09c12df9..00000000 --- a/packages/platforms/celestica/x86-64/x86-64-cel-redstone-xp/platform-config/r0/src/lib/boot/x86-64-cel-redstone-xp-r0 +++ /dev/null @@ -1,7 +0,0 @@ -############################## -# -# x86-64-cel-redstone-xp-r0 -# -############################## - - diff --git a/packages/platforms/celestica/x86-64/x86-64-cel-redstone-xp/platform-config/r0/src/lib/install/x86-64-cel-redstone-xp-r0.sh b/packages/platforms/celestica/x86-64/x86-64-cel-redstone-xp/platform-config/r0/src/lib/install/x86-64-cel-redstone-xp-r0.sh deleted file mode 100644 index e62ede0a..00000000 --- a/packages/platforms/celestica/x86-64/x86-64-cel-redstone-xp/platform-config/r0/src/lib/install/x86-64-cel-redstone-xp-r0.sh +++ /dev/null @@ -1,15 +0,0 @@ -############################################################ -# -# -# Copyright 2013, 2014 BigSwitch Networks, Inc. -# -# -# -# -############################################################ -# Platform data goes here. - -platform_installer() { - # Standard isntallation to an available GPT partition - installer_standard_gpt_install /dev/sda -} diff --git a/packages/platforms/kvm/x86-64/x86-64-kvm-x86-64/platform-config/r0/src/lib/boot/grub.cfg b/packages/platforms/kvm/x86-64/x86-64-kvm-x86-64/platform-config/r0/src/lib/boot/grub.cfg deleted file mode 100644 index e0526b6d..00000000 --- a/packages/platforms/kvm/x86-64/x86-64-kvm-x86-64/platform-config/r0/src/lib/boot/grub.cfg +++ /dev/null @@ -1,21 +0,0 @@ -serial --port=0x3f8 --speed=115200 --word=8 --parity=no --stop=1 -terminal_input serial -terminal_output serial -set timeout=5 - -menuentry OpenNetworkLinux { - search --no-floppy --label --set=root ONL-BOOT - echo 'Loading Open Network Linux ...' - insmod gzio - insmod part_msdos - linux /kernel-3.9.6-x86-64-all nopat console=ttyS0,115200n8 onl_platform=x86-64-kvm-x86-64-r0 - initrd /initrd-amd64 -} - -# Menu entry to chainload ONIE -menuentry ONIE { - search --no-floppy --label --set=root ONIE-BOOT - echo 'Loading ONIE ...' - chainloader +1 -} - diff --git a/packages/platforms/kvm/x86-64/x86-64-kvm-x86-64/platform-config/r0/src/lib/boot/x86-64-kvm-x86-64-r0 b/packages/platforms/kvm/x86-64/x86-64-kvm-x86-64/platform-config/r0/src/lib/boot/x86-64-kvm-x86-64-r0 deleted file mode 100644 index c869975b..00000000 --- a/packages/platforms/kvm/x86-64/x86-64-kvm-x86-64/platform-config/r0/src/lib/boot/x86-64-kvm-x86-64-r0 +++ /dev/null @@ -1,6 +0,0 @@ -############################## -# -# x86-64-kvm-x86-64-r0 -# -############################## - diff --git a/packages/platforms/kvm/x86-64/x86-64-kvm-x86-64/platform-config/r0/src/lib/install/x86-64-kvm-x86-64-r0.sh b/packages/platforms/kvm/x86-64/x86-64-kvm-x86-64/platform-config/r0/src/lib/install/x86-64-kvm-x86-64-r0.sh deleted file mode 100644 index 1fe58183..00000000 --- a/packages/platforms/kvm/x86-64/x86-64-kvm-x86-64/platform-config/r0/src/lib/install/x86-64-kvm-x86-64-r0.sh +++ /dev/null @@ -1,15 +0,0 @@ -############################################################ -# -# -# Copyright 2013, 2014 BigSwitch Networks, Inc. -# -# -# -# -############################################################ -# Platform data goes here. - -platform_installer() { - # Standard isntallation to an available GPT partition - installer_standard_gpt_install /dev/vda -} diff --git a/packages/platforms/quanta/x86-64/x86-64-quanta-ly6-rangeley/platform-config/r0/src/lib/boot/grub.cfg b/packages/platforms/quanta/x86-64/x86-64-quanta-ly6-rangeley/platform-config/r0/src/lib/boot/grub.cfg deleted file mode 100644 index 55ad9311..00000000 --- a/packages/platforms/quanta/x86-64/x86-64-quanta-ly6-rangeley/platform-config/r0/src/lib/boot/grub.cfg +++ /dev/null @@ -1,21 +0,0 @@ -serial --port=0x2f8 --speed=115200 --word=8 --parity=no --stop=1 -terminal_input serial -terminal_output serial -set timeout=5 - -# boot onl -menuentry OpenNetworkLinux { - search --no-floppy --label --set=root ONL-BOOT - echo 'Loading Open Network Linux ...' - insmod gzio - insmod part_msdos - linux /kernel-3.9.6-x86-64-all console=ttyS1,115200n8 onl_platform=x86-64-quanta-ly6-rangeley-r0 - initrd /initrd-amd64 -} - -# Menu entry to chainload ONIE -menuentry ONIE { - search --no-floppy --label --set=root ONIE-BOOT - echo 'Loading ONIE ...' - chainloader +1 -} diff --git a/packages/platforms/quanta/x86-64/x86-64-quanta-ly6-rangeley/platform-config/r0/src/lib/boot/x86-64-quanta-ly6-rangeley-r0 b/packages/platforms/quanta/x86-64/x86-64-quanta-ly6-rangeley/platform-config/r0/src/lib/boot/x86-64-quanta-ly6-rangeley-r0 deleted file mode 100644 index 0cba156d..00000000 --- a/packages/platforms/quanta/x86-64/x86-64-quanta-ly6-rangeley/platform-config/r0/src/lib/boot/x86-64-quanta-ly6-rangeley-r0 +++ /dev/null @@ -1,5 +0,0 @@ -############################## -# -# x86-64-quanta-ly6-rangely-r0 -# -############################## diff --git a/packages/platforms/quanta/x86-64/x86-64-quanta-ly6-rangeley/platform-config/r0/src/lib/install/x86-64-quanta-ly6-rangeley-r0.sh b/packages/platforms/quanta/x86-64/x86-64-quanta-ly6-rangeley/platform-config/r0/src/lib/install/x86-64-quanta-ly6-rangeley-r0.sh deleted file mode 100644 index 1a40e94b..00000000 --- a/packages/platforms/quanta/x86-64/x86-64-quanta-ly6-rangeley/platform-config/r0/src/lib/install/x86-64-quanta-ly6-rangeley-r0.sh +++ /dev/null @@ -1,16 +0,0 @@ -############################################################ -# -# -# Copyright 2013, 2014 BigSwitch Networks, Inc. -# Copyright 2015 Quanta Computer Inc. -# -# -# -# -############################################################ -# Platform data goes here. - -platform_installer() { - # Standard isntallation to an available GPT partition - installer_standard_gpt_install /dev/sda -} diff --git a/packages/platforms/quanta/x86-64/x86-64-quanta-ly8-rangeley/platform-config/r0/src/lib/boot/grub.cfg b/packages/platforms/quanta/x86-64/x86-64-quanta-ly8-rangeley/platform-config/r0/src/lib/boot/grub.cfg deleted file mode 100644 index 63c09023..00000000 --- a/packages/platforms/quanta/x86-64/x86-64-quanta-ly8-rangeley/platform-config/r0/src/lib/boot/grub.cfg +++ /dev/null @@ -1,21 +0,0 @@ -serial --port=0x2f8 --speed=115200 --word=8 --parity=no --stop=1 -terminal_input serial -terminal_output serial -set timeout=5 - -# boot onl -menuentry OpenNetworkLinux { - search --no-floppy --label --set=root ONL-BOOT - echo 'Loading Open Network Linux ...' - insmod gzio - insmod part_msdos - linux /kernel-3.9.6-x86-64-all console=ttyS1,115200n8 onl_platform=x86-64-quanta-ly8-rangeley-r0 - initrd /initrd-amd64 -} - -# Menu entry to chainload ONIE -menuentry ONIE { - search --no-floppy --label --set=root ONIE-BOOT - echo 'Loading ONIE ...' - chainloader +1 -} diff --git a/packages/platforms/quanta/x86-64/x86-64-quanta-ly8-rangeley/platform-config/r0/src/lib/boot/x86-64-quanta-ly8-rangeley-r0 b/packages/platforms/quanta/x86-64/x86-64-quanta-ly8-rangeley/platform-config/r0/src/lib/boot/x86-64-quanta-ly8-rangeley-r0 deleted file mode 100644 index 385ab67e..00000000 --- a/packages/platforms/quanta/x86-64/x86-64-quanta-ly8-rangeley/platform-config/r0/src/lib/boot/x86-64-quanta-ly8-rangeley-r0 +++ /dev/null @@ -1,6 +0,0 @@ -############################## -# -# x86-64-quanta-ly8-rangely-r0 -# -############################## - diff --git a/packages/platforms/quanta/x86-64/x86-64-quanta-ly8-rangeley/platform-config/r0/src/lib/install/x86-64-quanta-ly8-rangeley-r0.sh b/packages/platforms/quanta/x86-64/x86-64-quanta-ly8-rangeley/platform-config/r0/src/lib/install/x86-64-quanta-ly8-rangeley-r0.sh deleted file mode 100644 index 1a40e94b..00000000 --- a/packages/platforms/quanta/x86-64/x86-64-quanta-ly8-rangeley/platform-config/r0/src/lib/install/x86-64-quanta-ly8-rangeley-r0.sh +++ /dev/null @@ -1,16 +0,0 @@ -############################################################ -# -# -# Copyright 2013, 2014 BigSwitch Networks, Inc. -# Copyright 2015 Quanta Computer Inc. -# -# -# -# -############################################################ -# Platform data goes here. - -platform_installer() { - # Standard isntallation to an available GPT partition - installer_standard_gpt_install /dev/sda -} From b232b0946a79c85b099093089f29f96e0637e523 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Wed, 18 May 2016 13:13:27 -0700 Subject: [PATCH 079/113] Deprecated legacy install files for ppc and arm --- .../r0/src/lib/boot/arm-accton-as4610-54-r0 | 6 ---- .../lib/install/arm-accton-as4610-54-r0.sh | 7 ----- .../src/lib/boot/powerpc-accton-as4600-54t-r0 | 4 --- .../install/powerpc-accton-as4600-54t-r0.sh | 28 ------------------- .../src/lib/boot/powerpc-accton-as5610-52x-r0 | 3 -- .../install/powerpc-accton-as5610-52x-r0.sh | 28 ------------------- .../src/lib/boot/powerpc-accton-as5710-54x-r0 | 6 ---- .../install/powerpc-accton-as5710-54x-r0.sh | 27 ------------------ .../lib/boot/powerpc-accton-as5710-54x-r0b | 6 ---- .../install/powerpc-accton-as5710-54x-r0b.sh | 27 ------------------ .../src/lib/boot/powerpc-accton-as6700-32x-r0 | 12 -------- .../install/powerpc-accton-as6700-32x-r0.sh | 28 ------------------- .../src/lib/boot/powerpc-accton-as6700-32x-r1 | 9 ------ .../install/powerpc-accton-as6700-32x-r1.sh | 28 ------------------- .../r0/src/lib/boot/arm-qemu-armv7a-r0 | 5 ---- .../r0/src/lib/install/arm-qemu-armv7a-r0.sh | 15 ---------- .../r0/src/lib/boot/powerpc-quanta-lb9-r0 | 5 ---- .../src/lib/install/powerpc-quanta-lb9-r0.sh | 28 ------------------- .../r0/src/lib/boot/powerpc-quanta-ly2-r0 | 25 ----------------- .../src/lib/install/powerpc-quanta-ly2-r0.sh | 28 ------------------- 20 files changed, 325 deletions(-) delete mode 100644 packages/platforms/accton/armel/arm-accton-as4610-54/platform-config/r0/src/lib/boot/arm-accton-as4610-54-r0 delete mode 100644 packages/platforms/accton/armel/arm-accton-as4610-54/platform-config/r0/src/lib/install/arm-accton-as4610-54-r0.sh delete mode 100644 packages/platforms/accton/powerpc/powerpc-accton-as4600-54t/platform-config/r0/src/lib/boot/powerpc-accton-as4600-54t-r0 delete mode 100644 packages/platforms/accton/powerpc/powerpc-accton-as4600-54t/platform-config/r0/src/lib/install/powerpc-accton-as4600-54t-r0.sh delete mode 100644 packages/platforms/accton/powerpc/powerpc-accton-as5610-52x/platform-config/r0/src/lib/boot/powerpc-accton-as5610-52x-r0 delete mode 100644 packages/platforms/accton/powerpc/powerpc-accton-as5610-52x/platform-config/r0/src/lib/install/powerpc-accton-as5610-52x-r0.sh delete mode 100644 packages/platforms/accton/powerpc/powerpc-accton-as5710-54x/platform-config/r0/src/lib/boot/powerpc-accton-as5710-54x-r0 delete mode 100644 packages/platforms/accton/powerpc/powerpc-accton-as5710-54x/platform-config/r0/src/lib/install/powerpc-accton-as5710-54x-r0.sh delete mode 100644 packages/platforms/accton/powerpc/powerpc-accton-as5710-54x/platform-config/r0b/src/lib/boot/powerpc-accton-as5710-54x-r0b delete mode 100644 packages/platforms/accton/powerpc/powerpc-accton-as5710-54x/platform-config/r0b/src/lib/install/powerpc-accton-as5710-54x-r0b.sh delete mode 100644 packages/platforms/accton/powerpc/powerpc-accton-as6700-32x/platform-config/r0/src/lib/boot/powerpc-accton-as6700-32x-r0 delete mode 100644 packages/platforms/accton/powerpc/powerpc-accton-as6700-32x/platform-config/r0/src/lib/install/powerpc-accton-as6700-32x-r0.sh delete mode 100644 packages/platforms/accton/powerpc/powerpc-accton-as6700-32x/platform-config/r1/src/lib/boot/powerpc-accton-as6700-32x-r1 delete mode 100644 packages/platforms/accton/powerpc/powerpc-accton-as6700-32x/platform-config/r1/src/lib/install/powerpc-accton-as6700-32x-r1.sh delete mode 100644 packages/platforms/qemu/arm/arm-qemu-armv7a/platform-config/r0/src/lib/boot/arm-qemu-armv7a-r0 delete mode 100644 packages/platforms/qemu/arm/arm-qemu-armv7a/platform-config/r0/src/lib/install/arm-qemu-armv7a-r0.sh delete mode 100644 packages/platforms/quanta/powerpc/powerpc-quanta-lb9/platform-config/r0/src/lib/boot/powerpc-quanta-lb9-r0 delete mode 100644 packages/platforms/quanta/powerpc/powerpc-quanta-lb9/platform-config/r0/src/lib/install/powerpc-quanta-lb9-r0.sh delete mode 100644 packages/platforms/quanta/powerpc/powerpc-quanta-ly2/platform-config/r0/src/lib/boot/powerpc-quanta-ly2-r0 delete mode 100644 packages/platforms/quanta/powerpc/powerpc-quanta-ly2/platform-config/r0/src/lib/install/powerpc-quanta-ly2-r0.sh diff --git a/packages/platforms/accton/armel/arm-accton-as4610-54/platform-config/r0/src/lib/boot/arm-accton-as4610-54-r0 b/packages/platforms/accton/armel/arm-accton-as4610-54/platform-config/r0/src/lib/boot/arm-accton-as4610-54-r0 deleted file mode 100644 index f00ff42d..00000000 --- a/packages/platforms/accton/armel/arm-accton-as4610-54/platform-config/r0/src/lib/boot/arm-accton-as4610-54-r0 +++ /dev/null @@ -1,6 +0,0 @@ -############################## -# -# arm-accton-as4610-54-r0 -# -############################## - diff --git a/packages/platforms/accton/armel/arm-accton-as4610-54/platform-config/r0/src/lib/install/arm-accton-as4610-54-r0.sh b/packages/platforms/accton/armel/arm-accton-as4610-54/platform-config/r0/src/lib/install/arm-accton-as4610-54-r0.sh deleted file mode 100644 index 753d8c9e..00000000 --- a/packages/platforms/accton/armel/arm-accton-as4610-54/platform-config/r0/src/lib/install/arm-accton-as4610-54-r0.sh +++ /dev/null @@ -1,7 +0,0 @@ -# The loader is installed in the fat partition of the first USB storage device -platform_bootcmd="usb start; usbiddev; ext2load usb 0:1 70000000 $ONL_PLATFORM.itb; setenv bootargs console=\$consoledev,\$baudrate onl_platform=$ONL_PLATFORM; bootm 70000000#$ONL_PLATFORM" - -platform_installer() { - # Standard installation to usb storage - installer_standard_blockdev_install sda 128M 128M 1024M "" -} diff --git a/packages/platforms/accton/powerpc/powerpc-accton-as4600-54t/platform-config/r0/src/lib/boot/powerpc-accton-as4600-54t-r0 b/packages/platforms/accton/powerpc/powerpc-accton-as4600-54t/platform-config/r0/src/lib/boot/powerpc-accton-as4600-54t-r0 deleted file mode 100644 index e569ba60..00000000 --- a/packages/platforms/accton/powerpc/powerpc-accton-as4600-54t/platform-config/r0/src/lib/boot/powerpc-accton-as4600-54t-r0 +++ /dev/null @@ -1,4 +0,0 @@ -############################################################ -# powerpc-accton-as4600-54t-r0 -############################################################ - diff --git a/packages/platforms/accton/powerpc/powerpc-accton-as4600-54t/platform-config/r0/src/lib/install/powerpc-accton-as4600-54t-r0.sh b/packages/platforms/accton/powerpc/powerpc-accton-as4600-54t/platform-config/r0/src/lib/install/powerpc-accton-as4600-54t-r0.sh deleted file mode 100644 index e9bef0b1..00000000 --- a/packages/platforms/accton/powerpc/powerpc-accton-as4600-54t/platform-config/r0/src/lib/install/powerpc-accton-as4600-54t-r0.sh +++ /dev/null @@ -1,28 +0,0 @@ -############################################################ -# -# -# Copyright 2013, 2014 Big Switch Networks, Inc. -# -# Licensed under the Eclipse Public License, Version 1.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.eclipse.org/legal/epl-v10.html -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, -# either express or implied. See the License for the specific -# language governing permissions and limitations under the -# License. -# -# -############################################################ - -# The loader is installed in the fat partition of the first USB storage device -platform_bootcmd="usb start; ext2load usb 0:1 0x10000000 $ONL_PLATFORM.itb; setenv bootargs console=\$consoledev,\$baudrate onl_platform=$ONL_PLATFORM; bootm 0x10000000#$ONL_PLATFORM" - -platform_installer() { - # Standard installation to usb storage - installer_standard_blockdev_install sda 32M 32M 448M "" -} diff --git a/packages/platforms/accton/powerpc/powerpc-accton-as5610-52x/platform-config/r0/src/lib/boot/powerpc-accton-as5610-52x-r0 b/packages/platforms/accton/powerpc/powerpc-accton-as5610-52x/platform-config/r0/src/lib/boot/powerpc-accton-as5610-52x-r0 deleted file mode 100644 index 6601b373..00000000 --- a/packages/platforms/accton/powerpc/powerpc-accton-as5610-52x/platform-config/r0/src/lib/boot/powerpc-accton-as5610-52x-r0 +++ /dev/null @@ -1,3 +0,0 @@ -############################################################ -# powerpc-accton-as5610-52x-r0 -############################################################ diff --git a/packages/platforms/accton/powerpc/powerpc-accton-as5610-52x/platform-config/r0/src/lib/install/powerpc-accton-as5610-52x-r0.sh b/packages/platforms/accton/powerpc/powerpc-accton-as5610-52x/platform-config/r0/src/lib/install/powerpc-accton-as5610-52x-r0.sh deleted file mode 100644 index bb545142..00000000 --- a/packages/platforms/accton/powerpc/powerpc-accton-as5610-52x/platform-config/r0/src/lib/install/powerpc-accton-as5610-52x-r0.sh +++ /dev/null @@ -1,28 +0,0 @@ -############################################################ -# -# -# Copyright 2013, 2014 Big Switch Networks, Inc. -# -# Licensed under the Eclipse Public License, Version 1.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.eclipse.org/legal/epl-v10.html -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, -# either express or implied. See the License for the specific -# language governing permissions and limitations under the -# License. -# -# -############################################################ - -# The loader is installed in the fat partition of the first USB storage device -platform_bootcmd="usb start; ext2load usb 0:1 0x10000000 $ONL_PLATFORM.itb; setenv bootargs console=\$consoledev,\$baudrate onl_platform=$ONL_PLATFORM; bootm 0x10000000#$ONL_PLATFORM" - -platform_installer() { - # Standard installation to usb storage - installer_standard_blockdev_install sda 128M 128M 768M "" -} diff --git a/packages/platforms/accton/powerpc/powerpc-accton-as5710-54x/platform-config/r0/src/lib/boot/powerpc-accton-as5710-54x-r0 b/packages/platforms/accton/powerpc/powerpc-accton-as5710-54x/platform-config/r0/src/lib/boot/powerpc-accton-as5710-54x-r0 deleted file mode 100644 index c4f271d3..00000000 --- a/packages/platforms/accton/powerpc/powerpc-accton-as5710-54x/platform-config/r0/src/lib/boot/powerpc-accton-as5710-54x-r0 +++ /dev/null @@ -1,6 +0,0 @@ -############################################################ -# powerpc-accton-as5710-54x-r0 -############################################################ - - - diff --git a/packages/platforms/accton/powerpc/powerpc-accton-as5710-54x/platform-config/r0/src/lib/install/powerpc-accton-as5710-54x-r0.sh b/packages/platforms/accton/powerpc/powerpc-accton-as5710-54x/platform-config/r0/src/lib/install/powerpc-accton-as5710-54x-r0.sh deleted file mode 100644 index 029244c5..00000000 --- a/packages/platforms/accton/powerpc/powerpc-accton-as5710-54x/platform-config/r0/src/lib/install/powerpc-accton-as5710-54x-r0.sh +++ /dev/null @@ -1,27 +0,0 @@ -############################################################ -# -# -# Copyright 2013, 2014 Big Switch Networks, Inc. -# -# Licensed under the Eclipse Public License, Version 1.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.eclipse.org/legal/epl-v10.html -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, -# either express or implied. See the License for the specific -# language governing permissions and limitations under the -# License. -# -# -############################################################ - -platform_bootcmd="usb start; ext2load usb 0:1 0x10000000 $ONL_PLATFORM.itb; setenv bootargs console=\$consoledev,\$baudrate onl_platform=$ONL_PLATFORM; bootm 0x10000000#$ONL_PLATFORM" - -platform_installer() { - # Standard installation to usb storage - installer_standard_blockdev_install sda 128M 128M 1024M "" -} diff --git a/packages/platforms/accton/powerpc/powerpc-accton-as5710-54x/platform-config/r0b/src/lib/boot/powerpc-accton-as5710-54x-r0b b/packages/platforms/accton/powerpc/powerpc-accton-as5710-54x/platform-config/r0b/src/lib/boot/powerpc-accton-as5710-54x-r0b deleted file mode 100644 index 17e54a7d..00000000 --- a/packages/platforms/accton/powerpc/powerpc-accton-as5710-54x/platform-config/r0b/src/lib/boot/powerpc-accton-as5710-54x-r0b +++ /dev/null @@ -1,6 +0,0 @@ -############################################################ -# powerpc-accton-as5710-54x-r0b -############################################################ - - - diff --git a/packages/platforms/accton/powerpc/powerpc-accton-as5710-54x/platform-config/r0b/src/lib/install/powerpc-accton-as5710-54x-r0b.sh b/packages/platforms/accton/powerpc/powerpc-accton-as5710-54x/platform-config/r0b/src/lib/install/powerpc-accton-as5710-54x-r0b.sh deleted file mode 100644 index 029244c5..00000000 --- a/packages/platforms/accton/powerpc/powerpc-accton-as5710-54x/platform-config/r0b/src/lib/install/powerpc-accton-as5710-54x-r0b.sh +++ /dev/null @@ -1,27 +0,0 @@ -############################################################ -# -# -# Copyright 2013, 2014 Big Switch Networks, Inc. -# -# Licensed under the Eclipse Public License, Version 1.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.eclipse.org/legal/epl-v10.html -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, -# either express or implied. See the License for the specific -# language governing permissions and limitations under the -# License. -# -# -############################################################ - -platform_bootcmd="usb start; ext2load usb 0:1 0x10000000 $ONL_PLATFORM.itb; setenv bootargs console=\$consoledev,\$baudrate onl_platform=$ONL_PLATFORM; bootm 0x10000000#$ONL_PLATFORM" - -platform_installer() { - # Standard installation to usb storage - installer_standard_blockdev_install sda 128M 128M 1024M "" -} diff --git a/packages/platforms/accton/powerpc/powerpc-accton-as6700-32x/platform-config/r0/src/lib/boot/powerpc-accton-as6700-32x-r0 b/packages/platforms/accton/powerpc/powerpc-accton-as6700-32x/platform-config/r0/src/lib/boot/powerpc-accton-as6700-32x-r0 deleted file mode 100644 index 209a1851..00000000 --- a/packages/platforms/accton/powerpc/powerpc-accton-as6700-32x/platform-config/r0/src/lib/boot/powerpc-accton-as6700-32x-r0 +++ /dev/null @@ -1,12 +0,0 @@ -############################################################ -# powerpc-accton-as6700-32x-r0 -############################################################ - - - - - - - - - diff --git a/packages/platforms/accton/powerpc/powerpc-accton-as6700-32x/platform-config/r0/src/lib/install/powerpc-accton-as6700-32x-r0.sh b/packages/platforms/accton/powerpc/powerpc-accton-as6700-32x/platform-config/r0/src/lib/install/powerpc-accton-as6700-32x-r0.sh deleted file mode 100644 index bb545142..00000000 --- a/packages/platforms/accton/powerpc/powerpc-accton-as6700-32x/platform-config/r0/src/lib/install/powerpc-accton-as6700-32x-r0.sh +++ /dev/null @@ -1,28 +0,0 @@ -############################################################ -# -# -# Copyright 2013, 2014 Big Switch Networks, Inc. -# -# Licensed under the Eclipse Public License, Version 1.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.eclipse.org/legal/epl-v10.html -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, -# either express or implied. See the License for the specific -# language governing permissions and limitations under the -# License. -# -# -############################################################ - -# The loader is installed in the fat partition of the first USB storage device -platform_bootcmd="usb start; ext2load usb 0:1 0x10000000 $ONL_PLATFORM.itb; setenv bootargs console=\$consoledev,\$baudrate onl_platform=$ONL_PLATFORM; bootm 0x10000000#$ONL_PLATFORM" - -platform_installer() { - # Standard installation to usb storage - installer_standard_blockdev_install sda 128M 128M 768M "" -} diff --git a/packages/platforms/accton/powerpc/powerpc-accton-as6700-32x/platform-config/r1/src/lib/boot/powerpc-accton-as6700-32x-r1 b/packages/platforms/accton/powerpc/powerpc-accton-as6700-32x/platform-config/r1/src/lib/boot/powerpc-accton-as6700-32x-r1 deleted file mode 100644 index f9325723..00000000 --- a/packages/platforms/accton/powerpc/powerpc-accton-as6700-32x/platform-config/r1/src/lib/boot/powerpc-accton-as6700-32x-r1 +++ /dev/null @@ -1,9 +0,0 @@ -############################################################ -# powerpc-accton-as6700-32x-r1 -############################################################ - - - - - - diff --git a/packages/platforms/accton/powerpc/powerpc-accton-as6700-32x/platform-config/r1/src/lib/install/powerpc-accton-as6700-32x-r1.sh b/packages/platforms/accton/powerpc/powerpc-accton-as6700-32x/platform-config/r1/src/lib/install/powerpc-accton-as6700-32x-r1.sh deleted file mode 100644 index bb545142..00000000 --- a/packages/platforms/accton/powerpc/powerpc-accton-as6700-32x/platform-config/r1/src/lib/install/powerpc-accton-as6700-32x-r1.sh +++ /dev/null @@ -1,28 +0,0 @@ -############################################################ -# -# -# Copyright 2013, 2014 Big Switch Networks, Inc. -# -# Licensed under the Eclipse Public License, Version 1.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.eclipse.org/legal/epl-v10.html -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, -# either express or implied. See the License for the specific -# language governing permissions and limitations under the -# License. -# -# -############################################################ - -# The loader is installed in the fat partition of the first USB storage device -platform_bootcmd="usb start; ext2load usb 0:1 0x10000000 $ONL_PLATFORM.itb; setenv bootargs console=\$consoledev,\$baudrate onl_platform=$ONL_PLATFORM; bootm 0x10000000#$ONL_PLATFORM" - -platform_installer() { - # Standard installation to usb storage - installer_standard_blockdev_install sda 128M 128M 768M "" -} diff --git a/packages/platforms/qemu/arm/arm-qemu-armv7a/platform-config/r0/src/lib/boot/arm-qemu-armv7a-r0 b/packages/platforms/qemu/arm/arm-qemu-armv7a/platform-config/r0/src/lib/boot/arm-qemu-armv7a-r0 deleted file mode 100644 index 05edaafd..00000000 --- a/packages/platforms/qemu/arm/arm-qemu-armv7a/platform-config/r0/src/lib/boot/arm-qemu-armv7a-r0 +++ /dev/null @@ -1,5 +0,0 @@ -############################## -# -# arm-qemu-armv7a-r0 -# -############################## diff --git a/packages/platforms/qemu/arm/arm-qemu-armv7a/platform-config/r0/src/lib/install/arm-qemu-armv7a-r0.sh b/packages/platforms/qemu/arm/arm-qemu-armv7a/platform-config/r0/src/lib/install/arm-qemu-armv7a-r0.sh deleted file mode 100644 index e62ede0a..00000000 --- a/packages/platforms/qemu/arm/arm-qemu-armv7a/platform-config/r0/src/lib/install/arm-qemu-armv7a-r0.sh +++ /dev/null @@ -1,15 +0,0 @@ -############################################################ -# -# -# Copyright 2013, 2014 BigSwitch Networks, Inc. -# -# -# -# -############################################################ -# Platform data goes here. - -platform_installer() { - # Standard isntallation to an available GPT partition - installer_standard_gpt_install /dev/sda -} diff --git a/packages/platforms/quanta/powerpc/powerpc-quanta-lb9/platform-config/r0/src/lib/boot/powerpc-quanta-lb9-r0 b/packages/platforms/quanta/powerpc/powerpc-quanta-lb9/platform-config/r0/src/lib/boot/powerpc-quanta-lb9-r0 deleted file mode 100644 index 93588a96..00000000 --- a/packages/platforms/quanta/powerpc/powerpc-quanta-lb9/platform-config/r0/src/lib/boot/powerpc-quanta-lb9-r0 +++ /dev/null @@ -1,5 +0,0 @@ -############################################################ -# -# powerpc-quanta-lb9-r0 -# -############################################################ diff --git a/packages/platforms/quanta/powerpc/powerpc-quanta-lb9/platform-config/r0/src/lib/install/powerpc-quanta-lb9-r0.sh b/packages/platforms/quanta/powerpc/powerpc-quanta-lb9/platform-config/r0/src/lib/install/powerpc-quanta-lb9-r0.sh deleted file mode 100644 index 0b7ebb4f..00000000 --- a/packages/platforms/quanta/powerpc/powerpc-quanta-lb9/platform-config/r0/src/lib/install/powerpc-quanta-lb9-r0.sh +++ /dev/null @@ -1,28 +0,0 @@ -############################################################ -# -# -# Copyright 2013, 2014 Big Switch Networks, Inc. -# -# Licensed under the Eclipse Public License, Version 1.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.eclipse.org/legal/epl-v10.html -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, -# either express or implied. See the License for the specific -# language governing permissions and limitations under the -# License. -# -# -############################################################ - -# The bootcommand is to read the loader directly from the first partition and execute it. -platform_bootcmd="ext2load ide 0:1 0x10000000 powerpc-quanta-lb9-r0.itb; setenv bootargs console=\$consoledev,\$baudrate onl_platform=$ONL_PLATFORM; bootm 0x10000000#$ONL_PLATFORM" - -platform_installer() { - # Standard installation on the CF card. - installer_standard_blockdev_install sda 128M 128M 1024M "" -} diff --git a/packages/platforms/quanta/powerpc/powerpc-quanta-ly2/platform-config/r0/src/lib/boot/powerpc-quanta-ly2-r0 b/packages/platforms/quanta/powerpc/powerpc-quanta-ly2/platform-config/r0/src/lib/boot/powerpc-quanta-ly2-r0 deleted file mode 100644 index 4687f72c..00000000 --- a/packages/platforms/quanta/powerpc/powerpc-quanta-ly2/platform-config/r0/src/lib/boot/powerpc-quanta-ly2-r0 +++ /dev/null @@ -1,25 +0,0 @@ -# -*- sh -*- -############################################################ -# -# -# Copyright 2013, 2014 Big Switch Networks, Inc. -# -# Licensed under the Eclipse Public License, Version 1.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.eclipse.org/legal/epl-v10.html -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, -# either express or implied. See the License for the specific -# language governing permissions and limitations under the -# License. -# -# -############################################################ -# -# powerpc-quanta-ly2-r0 -# -############################################################ diff --git a/packages/platforms/quanta/powerpc/powerpc-quanta-ly2/platform-config/r0/src/lib/install/powerpc-quanta-ly2-r0.sh b/packages/platforms/quanta/powerpc/powerpc-quanta-ly2/platform-config/r0/src/lib/install/powerpc-quanta-ly2-r0.sh deleted file mode 100644 index 72f4a223..00000000 --- a/packages/platforms/quanta/powerpc/powerpc-quanta-ly2/platform-config/r0/src/lib/install/powerpc-quanta-ly2-r0.sh +++ /dev/null @@ -1,28 +0,0 @@ -############################################################ -# -# -# Copyright 2013, 2014 Big Switch Networks, Inc. -# -# Licensed under the Eclipse Public License, Version 1.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.eclipse.org/legal/epl-v10.html -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, -# either express or implied. See the License for the specific -# language governing permissions and limitations under the -# License. -# -# -############################################################ - -# The bootcommand is to read the loader directly from the first partition and execute it. -platform_bootcmd="mmc part 0; ext2load mmc 0:1 0x10000000 $ONL_PLATFORM.itb; setenv bootargs console=\$consoledev,\$baudrate onl_platform=$ONL_PLATFORM; bootm 0x10000000#$ONL_PLATFORM" - -platform_installer() { - # Standard installation on the CF card. - installer_standard_blockdev_install mmcblk0 128M 128M 1024M "" -} From 76eb1099d9d9b0cfd6cb2234b2f2185db8ae1eda Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Wed, 18 May 2016 13:30:42 -0700 Subject: [PATCH 080/113] Updatef for review feedback --- packages/base/all/vendor-config-onl/PKG.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/base/all/vendor-config-onl/PKG.yml b/packages/base/all/vendor-config-onl/PKG.yml index 025517c9..32109df3 100644 --- a/packages/base/all/vendor-config-onl/PKG.yml +++ b/packages/base/all/vendor-config-onl/PKG.yml @@ -24,7 +24,7 @@ packages: summary: ONL Base Configuration Package (Loader) files: - src/python/onl : /usr/lib/python2.7/dist-packages/onl + src/python/onl : $PY_INSTALL/onl src/bin/initmounts : /bin/initmounts src/bin/initubootenv : /bin/initubootenv src/bin/initnetdev : /bin/initnetdev From 929234b9ed2fd6601872e755d37b52b93593aa5a Mon Sep 17 00:00:00 2001 From: Charlie Lewis Date: Wed, 18 May 2016 15:40:43 -0700 Subject: [PATCH 081/113] small typo --- docs/GettingStartedWedge.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/GettingStartedWedge.md b/docs/GettingStartedWedge.md index fb479df2..42fe39c9 100644 --- a/docs/GettingStartedWedge.md +++ b/docs/GettingStartedWedge.md @@ -66,7 +66,7 @@ ONL Manual Install 4) Wait for the install to finish and the system to reboot -5) One the onl login prompt appears login with the username root and the +5) Once the onl login prompt appears login with the username root and the password "onl" 6) Configure the ma1 interface either via dhcp (dhclient ma1) or manually From ea375379db3dfcd27844df3103f73109e04153ab Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Wed, 18 May 2016 18:47:58 -0700 Subject: [PATCH 082/113] Deprecate initnetdev - moved to onl-vendor-config-onl - onl-loader-initscripts is now deprecated --- builds/any/rootfs/jessie/common/common-packages.yml | 1 - builds/any/rootfs/wheezy/common/common-packages.yml | 1 - packages/base/all/initrds/loader-initrd-files/PKG.yml | 11 ----------- 3 files changed, 13 deletions(-) diff --git a/builds/any/rootfs/jessie/common/common-packages.yml b/builds/any/rootfs/jessie/common/common-packages.yml index ef765ea3..d41477b4 100644 --- a/builds/any/rootfs/jessie/common/common-packages.yml +++ b/builds/any/rootfs/jessie/common/common-packages.yml @@ -66,7 +66,6 @@ - realpath - iptables - onl-faultd -- onl-loader-initscripts - onlp-snmpd - oom-shim - python-parted diff --git a/builds/any/rootfs/wheezy/common/common-packages.yml b/builds/any/rootfs/wheezy/common/common-packages.yml index 40a6bf5d..eb365075 100644 --- a/builds/any/rootfs/wheezy/common/common-packages.yml +++ b/builds/any/rootfs/wheezy/common/common-packages.yml @@ -65,7 +65,6 @@ - realpath - iptables - onl-faultd -- onl-loader-initscripts - onlp-snmpd - oom-shim - python-parted diff --git a/packages/base/all/initrds/loader-initrd-files/PKG.yml b/packages/base/all/initrds/loader-initrd-files/PKG.yml index 3ae21ef7..9b8e7022 100644 --- a/packages/base/all/initrds/loader-initrd-files/PKG.yml +++ b/packages/base/all/initrds/loader-initrd-files/PKG.yml @@ -22,15 +22,4 @@ packages: changelog: Change changes changes., - - name: onl-loader-initscripts - version: 1.0.0 - summary: Open Network Linux System Loader Common Initscripts - - files: - src/bin/initnetdev : /sbin/ - - changelog: Change changes changes., - - - From 3f5e708161d8cfa23928ef029b29c7899f560396 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Wed, 18 May 2016 18:49:34 -0700 Subject: [PATCH 083/113] Spray and pray! Everything is eth0, right? - stub out syspath entries for network devices - assume that each platform boots with eth0 --- .../r0/src/lib/powerpc-accton-as4600-54t-r0.yml | 10 +++++----- .../r0/src/lib/powerpc-accton-as5610-52x-r0.yml | 10 +++++----- .../r0/src/lib/powerpc-accton-as5710-54x-r0.yml | 10 +++++----- .../r0b/src/lib/powerpc-accton-as5710-54x-r0b.yml | 10 +++++----- .../r0/src/lib/powerpc-accton-as6700-32x-r0.yml | 10 +++++----- .../r1/src/lib/powerpc-accton-as6700-32x-r1.yml | 10 +++++----- .../r0/src/lib/x86-64-accton-as5512-54x-r0.yml | 10 +++++----- .../r0/src/lib/x86-64-accton-as5712-54x-r0.yml | 10 +++++----- .../r0/src/lib/x86-64-accton-as5812-54t-r0.yml | 10 +++++----- .../r0/src/lib/x86-64-accton-as5812-54x-r0.yml | 10 +++++----- .../r0/src/lib/x86-64-accton-as6712-32x-r0.yml | 10 +++++----- .../r0/src/lib/x86-64-accton-as6812-32x-r0.yml | 10 +++++----- .../r0/src/lib/x86-64-accton-as7512-32x-r0.yml | 10 +++++----- .../r0/src/lib/x86-64-accton-as7712-32x-r0.yml | 10 +++++----- .../r0/src/lib/x86-64-accton-wedge-16x-r0.yml | 10 +++++----- .../r0/src/lib/x86-64-cel-redstone-xp-r0.yml | 10 +++++----- .../r0/src/lib/x86-64-kvm-x86-64-r0.yml | 10 +++++----- .../r0/src/lib/powerpc-quanta-lb9-r0.yml | 10 +++++----- .../r0/src/lib/powerpc-quanta-ly2-r0.yml | 10 +++++----- .../r0/src/lib/x86-64-quanta-ly6-rangeley-r0.yml | 10 +++++----- .../r0/src/lib/x86-64-quanta-ly8-rangeley-r0.yml | 10 +++++----- 21 files changed, 105 insertions(+), 105 deletions(-) diff --git a/packages/platforms/accton/powerpc/powerpc-accton-as4600-54t/platform-config/r0/src/lib/powerpc-accton-as4600-54t-r0.yml b/packages/platforms/accton/powerpc/powerpc-accton-as4600-54t/platform-config/r0/src/lib/powerpc-accton-as4600-54t-r0.yml index 1e8f0c60..eb3bdf19 100644 --- a/packages/platforms/accton/powerpc/powerpc-accton-as4600-54t/platform-config/r0/src/lib/powerpc-accton-as4600-54t-r0.yml +++ b/packages/platforms/accton/powerpc/powerpc-accton-as4600-54t/platform-config/r0/src/lib/powerpc-accton-as4600-54t-r0.yml @@ -39,8 +39,8 @@ powerpc-accton-as4600-54t-r0: =: 100% format: ext4 - network: - interfaces: - ma1: - name: ~ - syspath: soc.0/ff725000.ethernet + ##network: + ## interfaces: + ## ma1: + ## name: ~ + ## syspath: soc.0/ff725000.ethernet diff --git a/packages/platforms/accton/powerpc/powerpc-accton-as5610-52x/platform-config/r0/src/lib/powerpc-accton-as5610-52x-r0.yml b/packages/platforms/accton/powerpc/powerpc-accton-as5610-52x/platform-config/r0/src/lib/powerpc-accton-as5610-52x-r0.yml index d81acd37..ca4037b2 100644 --- a/packages/platforms/accton/powerpc/powerpc-accton-as5610-52x/platform-config/r0/src/lib/powerpc-accton-as5610-52x-r0.yml +++ b/packages/platforms/accton/powerpc/powerpc-accton-as5610-52x/platform-config/r0/src/lib/powerpc-accton-as5610-52x-r0.yml @@ -40,8 +40,8 @@ powerpc-accton-as5610-52x-r0: =: 100% format: ext4 - network: - interfaces: - ma1: - name: ~ - syspath: soc.0/ff724000.ethernet + ##network: + ## interfaces: + ## ma1: + ## name: ~ + ## syspath: soc.0/ff724000.ethernet diff --git a/packages/platforms/accton/powerpc/powerpc-accton-as5710-54x/platform-config/r0/src/lib/powerpc-accton-as5710-54x-r0.yml b/packages/platforms/accton/powerpc/powerpc-accton-as5710-54x/platform-config/r0/src/lib/powerpc-accton-as5710-54x-r0.yml index 3f610df6..f30782be 100644 --- a/packages/platforms/accton/powerpc/powerpc-accton-as5710-54x/platform-config/r0/src/lib/powerpc-accton-as5710-54x-r0.yml +++ b/packages/platforms/accton/powerpc/powerpc-accton-as5710-54x/platform-config/r0/src/lib/powerpc-accton-as5710-54x-r0.yml @@ -40,8 +40,8 @@ powerpc-accton-as5710-54x-r0: =: 100% format: ext4 - network: - interfaces: - ma1: - name: ~ - syspath: fsl,dpaa.16/ethernet.17 + ##network: + ## interfaces: + ## ma1: + ## name: ~ + ## syspath: fsl,dpaa.16/ethernet.17 diff --git a/packages/platforms/accton/powerpc/powerpc-accton-as5710-54x/platform-config/r0b/src/lib/powerpc-accton-as5710-54x-r0b.yml b/packages/platforms/accton/powerpc/powerpc-accton-as5710-54x/platform-config/r0b/src/lib/powerpc-accton-as5710-54x-r0b.yml index ca2a066c..f940bd38 100644 --- a/packages/platforms/accton/powerpc/powerpc-accton-as5710-54x/platform-config/r0b/src/lib/powerpc-accton-as5710-54x-r0b.yml +++ b/packages/platforms/accton/powerpc/powerpc-accton-as5710-54x/platform-config/r0b/src/lib/powerpc-accton-as5710-54x-r0b.yml @@ -25,8 +25,8 @@ powerpc-accton-as5710-54x-r0b: device: /dev/sda nos_bootcmds: *usb_bootcmds - network: - interfaces: - ma1: - name: ~ - syspath: fsl,dpaa.16/ethernet.17 + ##network: + ## interfaces: + ## ma1: + ## name: ~ + ## syspath: fsl,dpaa.16/ethernet.17 diff --git a/packages/platforms/accton/powerpc/powerpc-accton-as6700-32x/platform-config/r0/src/lib/powerpc-accton-as6700-32x-r0.yml b/packages/platforms/accton/powerpc/powerpc-accton-as6700-32x/platform-config/r0/src/lib/powerpc-accton-as6700-32x-r0.yml index 570843ec..b7ee33b1 100644 --- a/packages/platforms/accton/powerpc/powerpc-accton-as6700-32x/platform-config/r0/src/lib/powerpc-accton-as6700-32x-r0.yml +++ b/packages/platforms/accton/powerpc/powerpc-accton-as6700-32x/platform-config/r0/src/lib/powerpc-accton-as6700-32x-r0.yml @@ -40,8 +40,8 @@ powerpc-accton-as6700-32x-r0: =: 100% format: ext4 - network: - interfaces: - ma1: - name: ~ - syspath: fsl,dpaa.16/ethernet.18 + ##network: + ## interfaces: + ## ma1: + ## name: ~ + ## syspath: fsl,dpaa.16/ethernet.18 diff --git a/packages/platforms/accton/powerpc/powerpc-accton-as6700-32x/platform-config/r1/src/lib/powerpc-accton-as6700-32x-r1.yml b/packages/platforms/accton/powerpc/powerpc-accton-as6700-32x/platform-config/r1/src/lib/powerpc-accton-as6700-32x-r1.yml index f6d5c232..249fa0f5 100644 --- a/packages/platforms/accton/powerpc/powerpc-accton-as6700-32x/platform-config/r1/src/lib/powerpc-accton-as6700-32x-r1.yml +++ b/packages/platforms/accton/powerpc/powerpc-accton-as6700-32x/platform-config/r1/src/lib/powerpc-accton-as6700-32x-r1.yml @@ -40,8 +40,8 @@ powerpc-accton-as6700-32x-r1: =: 100% format: ext4 - network: - interfaces: - ma1: - name: ~ - syspath: fsl,dpaa.16/ethernet.18 + ##network: + ## interfaces: + ## ma1: + ## name: ~ + ## syspath: fsl,dpaa.16/ethernet.18 diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as5512-54x/platform-config/r0/src/lib/x86-64-accton-as5512-54x-r0.yml b/packages/platforms/accton/x86-64/x86-64-accton-as5512-54x/platform-config/r0/src/lib/x86-64-accton-as5512-54x-r0.yml index 0cdb6fca..2c31c65a 100644 --- a/packages/platforms/accton/x86-64/x86-64-accton-as5512-54x/platform-config/r0/src/lib/x86-64-accton-as5512-54x-r0.yml +++ b/packages/platforms/accton/x86-64/x86-64-accton-as5512-54x/platform-config/r0/src/lib/x86-64-accton-as5512-54x-r0.yml @@ -24,8 +24,8 @@ x86-64-accton-as5512-54x-r0: nopat console=ttyS1,115200n8 - network - interfaces: - ma1: - name: ~ - syspath: pci0000:00/0000:00:14.0 + ##network + ## interfaces: + ## ma1: + ## name: ~ + ## syspath: pci0000:00/0000:00:14.0 diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as5712-54x/platform-config/r0/src/lib/x86-64-accton-as5712-54x-r0.yml b/packages/platforms/accton/x86-64/x86-64-accton-as5712-54x/platform-config/r0/src/lib/x86-64-accton-as5712-54x-r0.yml index 29ce9bef..fa4eea34 100644 --- a/packages/platforms/accton/x86-64/x86-64-accton-as5712-54x/platform-config/r0/src/lib/x86-64-accton-as5712-54x-r0.yml +++ b/packages/platforms/accton/x86-64/x86-64-accton-as5712-54x/platform-config/r0/src/lib/x86-64-accton-as5712-54x-r0.yml @@ -24,8 +24,8 @@ x86-64-accton-as5712-54x-r0: nopat console=ttyS1,115200n8 - network - interfaces: - ma1: - name: ~ - syspath: pci0000:00/0000:00:14.0 + ##network + ## interfaces: + ## ma1: + ## name: ~ + ## syspath: pci0000:00/0000:00:14.0 diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as5812-54t/platform-config/r0/src/lib/x86-64-accton-as5812-54t-r0.yml b/packages/platforms/accton/x86-64/x86-64-accton-as5812-54t/platform-config/r0/src/lib/x86-64-accton-as5812-54t-r0.yml index 4bfc8909..a88f81cf 100644 --- a/packages/platforms/accton/x86-64/x86-64-accton-as5812-54t/platform-config/r0/src/lib/x86-64-accton-as5812-54t-r0.yml +++ b/packages/platforms/accton/x86-64/x86-64-accton-as5812-54t/platform-config/r0/src/lib/x86-64-accton-as5812-54t-r0.yml @@ -24,8 +24,8 @@ x86-64-accton-as5812-54t-r0: nopat console=ttyS1,115200n8 - network - interfaces: - ma1: - name: ~ - syspath: pci0000:00/0000:00:14.0 + ##network + ## interfaces: + ## ma1: + ## name: ~ + ## syspath: pci0000:00/0000:00:14.0 diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as5812-54x/platform-config/r0/src/lib/x86-64-accton-as5812-54x-r0.yml b/packages/platforms/accton/x86-64/x86-64-accton-as5812-54x/platform-config/r0/src/lib/x86-64-accton-as5812-54x-r0.yml index 7e4f4230..95817d8a 100644 --- a/packages/platforms/accton/x86-64/x86-64-accton-as5812-54x/platform-config/r0/src/lib/x86-64-accton-as5812-54x-r0.yml +++ b/packages/platforms/accton/x86-64/x86-64-accton-as5812-54x/platform-config/r0/src/lib/x86-64-accton-as5812-54x-r0.yml @@ -24,8 +24,8 @@ x86-64-accton-as5812-54x-r0: nopat console=ttyS1,115200n8 - network - interfaces: - ma1: - name: ~ - syspath: pci0000:00/0000:00:14.0 + ##network + ## interfaces: + ## ma1: + ## name: ~ + ## syspath: pci0000:00/0000:00:14.0 diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as6712-32x/platform-config/r0/src/lib/x86-64-accton-as6712-32x-r0.yml b/packages/platforms/accton/x86-64/x86-64-accton-as6712-32x/platform-config/r0/src/lib/x86-64-accton-as6712-32x-r0.yml index 7d358255..b3310b8d 100644 --- a/packages/platforms/accton/x86-64/x86-64-accton-as6712-32x/platform-config/r0/src/lib/x86-64-accton-as6712-32x-r0.yml +++ b/packages/platforms/accton/x86-64/x86-64-accton-as6712-32x/platform-config/r0/src/lib/x86-64-accton-as6712-32x-r0.yml @@ -24,8 +24,8 @@ x86-64-accton-as6712-32x-r0: nopat console=ttyS1,115200n8 - network - interfaces: - ma1: - name: ~ - syspath: pci0000:00/0000:00:14.0 + ##network + ## interfaces: + ## ma1: + ## name: ~ + ## syspath: pci0000:00/0000:00:14.0 diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as6812-32x/platform-config/r0/src/lib/x86-64-accton-as6812-32x-r0.yml b/packages/platforms/accton/x86-64/x86-64-accton-as6812-32x/platform-config/r0/src/lib/x86-64-accton-as6812-32x-r0.yml index 3eccc8bf..a7b75803 100644 --- a/packages/platforms/accton/x86-64/x86-64-accton-as6812-32x/platform-config/r0/src/lib/x86-64-accton-as6812-32x-r0.yml +++ b/packages/platforms/accton/x86-64/x86-64-accton-as6812-32x/platform-config/r0/src/lib/x86-64-accton-as6812-32x-r0.yml @@ -24,8 +24,8 @@ x86-64-accton-as6812-32x-r0: nopat console=ttyS1,115200n8 - network - interfaces: - ma1: - name: ~ - syspath: pci0000:00/0000:00:14.0 + ##network + ## interfaces: + ## ma1: + ## name: ~ + ## syspath: pci0000:00/0000:00:14.0 diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as7512-32x/platform-config/r0/src/lib/x86-64-accton-as7512-32x-r0.yml b/packages/platforms/accton/x86-64/x86-64-accton-as7512-32x/platform-config/r0/src/lib/x86-64-accton-as7512-32x-r0.yml index 319e4db2..4f4c51ce 100644 --- a/packages/platforms/accton/x86-64/x86-64-accton-as7512-32x/platform-config/r0/src/lib/x86-64-accton-as7512-32x-r0.yml +++ b/packages/platforms/accton/x86-64/x86-64-accton-as7512-32x/platform-config/r0/src/lib/x86-64-accton-as7512-32x-r0.yml @@ -24,8 +24,8 @@ x86-64-accton-as5712-32x-r0: nopat console=ttyS1,115200n8 - network - interfaces: - ma1: - name: ~ - syspath: pci0000:00/0000:00:14.0 + ##network + ## interfaces: + ## ma1: + ## name: ~ + ## syspath: pci0000:00/0000:00:14.0 diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as7712-32x/platform-config/r0/src/lib/x86-64-accton-as7712-32x-r0.yml b/packages/platforms/accton/x86-64/x86-64-accton-as7712-32x/platform-config/r0/src/lib/x86-64-accton-as7712-32x-r0.yml index 83e1d05d..1220adf4 100644 --- a/packages/platforms/accton/x86-64/x86-64-accton-as7712-32x/platform-config/r0/src/lib/x86-64-accton-as7712-32x-r0.yml +++ b/packages/platforms/accton/x86-64/x86-64-accton-as7712-32x/platform-config/r0/src/lib/x86-64-accton-as7712-32x-r0.yml @@ -24,8 +24,8 @@ x86-64-accton-as7712-32x-r0: nopat console=ttyS1,115200n8 - network - interfaces: - ma1: - name: ~ - syspath: pci0000:00/0000:00:14.0 + ##network + ## interfaces: + ## ma1: + ## name: ~ + ## syspath: pci0000:00/0000:00:14.0 diff --git a/packages/platforms/accton/x86-64/x86-64-accton-wedge-16x/platform-config/r0/src/lib/x86-64-accton-wedge-16x-r0.yml b/packages/platforms/accton/x86-64/x86-64-accton-wedge-16x/platform-config/r0/src/lib/x86-64-accton-wedge-16x-r0.yml index dc009fbb..1c42ce71 100644 --- a/packages/platforms/accton/x86-64/x86-64-accton-wedge-16x/platform-config/r0/src/lib/x86-64-accton-wedge-16x-r0.yml +++ b/packages/platforms/accton/x86-64/x86-64-accton-wedge-16x/platform-config/r0/src/lib/x86-64-accton-wedge-16x-r0.yml @@ -27,8 +27,8 @@ x86-64-accton-wedge-16x-r0: rd_NO_LUKS intel_iommu=off - network - interfaces: - ma1: - name: ~ - syspath: pci0000:00/0000:00:14.0 + ##network + ## interfaces: + ## ma1: + ## name: ~ + ## syspath: pci0000:00/0000:00:14.0 diff --git a/packages/platforms/celestica/x86-64/x86-64-cel-redstone-xp/platform-config/r0/src/lib/x86-64-cel-redstone-xp-r0.yml b/packages/platforms/celestica/x86-64/x86-64-cel-redstone-xp/platform-config/r0/src/lib/x86-64-cel-redstone-xp-r0.yml index b3efd7ec..76c1455d 100644 --- a/packages/platforms/celestica/x86-64/x86-64-cel-redstone-xp/platform-config/r0/src/lib/x86-64-cel-redstone-xp-r0.yml +++ b/packages/platforms/celestica/x86-64/x86-64-cel-redstone-xp/platform-config/r0/src/lib/x86-64-cel-redstone-xp-r0.yml @@ -24,8 +24,8 @@ x86-64-cel-redstone-xp-r0: nopat console=ttyS0,115200n8 - network: - interfaces: - ma1: - name: ~ - syspath: pci0000:00/0000:00:14.0 + ##network: + ## interfaces: + ## ma1: + ## name: ~ + ## syspath: pci0000:00/0000:00:14.0 diff --git a/packages/platforms/kvm/x86-64/x86-64-kvm-x86-64/platform-config/r0/src/lib/x86-64-kvm-x86-64-r0.yml b/packages/platforms/kvm/x86-64/x86-64-kvm-x86-64/platform-config/r0/src/lib/x86-64-kvm-x86-64-r0.yml index 9f7a641c..e20a30ab 100644 --- a/packages/platforms/kvm/x86-64/x86-64-kvm-x86-64/platform-config/r0/src/lib/x86-64-kvm-x86-64-r0.yml +++ b/packages/platforms/kvm/x86-64/x86-64-kvm-x86-64/platform-config/r0/src/lib/x86-64-kvm-x86-64-r0.yml @@ -24,8 +24,8 @@ x86-64-kvm-x86-64-r0: nopat console=ttyS0,115200n8 - network - interfaces: - ma1: - name: ~ - syspath: pci0000:00/0000:00:03.0 + ##network + ## interfaces: + ## ma1: + ## name: ~ + ## syspath: pci0000:00/0000:00:03.0 diff --git a/packages/platforms/quanta/powerpc/powerpc-quanta-lb9/platform-config/r0/src/lib/powerpc-quanta-lb9-r0.yml b/packages/platforms/quanta/powerpc/powerpc-quanta-lb9/platform-config/r0/src/lib/powerpc-quanta-lb9-r0.yml index 170b83a9..5e6528cd 100644 --- a/packages/platforms/quanta/powerpc/powerpc-quanta-lb9/platform-config/r0/src/lib/powerpc-quanta-lb9-r0.yml +++ b/packages/platforms/quanta/powerpc/powerpc-quanta-lb9/platform-config/r0/src/lib/powerpc-quanta-lb9-r0.yml @@ -26,8 +26,8 @@ powerpc-quanta-lb9-r0: env_size: 0x00002000 sector_size: 0x00020000 - network: - interfaces: - ma1: - name: ~ - syspath: e0000000.soc8541/e0024000.ethernet + ##network: + ## interfaces: + ## ma1: + ## name: ~ + ## syspath: e0000000.soc8541/e0024000.ethernet diff --git a/packages/platforms/quanta/powerpc/powerpc-quanta-ly2/platform-config/r0/src/lib/powerpc-quanta-ly2-r0.yml b/packages/platforms/quanta/powerpc/powerpc-quanta-ly2/platform-config/r0/src/lib/powerpc-quanta-ly2-r0.yml index 29626424..47231061 100644 --- a/packages/platforms/quanta/powerpc/powerpc-quanta-ly2/platform-config/r0/src/lib/powerpc-quanta-ly2-r0.yml +++ b/packages/platforms/quanta/powerpc/powerpc-quanta-ly2/platform-config/r0/src/lib/powerpc-quanta-ly2-r0.yml @@ -26,8 +26,8 @@ powerpc-quanta-ly2-r0: env_size: 0x00002000 sector_size: 0x00020000 - network - interfaces: - ma1: - name: ~ - syspath: soc.0/ffe24000.ethernet + ##network + ## interfaces: + ## ma1: + ## name: ~ + ## syspath: soc.0/ffe24000.ethernet diff --git a/packages/platforms/quanta/x86-64/x86-64-quanta-ly6-rangeley/platform-config/r0/src/lib/x86-64-quanta-ly6-rangeley-r0.yml b/packages/platforms/quanta/x86-64/x86-64-quanta-ly6-rangeley/platform-config/r0/src/lib/x86-64-quanta-ly6-rangeley-r0.yml index ecd6b139..0d6cc8f9 100644 --- a/packages/platforms/quanta/x86-64/x86-64-quanta-ly6-rangeley/platform-config/r0/src/lib/x86-64-quanta-ly6-rangeley-r0.yml +++ b/packages/platforms/quanta/x86-64/x86-64-quanta-ly6-rangeley/platform-config/r0/src/lib/x86-64-quanta-ly6-rangeley-r0.yml @@ -23,8 +23,8 @@ x86-64-quanta-ly6-rangeley-r0: args: >- console=ttyS1,115200n8 - network: - interfaces: - ma1: - name: ~ - syspath: pci0000:00/0000:00:14.0 + ##network: + ## interfaces: + ## ma1: + ## name: ~ + ## syspath: pci0000:00/0000:00:14.0 diff --git a/packages/platforms/quanta/x86-64/x86-64-quanta-ly8-rangeley/platform-config/r0/src/lib/x86-64-quanta-ly8-rangeley-r0.yml b/packages/platforms/quanta/x86-64/x86-64-quanta-ly8-rangeley/platform-config/r0/src/lib/x86-64-quanta-ly8-rangeley-r0.yml index 24bd1298..d6d78f2a 100644 --- a/packages/platforms/quanta/x86-64/x86-64-quanta-ly8-rangeley/platform-config/r0/src/lib/x86-64-quanta-ly8-rangeley-r0.yml +++ b/packages/platforms/quanta/x86-64/x86-64-quanta-ly8-rangeley/platform-config/r0/src/lib/x86-64-quanta-ly8-rangeley-r0.yml @@ -23,8 +23,8 @@ x86-64-quanta-ly8-rangeley-r0: args: >- console=ttyS1,115200n8 - network: - interfaces: - ma1: - name: ~ - syspath: pci0000:00/0000:00:14.0 + ##network: + ## interfaces: + ## ma1: + ## name: ~ + ## syspath: pci0000:00/0000:00:14.0 From 8d27402a3dd1ad46f5c9d51d7007d8057fea6459 Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Thu, 19 May 2016 11:30:20 -0700 Subject: [PATCH 084/113] loader init files depend on onl-vendor-config-onl --- packages/base/all/initrds/loader-initrd-files/PKG.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/base/all/initrds/loader-initrd-files/PKG.yml b/packages/base/all/initrds/loader-initrd-files/PKG.yml index 9b8e7022..79489347 100644 --- a/packages/base/all/initrds/loader-initrd-files/PKG.yml +++ b/packages/base/all/initrds/loader-initrd-files/PKG.yml @@ -6,6 +6,7 @@ common: packages: - name: onl-loader-initrd-files + depends: [ onl-vendor-config-onl ] version: 1.0.0 summary: Open Network Linux System Loader Source Files From 1cd5a85fd9a155f292980f334c4a8edb917652e5 Mon Sep 17 00:00:00 2001 From: Jeffrey Townsend Date: Fri, 20 May 2016 00:02:59 +0000 Subject: [PATCH 085/113] Add YAML output files. --- tools/make-versions.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tools/make-versions.py b/tools/make-versions.py index a5c0ae17..2813c44e 100755 --- a/tools/make-versions.py +++ b/tools/make-versions.py @@ -56,6 +56,12 @@ class OnlVersionsGenerator(object): with open(fname, "w") as f: json.dump(data, f, indent=2) + # YAML + fname = os.path.join(self.ops.output_dir, basename + '.yml') + if not os.path.exists(fname) or self.ops.force: + with open(fname, "w") as f: + yaml.dump(data, f, default_flow_style=False) + # mk fname = os.path.join(self.ops.output_dir, basename + '.mk') if not os.path.exists(fname) or self.ops.force: From 4158ab47c8a1fc2216e1c15d3cdbb2ff05fce9c1 Mon Sep 17 00:00:00 2001 From: Jeffrey Townsend Date: Fri, 20 May 2016 00:03:32 +0000 Subject: [PATCH 086/113] - Move version files to versions directory. - Remove ENV_JSON option in favor of explicit includes in necessary packages files. --- setup.env | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/setup.env b/setup.env index ed0ae4a9..5c05029b 100755 --- a/setup.env +++ b/setup.env @@ -23,10 +23,7 @@ export PATH="$ONL/tools/scripts:$ONL/tools:$PATH" export ONL_MAKE_PARALLEL=-j16 # Version files -$ONL/tools/make-versions.py --import-file=$ONL/tools/onlvi --class-name=OnlVersionImplementation --output-dir $ONL/make - -# Make version values available in the package environment -export ONLPM_OPTION_INCLUDE_ENV_JSON="$ONL/make/version-onl.json" +$ONL/tools/make-versions.py --import-file=$ONL/tools/onlvi --class-name=OnlVersionImplementation --output-dir $ONL/make/versions # # buildroot download mirror. We suggest you setup a local repository containing these contents for faster local builds. @@ -41,6 +38,6 @@ $ONL/tools/submodules.py $ONL sm/bigcode export ONL_DEBIAN_SUITE=$(lsb_release -c -s) # Enable local post-merge githook -if [ ! -f $ONL/.git/hooks/post-merge ]; then +if [ ! -f $ONL/.git/hooks/post-merge ] && [ -d $ONL/.git ]; then cp $ONL/tools/scripts/post-merge.hook $ONL/.git/hooks/post-merge fi From 647e9d3bef44c51a49f95606bd9592a555f78041 Mon Sep 17 00:00:00 2001 From: Jeffrey Townsend Date: Fri, 20 May 2016 00:07:26 +0000 Subject: [PATCH 087/113] Mount ONL-BOOT read-write by default. --- packages/base/all/initrds/loader-initrd-files/src/etc/mtab.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/base/all/initrds/loader-initrd-files/src/etc/mtab.yml b/packages/base/all/initrds/loader-initrd-files/src/etc/mtab.yml index 00f64685..8026f979 100644 --- a/packages/base/all/initrds/loader-initrd-files/src/etc/mtab.yml +++ b/packages/base/all/initrds/loader-initrd-files/src/etc/mtab.yml @@ -14,6 +14,6 @@ mounts: fsck: true ONL-BOOT: - mount: r + mount: w dir: /mnt/onl/boot fsck: false From 95997e7983decebf25ac4eae45dd406ef2eb583b Mon Sep 17 00:00:00 2001 From: Jeffrey Townsend Date: Fri, 20 May 2016 00:08:16 +0000 Subject: [PATCH 088/113] Use the system boot-config from /mnt/onl/boot/boot-config if present. If not, use system default /etc/onl/boot-config-default if present. --- .../base/all/initrds/loader-initrd-files/src/bin/sysinit | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/base/all/initrds/loader-initrd-files/src/bin/sysinit b/packages/base/all/initrds/loader-initrd-files/src/bin/sysinit index 07b1f2e3..5a42b204 100755 --- a/packages/base/all/initrds/loader-initrd-files/src/bin/sysinit +++ b/packages/base/all/initrds/loader-initrd-files/src/bin/sysinit @@ -76,7 +76,13 @@ if [ ! -f /etc/onl/abort ]; then cat /etc/issue fi - [ ! -f /mnt/onl/boot/boot-config ] || cat /mnt/onl/boot/boot-config >>/etc/onl/boot-config + if [ -f /mnt/onl/boot/boot-config ]; then + # Use local boot-config. + cp /mnt/onl/boot/boot-config /etc/onl/boot-config + elif [ -f /etc/onl/boot-config-default ]; then + # Use default boot-config. + cp /etc/onl/boot-config-default /etc/onl/boot-config + fi # # Initialize the /mnt/flash/boot area. From dd4ebb7904cba5feae11c4531bc13bbcbba5e9b0 Mon Sep 17 00:00:00 2001 From: Jeffrey Townsend Date: Fri, 20 May 2016 00:09:24 +0000 Subject: [PATCH 089/113] Support possible dynamic generation of the boot-config if not present. --- packages/base/all/initrds/loader-initrd-files/src/bin/banner | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/base/all/initrds/loader-initrd-files/src/bin/banner b/packages/base/all/initrds/loader-initrd-files/src/bin/banner index bcd344c0..546872ed 100755 --- a/packages/base/all/initrds/loader-initrd-files/src/bin/banner +++ b/packages/base/all/initrds/loader-initrd-files/src/bin/banner @@ -23,11 +23,10 @@ field "$ONL_PLATFORM" " Platform: $ONL_PLATFORM" field "MA1_ADDR" " ma1: $MA1_ADDR" echo "*" echo "************************************************************" -if [ -f /etc/onl/boot-config ]; then +if [ -s /etc/onl/boot-config ]; then msg_info "boot-config" cat /etc/onl/boot-config else - if [ -f /bin/boot-config.py ]; then if /bin/boot-config.py configure; then echo "The system will now reboot to apply your configuration." @@ -36,7 +35,7 @@ else echo "The boot-config script failed." >> /etc/onl/abort fi else - msg_info "No boot-config" + echo "No boot-config." >> /etc/onl/abort fi fi From 70327a396e39324bb73402d7d5103272736b9ae3 Mon Sep 17 00:00:00 2001 From: Jeffrey Townsend Date: Fri, 20 May 2016 00:10:26 +0000 Subject: [PATCH 090/113] Generate the version files if necessary. This is to support inclusion in a superproject which does not use the local setup.env. --- make/config.mk | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/make/config.mk b/make/config.mk index 215be80c..cd957fba 100644 --- a/make/config.mk +++ b/make/config.mk @@ -29,6 +29,10 @@ export BUILD_DIR_BASE=BUILD/$(ONL_DEBIAN_SUITE) # Generate manifest if necessary export MODULEMANIFEST := $(shell $(BUILDER)/tools/mmg.py --dirs $(ONL) $(ONLPM_OPTION_PACKAGEDIRS) --out $(ONL)/make/module-manifest.mk --only-if-missing make) +# Generate versions if necessary. +$(shell $(ONL)/tools/make-versions.py --import-file=$(ONL)/tools/onlvi --class-name=OnlVersionImplementation --output-dir $(ONL)/make/versions) + + # # Default make options. # From f7e3d54e721d9296bc65fa44bb380b8f25f5abb2 Mon Sep 17 00:00:00 2001 From: Jeffrey Townsend Date: Fri, 20 May 2016 00:11:43 +0000 Subject: [PATCH 091/113] Removed. --- make/Makefile | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 make/Makefile diff --git a/make/Makefile b/make/Makefile deleted file mode 100644 index d7a2afeb..00000000 --- a/make/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -############################################################ -# -# Convenience makefile for generating -# the local version variables. -# -versions.env: - $(ONL_V_at) $(MAKE) -f versions.mk ONL_VERSION_ENV_FILE=versions.env - From dd93bf58bdf9a30227209bfedbff660bb6f94e7f Mon Sep 17 00:00:00 2001 From: Jeffrey Townsend Date: Fri, 20 May 2016 00:12:18 +0000 Subject: [PATCH 092/113] Version ignore. --- make/.gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/make/.gitignore b/make/.gitignore index d6850c00..4bf19b41 100644 --- a/make/.gitignore +++ b/make/.gitignore @@ -1,3 +1,3 @@ -version-onl.* +versions/ module-manifest.mk From 9057eb80e25c5b6cf8a2c4479c65f084101e3cb8 Mon Sep 17 00:00:00 2001 From: Jeffrey Townsend Date: Fri, 20 May 2016 01:25:36 +0000 Subject: [PATCH 093/113] Version files moved. --- builds/amd64/installer/legacy/builds/Makefile | 4 ++-- builds/any/installer/grub/builds/Makefile | 4 ++-- builds/any/installer/legacy/fit/builds/Makefile | 4 ++-- builds/any/installer/uboot/builds/Makefile | 4 ++-- builds/any/rootfs/jessie/standard/standard.yml | 2 +- builds/any/rootfs/wheezy/standard/standard.yml | 2 +- packages/base/all/initrds/loader-initrd-files/PKG.yml | 8 ++++---- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/builds/amd64/installer/legacy/builds/Makefile b/builds/amd64/installer/legacy/builds/Makefile index c32b3bce..e5c06989 100644 --- a/builds/amd64/installer/legacy/builds/Makefile +++ b/builds/amd64/installer/legacy/builds/Makefile @@ -13,7 +13,7 @@ MKSHAR_PERMS = autoperms.sh # Hardcoded to match ONL File naming conventions. -include $(ONL)/make/version-onl.mk +include $(ONL)/make/versions/version-onl.mk INSTALLER_NAME=$(FNAME_PRODUCT_VERSION)_ONL-OS_$(FNAME_BUILD_ID)_$(UARCH)_LEGACY_INSTALLER @@ -28,7 +28,7 @@ __installer: mv ./usr/share/onl/packages/amd64/onl-swi/*.swi . rm -rf ./usr $(ONL_V_at)cp /dev/null $(MKSHAR_PERMS) - $(ONL_V_at) cp $(ONL)/make/version-onl.sh . + $(ONL_V_at) cp $(ONL)/make/versions/version-onl.sh . $(ONL_V_at)echo "#!/bin/sh" >> $(MKSHAR_PERMS) $(ONL_V_at)echo "set -e" >> $(MKSHAR_PERMS) $(ONL_V_at)echo "set -x" >> $(MKSHAR_PERMS) diff --git a/builds/any/installer/grub/builds/Makefile b/builds/any/installer/grub/builds/Makefile index 99be574f..2d1e55a6 100644 --- a/builds/any/installer/grub/builds/Makefile +++ b/builds/any/installer/grub/builds/Makefile @@ -10,7 +10,7 @@ MKSHAR_OPTS = --lazy --unzip-pad --fixup-perms autoperms.sh MKSHAR_PERMS = autoperms.sh # Hardcoded to match ONL File naming conventions. -include $(ONL)/make/version-onl.mk +include $(ONL)/make/versions/version-onl.mk INSTALLER_NAME=$(FNAME_PRODUCT_VERSION)_ONL-OS_$(FNAME_BUILD_ID)_$(UARCH)_INSTALLER ifeq ($(ARCH), amd64) @@ -36,7 +36,7 @@ __installer: __installer_platform_files __installer_swi_files >> installer.sh $(ONL_V_at)echo "PAYLOAD_FOLLOWS" >> installer.sh $(ONL_V_at)cp /dev/null $(MKSHAR_PERMS) - $(ONL_V_at)cp $(ONL)/make/version-onl.sh . + $(ONL_V_at)cp $(ONL)/make/versions/version-onl.sh . $(ONL_V_at)echo "#!/bin/sh" >> $(MKSHAR_PERMS) $(ONL_V_at)echo "set -e" >> $(MKSHAR_PERMS) $(ONL_V_at)echo "set -x" >> $(MKSHAR_PERMS) diff --git a/builds/any/installer/legacy/fit/builds/Makefile b/builds/any/installer/legacy/fit/builds/Makefile index ce7e1c65..7052ebab 100644 --- a/builds/any/installer/legacy/fit/builds/Makefile +++ b/builds/any/installer/legacy/fit/builds/Makefile @@ -5,7 +5,7 @@ endif THISDIR := $(dir $(lastword $(MAKEFILE_LIST))) # Hardcoded to match ONL File naming conventions. -include $(ONL)/make/version-onl.mk +include $(ONL)/make/versions/version-onl.mk INSTALLER_NAME=$(FNAME_PRODUCT_VERSION)_ONL-OS_$(FNAME_BUILD_ID)_$(UARCH)_LEGACY_INSTALLER FIT_IMAGE_ALL := $(shell $(ONLPM) --find-file onl-loader-fit:$(ARCH) onl-loader-fit.itb) @@ -28,7 +28,7 @@ ifndef NO_SWI endif rm -rf ./usr $(ONL_V_at)cp /dev/null $(MKSHAR_PERMS) - $(ONL_V_at) cp $(ONL)/make/version-onl.sh . + $(ONL_V_at) cp $(ONL)/make/versions/version-onl.sh . $(ONL_V_at)echo "#!/bin/sh" >> $(MKSHAR_PERMS) $(ONL_V_at)echo "set -e" >> $(MKSHAR_PERMS) $(ONL_V_at)echo "set -x" >> $(MKSHAR_PERMS) diff --git a/builds/any/installer/uboot/builds/Makefile b/builds/any/installer/uboot/builds/Makefile index ea5ad357..eae9c217 100644 --- a/builds/any/installer/uboot/builds/Makefile +++ b/builds/any/installer/uboot/builds/Makefile @@ -14,7 +14,7 @@ PYFIT = $(VONLDIR)/src/bin/pyfit PYFIT_ENVIRONMENT = PYTHONPATH=$(VONLDIR)/src/python # Hardcoded to match ONL File naming conventions. -include $(ONL)/make/version-onl.mk +include $(ONL)/make/versions/version-onl.mk INSTALLER_NAME=$(FNAME_PRODUCT_VERSION)_ONL-OS_$(FNAME_BUILD_ID)_$(UARCH)_INSTALLER # default fit image can be used as the canonical location for the initrd @@ -25,7 +25,7 @@ INITRD_BOUNDS := $(shell $(PYFIT_ENVIRONMENT) $(PYFIT) -v offset $(FIT_IMAGE_ALL __installer: installer.sh __installer_fit_files __installer_platform_files __installer_swi_files $(ONL_V_at)rm -rf *INSTALLER* *.md5sum $(ONL_V_at)cp /dev/null $(MKSHAR_PERMS) - $(ONL_V_at)cp $(ONL)/make/version-onl.sh . + $(ONL_V_at)cp $(ONL)/make/versions/version-onl.sh . $(ONL_V_at)echo "#!/bin/sh" >> $(MKSHAR_PERMS) $(ONL_V_at)echo "set -e" >> $(MKSHAR_PERMS) $(ONL_V_at)echo "set -x" >> $(MKSHAR_PERMS) diff --git a/builds/any/rootfs/jessie/standard/standard.yml b/builds/any/rootfs/jessie/standard/standard.yml index 7266fa7d..c3b22d8e 100644 --- a/builds/any/rootfs/jessie/standard/standard.yml +++ b/builds/any/rootfs/jessie/standard/standard.yml @@ -89,5 +89,5 @@ Configure: password: onl manifest: - version: $ONL/make/version-onl.json + version: $ONL/make/versions/version-onl.json platforms: $PLATFORM_LIST diff --git a/builds/any/rootfs/wheezy/standard/standard.yml b/builds/any/rootfs/wheezy/standard/standard.yml index f7f04c32..1ba7a3d4 100644 --- a/builds/any/rootfs/wheezy/standard/standard.yml +++ b/builds/any/rootfs/wheezy/standard/standard.yml @@ -91,5 +91,5 @@ Configure: password: onl manifest: - version: $ONL/make/version-onl.json + version: $ONL/make/versions/version-onl.json platforms: $PLATFORM_LIST diff --git a/packages/base/all/initrds/loader-initrd-files/PKG.yml b/packages/base/all/initrds/loader-initrd-files/PKG.yml index 3ae21ef7..09237084 100644 --- a/packages/base/all/initrds/loader-initrd-files/PKG.yml +++ b/packages/base/all/initrds/loader-initrd-files/PKG.yml @@ -15,10 +15,10 @@ packages: - src/lib : /lib - src/bootmodes : /bootmodes - src/python: /usr/lib/python2.7/site-packages - - $ONL/make/version-onl.sh : /etc/onl/loader/versions.sh - - $ONL/make/version-onl.json : /etc/onl/loader/versions.json - - $ONL/make/version-onl.mk : /etc/onl/loader/versions.mk - + - $ONL/make/versions/version-onl.sh : /etc/onl/loader/versions.sh + - $ONL/make/versions/version-onl.json : /etc/onl/loader/versions.json + - $ONL/make/versions/version-onl.mk : /etc/onl/loader/versions.mk + changelog: Change changes changes., From 4bfad168fbb0cf9f665b51726448b9688a9e339f Mon Sep 17 00:00:00 2001 From: Jeffrey Townsend Date: Fri, 20 May 2016 01:25:48 +0000 Subject: [PATCH 094/113] Include the version files contents as PKG variables. --- builds/any/installer/APKG.yml | 2 ++ builds/any/installer/legacy/APKG.yml | 2 ++ builds/any/rootfs/APKG.yml | 3 +++ builds/any/swi/APKG.yml | 2 ++ 4 files changed, 9 insertions(+) diff --git a/builds/any/installer/APKG.yml b/builds/any/installer/APKG.yml index 62ad5191..4c96a4f9 100644 --- a/builds/any/installer/APKG.yml +++ b/builds/any/installer/APKG.yml @@ -1,3 +1,5 @@ +variables: + !include $ONL/make/versions/version-onl.yml prerequisites: broken: true diff --git a/builds/any/installer/legacy/APKG.yml b/builds/any/installer/legacy/APKG.yml index a53d0129..26106bd6 100644 --- a/builds/any/installer/legacy/APKG.yml +++ b/builds/any/installer/legacy/APKG.yml @@ -1,3 +1,5 @@ +variables: + !include $ONL/make/versions/version-onl.yml prerequisites: broken: true diff --git a/builds/any/rootfs/APKG.yml b/builds/any/rootfs/APKG.yml index 114d10c2..7a716da9 100644 --- a/builds/any/rootfs/APKG.yml +++ b/builds/any/rootfs/APKG.yml @@ -1,3 +1,6 @@ +variables: + !include $ONL/make/versions/version-onl.yml + prerequisites: broken: true diff --git a/builds/any/swi/APKG.yml b/builds/any/swi/APKG.yml index c7ca8ea1..8d87930b 100644 --- a/builds/any/swi/APKG.yml +++ b/builds/any/swi/APKG.yml @@ -1,3 +1,5 @@ +variables: + !include $ONL/make/versions/version-onl.yml prerequisites: broken: true From e9facee6c481d83aa72b54f0b62e698234c54ff3 Mon Sep 17 00:00:00 2001 From: Jeffrey Townsend Date: Fri, 20 May 2016 14:28:35 +0000 Subject: [PATCH 095/113] Add new LED mode AUTO_BLINKING. --- packages/base/any/onlp/src/onlp/module/auto/onlp.yml | 2 ++ packages/base/any/onlp/src/onlp/module/inc/onlp/led.h | 2 ++ packages/base/any/onlp/src/onlp/module/src/onlp_enums.c | 4 ++++ 3 files changed, 8 insertions(+) diff --git a/packages/base/any/onlp/src/onlp/module/auto/onlp.yml b/packages/base/any/onlp/src/onlp/module/auto/onlp.yml index 972d47eb..9d4255f1 100644 --- a/packages/base/any/onlp/src/onlp/module/auto/onlp.yml +++ b/packages/base/any/onlp/src/onlp/module/auto/onlp.yml @@ -179,6 +179,7 @@ led_caps: &led_caps - PURPLE : (1 << 20) - PURPLE_BLINKING : (1 << 21) - AUTO : (1 << 22) +- AUTO_BLINKING : (1 << 23) # LED status led_status: &led_status @@ -205,6 +206,7 @@ led_mode: &led_mode - 'PURPLE' : 20 - 'PURPLE_BLINKING' : 21 - 'AUTO' : 22 +- 'AUTO_BLINKING' : 23 # PSU Status psu_status: &psu_status diff --git a/packages/base/any/onlp/src/onlp/module/inc/onlp/led.h b/packages/base/any/onlp/src/onlp/module/inc/onlp/led.h index 2909b9df..1c99843e 100644 --- a/packages/base/any/onlp/src/onlp/module/inc/onlp/led.h +++ b/packages/base/any/onlp/src/onlp/module/inc/onlp/led.h @@ -46,6 +46,7 @@ typedef enum onlp_led_caps_e { ONLP_LED_CAPS_PURPLE = (1 << 20), ONLP_LED_CAPS_PURPLE_BLINKING = (1 << 21), ONLP_LED_CAPS_AUTO = (1 << 22), + ONLP_LED_CAPS_AUTO_BLINKING = (1 << 23), } onlp_led_caps_t; /** onlp_led_mode */ @@ -66,6 +67,7 @@ typedef enum onlp_led_mode_e { ONLP_LED_MODE_PURPLE = 20, ONLP_LED_MODE_PURPLE_BLINKING = 21, ONLP_LED_MODE_AUTO = 22, + ONLP_LED_MODE_AUTO_BLINKING = 23, } onlp_led_mode_t; /** onlp_led_status */ diff --git a/packages/base/any/onlp/src/onlp/module/src/onlp_enums.c b/packages/base/any/onlp/src/onlp/module/src/onlp_enums.c index f5c9a74d..78a169ae 100644 --- a/packages/base/any/onlp/src/onlp/module/src/onlp_enums.c +++ b/packages/base/any/onlp/src/onlp/module/src/onlp_enums.c @@ -296,6 +296,7 @@ aim_map_si_t onlp_led_caps_map[] = { "PURPLE", ONLP_LED_CAPS_PURPLE }, { "PURPLE_BLINKING", ONLP_LED_CAPS_PURPLE_BLINKING }, { "AUTO", ONLP_LED_CAPS_AUTO }, + { "AUTO_BLINKING", ONLP_LED_CAPS_AUTO_BLINKING }, { NULL, 0 } }; @@ -316,6 +317,7 @@ aim_map_si_t onlp_led_caps_desc_map[] = { "None", ONLP_LED_CAPS_PURPLE }, { "None", ONLP_LED_CAPS_PURPLE_BLINKING }, { "None", ONLP_LED_CAPS_AUTO }, + { "None", ONLP_LED_CAPS_AUTO_BLINKING }, { NULL, 0 } }; @@ -383,6 +385,7 @@ aim_map_si_t onlp_led_mode_map[] = { "PURPLE", ONLP_LED_MODE_PURPLE }, { "PURPLE_BLINKING", ONLP_LED_MODE_PURPLE_BLINKING }, { "AUTO", ONLP_LED_MODE_AUTO }, + { "AUTO_BLINKING", ONLP_LED_MODE_AUTO_BLINKING }, { NULL, 0 } }; @@ -404,6 +407,7 @@ aim_map_si_t onlp_led_mode_desc_map[] = { "None", ONLP_LED_MODE_PURPLE }, { "None", ONLP_LED_MODE_PURPLE_BLINKING }, { "None", ONLP_LED_MODE_AUTO }, + { "None", ONLP_LED_MODE_AUTO_BLINKING }, { NULL, 0 } }; From 89a4fe3f2446b54d1ca1beb2426b199978f422b4 Mon Sep 17 00:00:00 2001 From: Jeffrey Townsend Date: Fri, 20 May 2016 14:29:41 +0000 Subject: [PATCH 096/113] Version files have moved. --- packages/base/any/initrds/loader/builds/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/base/any/initrds/loader/builds/Makefile b/packages/base/any/initrds/loader/builds/Makefile index b117a086..a60ba9f9 100644 --- a/packages/base/any/initrds/loader/builds/Makefile +++ b/packages/base/any/initrds/loader/builds/Makefile @@ -27,7 +27,7 @@ $(TARGET): $(ONLPM) --sudo $(foreach p,$(PLATFORM_PACKAGES),--extract-dir $(p) $(ROOT)) $(MAKE) __vendor_config_data $(ONLPM) --sudo --force --extract-dir onl-vendor-config-onl:all $(ROOT) - $(ONL)/tools/sjson.py --kj version $(ONL)/make/version-onl.json --kl platforms $(PLATFORMS) --kv arch $(ARCH) --out manifest.json + $(ONL)/tools/sjson.py --kj version $(ONL)/make/versions/version-onl.json --kl platforms $(PLATFORMS) --kv arch $(ARCH) --out manifest.json sudo mkdir -p $(ROOT)/etc/onl/loader && sudo cp manifest.json $(ROOT)/etc/onl/loader sudo $(ONL)/tools/makedevs -d $(ROOT)/etc/rootperms $(abspath $(ROOT)) sudo $(ONL)/tools/cpiomod.py --cpio onl-buildroot-initrd-$(ARCH).cpio.gz --add-directory $(ROOT) --out $@ From 3174eb6db1c80bf8eeb6af4f855c29c58a4f5ddf Mon Sep 17 00:00:00 2001 From: Jeffrey Townsend Date: Fri, 20 May 2016 14:53:45 +0000 Subject: [PATCH 097/113] Make the RELEASE directory customizable. --- tools/onlpm.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/onlpm.py b/tools/onlpm.py index d45b2e29..11b93099 100755 --- a/tools/onlpm.py +++ b/tools/onlpm.py @@ -548,8 +548,9 @@ class OnlPackageGroup(object): dict(), OnlPackageError) for f in release_list: - # Todo -- customize - dst = os.path.join(os.getenv('ONL'), 'RELEASE', g_dist_codename, f[1]) + release_dir = os.environ.get('ONLPM_OPTION_RELEASE_DIR', + os.path.join(os.environ.get('ONL', 'RELEASE'))) + dst = os.path.join(release_dir, g_dist_codename, f[1]) if not os.path.exists(dst): os.makedirs(dst) logger.info("Releasing %s -> %s" % (os.path.basename(f[0]), dst)) From 6eab05f1de36e2de5bf3154ca53ebf0a67053a15 Mon Sep 17 00:00:00 2001 From: Jeffrey Townsend Date: Fri, 20 May 2016 16:49:30 +0000 Subject: [PATCH 098/113] initdev -> initmounts --- packages/base/all/boot.d/src/50.initdev | 19 ------------------- packages/base/all/boot.d/src/50.initmounts | 6 ++++++ 2 files changed, 6 insertions(+), 19 deletions(-) delete mode 100755 packages/base/all/boot.d/src/50.initdev create mode 100755 packages/base/all/boot.d/src/50.initmounts diff --git a/packages/base/all/boot.d/src/50.initdev b/packages/base/all/boot.d/src/50.initdev deleted file mode 100755 index 9fbc1152..00000000 --- a/packages/base/all/boot.d/src/50.initdev +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/sh - -. /lib/lsb/init-functions - -log_action_begin_msg "Setting up block and net devices" - -ln -snf /proc/mounts /etc/mtab - -( cd /sys/class/block; for d in *; do /sbin/initblockdev $d add; done ) -if [ -d /sys/class/ubi ]; then - ( cd /sys/class/ubi; for d in *; do /sbin/initblockdev $d add; done ) -fi -( cd /sys/class/net; for d in *; do /sbin/initnetdev $d add; done ) - -log_action_end_msg 0 - -log_action_begin_msg "Mounting filesystems" -initmounts -q -log_action_end_msg 0 diff --git a/packages/base/all/boot.d/src/50.initmounts b/packages/base/all/boot.d/src/50.initmounts new file mode 100755 index 00000000..8aa7ca5b --- /dev/null +++ b/packages/base/all/boot.d/src/50.initmounts @@ -0,0 +1,6 @@ +#!/bin/sh + +. /lib/lsb/init-functions +log_action_begin_msg "Mounting filesystems..." +initmounts -q +log_action_end_msg 0 From 3727a226e7a8dc7a6117f76bffe30861a870148a Mon Sep 17 00:00:00 2001 From: Jeffrey Townsend Date: Fri, 20 May 2016 16:52:24 +0000 Subject: [PATCH 099/113] Latest --- packages/platforms-closed | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/platforms-closed b/packages/platforms-closed index 1bea6253..5628d2f2 160000 --- a/packages/platforms-closed +++ b/packages/platforms-closed @@ -1 +1 @@ -Subproject commit 1bea6253f9814607df5c51a7cf5e1ee509331a37 +Subproject commit 5628d2f2e43a78b9faa33428575e8e322899d3c7 From 58ec3fadbf821190a0e6aaea9aa32e8b358d10fa Mon Sep 17 00:00:00 2001 From: Steven Noble Date: Mon, 23 May 2016 12:05:40 -0700 Subject: [PATCH 100/113] updated install.sh to reference new location of version files (#84) --- tools/autobuild/install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/autobuild/install.sh b/tools/autobuild/install.sh index e04b0289..dddc2bfa 100755 --- a/tools/autobuild/install.sh +++ b/tools/autobuild/install.sh @@ -68,7 +68,7 @@ if [ -z "$REMOTE_PASS" ]; then fi -. $ONL/make/version-onl.sh +. $ONL/make/versions/version-onl.sh REMOTE_DIR="$REMOTE_BASE_DIR/$BUILD_BRANCH/$FNAME_BUILD_ID" workdir=$(mktemp -d -t update-XXXXXX) From 5141acb92e8de65417c931466bbc0ae6da785cdd Mon Sep 17 00:00:00 2001 From: Steven Noble Date: Mon, 23 May 2016 14:13:34 -0700 Subject: [PATCH 101/113] add default RELEASE directory to setup.env (#85) --- setup.env | 3 +++ 1 file changed, 3 insertions(+) diff --git a/setup.env b/setup.env index 5c05029b..56d0ad37 100755 --- a/setup.env +++ b/setup.env @@ -15,6 +15,9 @@ export ONLPM_OPTION_PACKAGEDIRS="$ONL/packages:$ONL/builds" # The ONL repo dir is here: export ONLPM_OPTION_REPO="$ONL/REPO" +# The default RELEASE dir is here: +export ONLPM_OPTION_RELEASE_DIR="$ONL/RELEASE" + # The ONL build tools should be included in the local path: export PATH="$ONL/tools/scripts:$ONL/tools:$PATH" From 842d7c58cedca45feae9a61ad4d9e98cc367ee69 Mon Sep 17 00:00:00 2001 From: Jeffrey Townsend Date: Tue, 31 May 2016 15:53:44 +0000 Subject: [PATCH 102/113] Regenerated menuconfig. --- .../any/initrds/buildroot/builds/buildroot.config-powerpc | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/packages/base/any/initrds/buildroot/builds/buildroot.config-powerpc b/packages/base/any/initrds/buildroot/builds/buildroot.config-powerpc index 84d06b85..27149382 100644 --- a/packages/base/any/initrds/buildroot/builds/buildroot.config-powerpc +++ b/packages/base/any/initrds/buildroot/builds/buildroot.config-powerpc @@ -86,10 +86,6 @@ BR2_HOST_DIR="$(BASE_DIR)/host" # BR2_PRIMARY_SITE="$(BUILDROOTMIRROR)" BR2_PRIMARY_SITE_ONLY=y -BR2_BACKUP_SITE="https://raw.githubusercontent.com/opennetworklinux/buildroot-download-cache/master/dl" -BR2_KERNEL_MIRROR="http://www.kernel.org/pub/" -BR2_GNU_MIRROR="http://ftp.gnu.org/pub/gnu" -BR2_DEBIAN_MIRROR="http://ftp.debian.org" BR2_JLEVEL=0 BR2_CCACHE=y BR2_CCACHE_DIR="$(HOME)/.buildroot-ccache" @@ -632,10 +628,10 @@ BR2_PACKAGE_PYTHON_ZLIB=y # BR2_PACKAGE_PYTHON_PYPARSING is not set # BR2_PACKAGE_PYTHON_SERIAL is not set # BR2_PACKAGE_PYTHON_SETUPTOOLS is not set +BR2_PACKAGE_PYTHON_PYPARTED=y +BR2_PACKAGE_PYTHON_YAML=y BR2_PACKAGE_PYTHON_DNSPYTHON=y BR2_PACKAGE_PYTHON_PYROUTE2=y -BR2_PACKAGE_PYTHON_YAML=y -BR2_PACKAGE_PYTHON_PYPARTED=y # BR2_PACKAGE_RUBY is not set # BR2_PACKAGE_TCL is not set From be4620b7056a76e778b015891ac7db0b652d2850 Mon Sep 17 00:00:00 2001 From: Jeffrey Townsend Date: Tue, 31 May 2016 16:11:38 +0000 Subject: [PATCH 103/113] Use external toolchain. --- .../buildroot/builds/buildroot.config-powerpc | 102 +++++------------- 1 file changed, 27 insertions(+), 75 deletions(-) diff --git a/packages/base/any/initrds/buildroot/builds/buildroot.config-powerpc b/packages/base/any/initrds/buildroot/builds/buildroot.config-powerpc index 27149382..2a17d35f 100644 --- a/packages/base/any/initrds/buildroot/builds/buildroot.config-powerpc +++ b/packages/base/any/initrds/buildroot/builds/buildroot.config-powerpc @@ -107,99 +107,51 @@ BR2_PACKAGE_OVERRIDE_FILE="$(TOPDIR)/local.mk" # # Toolchain # -BR2_TOOLCHAIN_BUILDROOT=y -# BR2_TOOLCHAIN_EXTERNAL is not set +# BR2_TOOLCHAIN_BUILDROOT is not set +BR2_TOOLCHAIN_EXTERNAL=y # BR2_TOOLCHAIN_CTNG is not set - -# -# Kernel Header Options -# -# BR2_KERNEL_HEADERS_3_0 is not set -# BR2_KERNEL_HEADERS_3_2 is not set -# BR2_KERNEL_HEADERS_3_4 is not set -BR2_KERNEL_HEADERS_3_6=y -# BR2_KERNEL_HEADERS_3_7 is not set -# BR2_KERNEL_HEADERS_VERSION is not set -# BR2_KERNEL_HEADERS_SNAP is not set -BR2_DEFAULT_KERNEL_HEADERS="3.6.11" - -# -# uClibc Options -# -# BR2_UCLIBC_VERSION_0_9_32 is not set -BR2_UCLIBC_VERSION_0_9_33=y -# BR2_UCLIBC_VERSION_SNAPSHOT is not set -BR2_UCLIBC_VERSION_STRING="0.9.33.2" -BR2_UCLIBC_CONFIG="toolchain/uClibc/uClibc-0.9.33.config" -# BR2_PTHREAD_DEBUG is not set -# BR2_UCLIBC_INSTALL_TEST_SUITE is not set - -# -# Binutils Options -# -# BR2_BINUTILS_VERSION_2_20_1 is not set -# BR2_BINUTILS_VERSION_2_21 is not set -BR2_BINUTILS_VERSION_2_21_1=y -# BR2_BINUTILS_VERSION_2_22 is not set -# BR2_BINUTILS_VERSION_2_23_1 is not set -BR2_BINUTILS_VERSION="2.21.1" -BR2_BINUTILS_EXTRA_CONFIG_OPTIONS="" - -# -# GCC Options -# -# BR2_GCC_VERSION_4_3_X is not set -# BR2_GCC_VERSION_4_4_X is not set -# BR2_GCC_VERSION_4_5_X is not set -BR2_GCC_VERSION_4_6_X=y -# BR2_GCC_VERSION_4_7_X is not set -# BR2_GCC_VERSION_SNAP is not set -BR2_GCC_SUPPORTS_FINEGRAINEDMTUNE=y -BR2_GCC_VERSION="4.6.3" -BR2_EXTRA_GCC_CONFIG_OPTIONS="" -# BR2_INSTALL_OBJC is not set -# BR2_INSTALL_FORTRAN is not set -BR2_GCC_SHARED_LIBGCC=y -BR2_GCC_ENABLE_TLS=y -# BR2_GCC_ENABLE_OPENMP is not set +# BR2_TOOLCHAIN_EXTERNAL_CODESOURCERY_POWERPC201103 is not set +# BR2_TOOLCHAIN_EXTERNAL_CODESOURCERY_POWERPC201009 is not set +BR2_TOOLCHAIN_EXTERNAL_CUSTOM=y +# BR2_TOOLCHAIN_EXTERNAL_DOWNLOAD is not set +BR2_TOOLCHAIN_EXTERNAL_PREINSTALLED=y +BR2_TOOLCHAIN_EXTERNAL_PATH="/usr/buildroot/toolchains/powerpc" +BR2_TOOLCHAIN_EXTERNAL_CUSTOM_PREFIX="powerpc-buildroot-linux-uclibc" +BR2_TOOLCHAIN_EXTERNAL_PREFIX="powerpc-buildroot-linux-uclibc" +BR2_TOOLCHAIN_EXTERNAL_UCLIBC=y +BR2_TOOLCHAIN_EXTERNAL_CUSTOM_UCLIBC=y +# BR2_TOOLCHAIN_EXTERNAL_CUSTOM_GLIBC is not set +BR2_TOOLCHAIN_EXTERNAL_LARGEFILE=y +BR2_TOOLCHAIN_EXTERNAL_INET_IPV6=y +BR2_TOOLCHAIN_EXTERNAL_WCHAR=y +# BR2_TOOLCHAIN_EXTERNAL_LOCALE is not set +BR2_TOOLCHAIN_EXTERNAL_HAS_THREADS=y +# BR2_TOOLCHAIN_EXTERNAL_HAS_THREADS_DEBUG is not set +BR2_TOOLCHAIN_EXTERNAL_INET_RPC=y +# BR2_TOOLCHAIN_EXTERNAL_CXX is not set +BR2_TOOLCHAIN_EXTRA_EXTERNAL_LIBS="" # # Gdb Options # -# BR2_PACKAGE_GDB is not set -# BR2_PACKAGE_GDB_SERVER is not set -# BR2_PACKAGE_GDB_HOST is not set +# BR2_TOOLCHAIN_EXTERNAL_GDB_SERVER_COPY is not set + +# +# gdb support needs pthread debug support in toolchain +# BR2_LARGEFILE=y BR2_INET_IPV6=y BR2_TOOLCHAIN_HAS_NATIVE_RPC=y BR2_USE_WCHAR=y BR2_TOOLCHAIN_HAS_THREADS=y -BR2_TOOLCHAIN_HAS_THREADS_DEBUG_IF_NEEDED=y BR2_TOOLCHAIN_HAS_SHADOW_PASSWORDS=y # BR2_ENABLE_LOCALE_PURGE is not set -BR2_GENERATE_LOCALE="" BR2_NEEDS_GETTEXT=y BR2_USE_MMU=y -# BR2_SOFT_FLOAT is not set BR2_TARGET_OPTIMIZATION="-pipe" BR2_TARGET_LDFLAGS="" # BR2_ECLIPSE_REGISTER is not set -# -# Toolchain Options -# -BR2_TOOLCHAIN_BUILDROOT_LARGEFILE=y -BR2_TOOLCHAIN_BUILDROOT_INET_IPV6=y -BR2_TOOLCHAIN_BUILDROOT_INET_RPC=y -BR2_TOOLCHAIN_BUILDROOT_WCHAR=y -# BR2_TOOLCHAIN_BUILDROOT_LOCALE is not set -# BR2_TOOLCHAIN_BUILDROOT_CXX is not set -# BR2_TOOLCHAIN_BUILDROOT_USE_SSP is not set -# BR2_PTHREADS_NONE is not set -# BR2_PTHREADS is not set -# BR2_PTHREADS_OLD is not set -BR2_PTHREADS_NATIVE=y - # # System configuration # From a451a3658cae48af9d66d2f23aa893ff8a6bbb19 Mon Sep 17 00:00:00 2001 From: Jeffrey Townsend Date: Tue, 31 May 2016 16:15:18 +0000 Subject: [PATCH 104/113] Regenerated menuconfig. --- .../any/initrds/buildroot/builds/buildroot.config-x86_64 | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/packages/base/any/initrds/buildroot/builds/buildroot.config-x86_64 b/packages/base/any/initrds/buildroot/builds/buildroot.config-x86_64 index 0ae7448b..815f56e2 100644 --- a/packages/base/any/initrds/buildroot/builds/buildroot.config-x86_64 +++ b/packages/base/any/initrds/buildroot/builds/buildroot.config-x86_64 @@ -61,10 +61,6 @@ BR2_HOST_DIR="$(BASE_DIR)/host" # BR2_PRIMARY_SITE="$(BUILDROOTMIRROR)" BR2_PRIMARY_SITE_ONLY=y -BR2_BACKUP_SITE="https://raw.githubusercontent.com/opennetworklinux/buildroot-download-cache/master/dl" -BR2_KERNEL_MIRROR="http://www.kernel.org/pub/" -BR2_GNU_MIRROR="http://ftp.gnu.org/pub/gnu" -BR2_DEBIAN_MIRROR="http://ftp.debian.org" BR2_JLEVEL=0 BR2_CCACHE=y BR2_CCACHE_DIR="$(HOME)/.buildroot-ccache" @@ -607,10 +603,10 @@ BR2_PACKAGE_PYTHON_ZLIB=y # BR2_PACKAGE_PYTHON_PYPARSING is not set # BR2_PACKAGE_PYTHON_SERIAL is not set # BR2_PACKAGE_PYTHON_SETUPTOOLS is not set +BR2_PACKAGE_PYTHON_PYPARTED=y +BR2_PACKAGE_PYTHON_YAML=y BR2_PACKAGE_PYTHON_DNSPYTHON=y BR2_PACKAGE_PYTHON_PYROUTE2=y -BR2_PACKAGE_PYTHON_YAML=y -BR2_PACKAGE_PYTHON_PYPARTED=y # BR2_PACKAGE_RUBY is not set # BR2_PACKAGE_TCL is not set From 8195678c6527698b382ad7e3e8a2bf38a1ffd667 Mon Sep 17 00:00:00 2001 From: Jeffrey Townsend Date: Tue, 31 May 2016 16:25:42 +0000 Subject: [PATCH 105/113] Use external toolchain. --- .../buildroot/builds/buildroot.config-x86_64 | 101 +++++------------- 1 file changed, 28 insertions(+), 73 deletions(-) diff --git a/packages/base/any/initrds/buildroot/builds/buildroot.config-x86_64 b/packages/base/any/initrds/buildroot/builds/buildroot.config-x86_64 index 815f56e2..0042c485 100644 --- a/packages/base/any/initrds/buildroot/builds/buildroot.config-x86_64 +++ b/packages/base/any/initrds/buildroot/builds/buildroot.config-x86_64 @@ -82,97 +82,52 @@ BR2_PACKAGE_OVERRIDE_FILE="$(TOPDIR)/local.mk" # # Toolchain # -BR2_TOOLCHAIN_BUILDROOT=y -# BR2_TOOLCHAIN_EXTERNAL is not set +# BR2_TOOLCHAIN_BUILDROOT is not set +BR2_TOOLCHAIN_EXTERNAL=y # BR2_TOOLCHAIN_CTNG is not set - -# -# Kernel Header Options -# -# BR2_KERNEL_HEADERS_3_0 is not set -# BR2_KERNEL_HEADERS_3_2 is not set -# BR2_KERNEL_HEADERS_3_4 is not set -# BR2_KERNEL_HEADERS_3_6 is not set -BR2_KERNEL_HEADERS_3_7=y -# BR2_KERNEL_HEADERS_VERSION is not set -# BR2_KERNEL_HEADERS_SNAP is not set -BR2_DEFAULT_KERNEL_HEADERS="3.7.8" - -# -# uClibc Options -# -# BR2_UCLIBC_VERSION_0_9_32 is not set -BR2_UCLIBC_VERSION_0_9_33=y -# BR2_UCLIBC_VERSION_SNAPSHOT is not set -BR2_UCLIBC_VERSION_STRING="0.9.33.2" -BR2_UCLIBC_CONFIG="toolchain/uClibc/uClibc-0.9.33.config" -# BR2_PTHREAD_DEBUG is not set -# BR2_UCLIBC_INSTALL_TEST_SUITE is not set - -# -# Binutils Options -# -# BR2_BINUTILS_VERSION_2_20_1 is not set -# BR2_BINUTILS_VERSION_2_21 is not set -# BR2_BINUTILS_VERSION_2_21_1 is not set -# BR2_BINUTILS_VERSION_2_22 is not set -BR2_BINUTILS_VERSION_2_23_1=y -BR2_BINUTILS_VERSION="2.23.1" -BR2_BINUTILS_EXTRA_CONFIG_OPTIONS="" - -# -# GCC Options -# -# BR2_GCC_VERSION_4_3_X is not set -# BR2_GCC_VERSION_4_4_X is not set -# BR2_GCC_VERSION_4_5_X is not set -# BR2_GCC_VERSION_4_6_X is not set -BR2_GCC_VERSION_4_7_X=y -# BR2_GCC_VERSION_SNAP is not set -BR2_GCC_SUPPORTS_FINEGRAINEDMTUNE=y -BR2_GCC_VERSION="4.7.2" -BR2_EXTRA_GCC_CONFIG_OPTIONS="" -# BR2_INSTALL_OBJC is not set -# BR2_INSTALL_FORTRAN is not set -BR2_GCC_SHARED_LIBGCC=y -# BR2_GCC_ENABLE_OPENMP is not set +# BR2_TOOLCHAIN_EXTERNAL_CODESOURCERY_X86_201209 is not set +# BR2_TOOLCHAIN_EXTERNAL_CODESOURCERY_X86_201203 is not set +# BR2_TOOLCHAIN_EXTERNAL_CODESOURCERY_X86_201109 is not set +BR2_TOOLCHAIN_EXTERNAL_CUSTOM=y +# BR2_TOOLCHAIN_EXTERNAL_DOWNLOAD is not set +BR2_TOOLCHAIN_EXTERNAL_PREINSTALLED=y +BR2_TOOLCHAIN_EXTERNAL_PATH="/usr/buildroot/toolchains/x86_64" +BR2_TOOLCHAIN_EXTERNAL_CUSTOM_PREFIX="x86_64-buildroot-linux-uclibc" +BR2_TOOLCHAIN_EXTERNAL_PREFIX="x86_64-buildroot-linux-uclibc" +BR2_TOOLCHAIN_EXTERNAL_UCLIBC=y +BR2_TOOLCHAIN_EXTERNAL_CUSTOM_UCLIBC=y +# BR2_TOOLCHAIN_EXTERNAL_CUSTOM_GLIBC is not set +BR2_TOOLCHAIN_EXTERNAL_LARGEFILE=y +BR2_TOOLCHAIN_EXTERNAL_INET_IPV6=y +BR2_TOOLCHAIN_EXTERNAL_WCHAR=y +# BR2_TOOLCHAIN_EXTERNAL_LOCALE is not set +BR2_TOOLCHAIN_EXTERNAL_HAS_THREADS=y +# BR2_TOOLCHAIN_EXTERNAL_HAS_THREADS_DEBUG is not set +BR2_TOOLCHAIN_EXTERNAL_INET_RPC=y +# BR2_TOOLCHAIN_EXTERNAL_CXX is not set +BR2_TOOLCHAIN_EXTRA_EXTERNAL_LIBS="" # # Gdb Options # -# BR2_PACKAGE_GDB is not set -# BR2_PACKAGE_GDB_SERVER is not set -# BR2_PACKAGE_GDB_HOST is not set +# BR2_TOOLCHAIN_EXTERNAL_GDB_SERVER_COPY is not set + +# +# gdb support needs pthread debug support in toolchain +# BR2_LARGEFILE=y BR2_INET_IPV6=y BR2_TOOLCHAIN_HAS_NATIVE_RPC=y BR2_USE_WCHAR=y BR2_TOOLCHAIN_HAS_THREADS=y -BR2_TOOLCHAIN_HAS_THREADS_DEBUG_IF_NEEDED=y BR2_TOOLCHAIN_HAS_SHADOW_PASSWORDS=y # BR2_ENABLE_LOCALE_PURGE is not set -BR2_GENERATE_LOCALE="" BR2_NEEDS_GETTEXT=y BR2_USE_MMU=y BR2_TARGET_OPTIMIZATION="-pipe" BR2_TARGET_LDFLAGS="" # BR2_ECLIPSE_REGISTER is not set -# -# Toolchain Options -# -BR2_TOOLCHAIN_BUILDROOT_LARGEFILE=y -BR2_TOOLCHAIN_BUILDROOT_INET_IPV6=y -BR2_TOOLCHAIN_BUILDROOT_INET_RPC=y -BR2_TOOLCHAIN_BUILDROOT_WCHAR=y -# BR2_TOOLCHAIN_BUILDROOT_LOCALE is not set -# BR2_TOOLCHAIN_BUILDROOT_CXX is not set -# BR2_TOOLCHAIN_BUILDROOT_USE_SSP is not set -# BR2_PTHREADS_NONE is not set -# BR2_PTHREADS is not set -BR2_PTHREADS_OLD=y -# BR2_PTHREADS_NATIVE is not set - # # System configuration # From 031ad4580c35d92d807171e3b0d1dfcf26a1220c Mon Sep 17 00:00:00 2001 From: Jeffrey Townsend Date: Tue, 31 May 2016 11:27:06 -0700 Subject: [PATCH 106/113] Fix bug in template. --- packages/base/any/initrds/buildroot/builds/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/base/any/initrds/buildroot/builds/Makefile b/packages/base/any/initrds/buildroot/builds/Makefile index f628575a..232471e4 100644 --- a/packages/base/any/initrds/buildroot/builds/Makefile +++ b/packages/base/any/initrds/buildroot/builds/Makefile @@ -79,11 +79,11 @@ setup-pyparted: define buildroot_arch buildroot-$(1): - make -C $(BUILDROOT_SOURCE) O=../buildroot-$(1) + make -C $(BUILDROOT_SOURCE) O=../buildroot-$(1) LD_LIBRARY_PATH=/usr/buildroot/toolchains/$(1)/lib buildroot-menuconfig-$(1): make -C $(BUILDROOT_SOURCE) menuconfig O=../buildroot-$(1) - cp buildroot-powerpc/.config buildroot.config-$(1) + cp buildroot-$(1)/.config buildroot.config-$(1) endef $(foreach a,$(ARCHS),$(eval $(call buildroot_arch,$(a)))) From f2bf36ec1484d28e69b9ca5c9e863badd7098b64 Mon Sep 17 00:00:00 2001 From: Jeffrey Townsend Date: Tue, 31 May 2016 11:29:37 -0700 Subject: [PATCH 107/113] Menuconfig regenerated. --- .../buildroot/builds/buildroot.config-arm | 33 ++++--------------- 1 file changed, 7 insertions(+), 26 deletions(-) diff --git a/packages/base/any/initrds/buildroot/builds/buildroot.config-arm b/packages/base/any/initrds/buildroot/builds/buildroot.config-arm index 02f39514..6ba13a47 100644 --- a/packages/base/any/initrds/buildroot/builds/buildroot.config-arm +++ b/packages/base/any/initrds/buildroot/builds/buildroot.config-arm @@ -1,4 +1,3 @@ - # # Automatically generated make config: don't edit # Buildroot 2013.02-rc2-g5e1a5c1-dirty Configuration @@ -79,10 +78,6 @@ BR2_HOST_DIR="$(BASE_DIR)/host" # BR2_PRIMARY_SITE="$(BUILDROOTMIRROR)" BR2_PRIMARY_SITE_ONLY=y -BR2_BACKUP_SITE="https://raw.githubusercontent.com/opennetworklinux/buildroot-download-cache/master/dl" -BR2_KERNEL_MIRROR="http://www.kernel.org/pub/" -BR2_GNU_MIRROR="http://ftp.gnu.org/pub/gnu" -BR2_DEBIAN_MIRROR="http://ftp.debian.org" BR2_JLEVEL=0 BR2_CCACHE=y BR2_CCACHE_DIR="$(HOME)/.buildroot-ccache" @@ -169,6 +164,7 @@ BR2_GCC_ENABLE_TLS=y # BR2_PACKAGE_GDB_HOST is not set BR2_LARGEFILE=y BR2_INET_IPV6=y +BR2_TOOLCHAIN_HAS_NATIVE_RPC=y BR2_USE_WCHAR=y BR2_TOOLCHAIN_HAS_THREADS=y BR2_TOOLCHAIN_HAS_THREADS_DEBUG_IF_NEEDED=y @@ -308,9 +304,7 @@ BR2_PACKAGE_KEXEC_ZLIB=y # BR2_PACKAGE_RT_TESTS is not set BR2_PACKAGE_STRACE=y # BR2_PACKAGE_STRESS is not set -# BR2_PACKAGE_SYSPROF is not set # BR2_PACKAGE_WHETSTONE is not set -# BR2_PACKAGE_VALGRIND is not set # BR2_PACKAGE_PV is not set # @@ -543,6 +537,10 @@ BR2_PACKAGE_LVM2=y # BR2_PACKAGE_OFONO is not set # BR2_PACKAGE_OPEN2300 is not set # BR2_PACKAGE_OPENOCD is not set + +# +# owl-linux requires a Linux kernel +# BR2_PACKAGE_PARTED=y # BR2_PACKAGE_PCIUTILS is not set # BR2_PACKAGE_PICOCOM is not set @@ -629,10 +627,10 @@ BR2_PACKAGE_PYTHON_ZLIB=y # BR2_PACKAGE_PYTHON_PYPARSING is not set # BR2_PACKAGE_PYTHON_SERIAL is not set # BR2_PACKAGE_PYTHON_SETUPTOOLS is not set +BR2_PACKAGE_PYTHON_PYPARTED=y +BR2_PACKAGE_PYTHON_YAML=y BR2_PACKAGE_PYTHON_DNSPYTHON=y BR2_PACKAGE_PYTHON_PYROUTE2=y -BR2_PACKAGE_PYTHON_YAML=y -BR2_PACKAGE_PYTHON_PYPARTED=y # BR2_PACKAGE_RUBY is not set # BR2_PACKAGE_TCL is not set @@ -1235,10 +1233,6 @@ BR2_TARGET_ROOTFS_CPIO_GZIP=y # BR2_TARGET_ROOTFS_CPIO_LZMA is not set # BR2_TARGET_ROOTFS_CRAMFS is not set # BR2_TARGET_ROOTFS_EXT2 is not set -# BR2_TARGET_ROOTFS_EXT2_NONE is not set -# BR2_TARGET_ROOTFS_EXT2_GZIP is not set -# BR2_TARGET_ROOTFS_EXT2_BZIP2 is not set -# BR2_TARGET_ROOTFS_EXT2_LZMA is not set # # initramfs requires a Linux kernel to be built @@ -1264,19 +1258,6 @@ BR2_TARGET_ROOTFS_CPIO_GZIP=y # Kernel # # BR2_LINUX_KERNEL is not set -# BR2_LINUX_KERNEL_3_7 is not set -# BR2_LINUX_KERNEL_SAME_AS_HEADERS is not set -# BR2_LINUX_KERNEL_CUSTOM_VERSION is not set -# BR2_LINUX_KERNEL_CUSTOM_TARBALL is not set -# BR2_LINUX_KERNEL_CUSTOM_GIT is not set -# BR2_LINUX_KERNEL_USE_DEFCONFIG is not set -# BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG is not set -# BR2_LINUX_KERNEL_UIMAGE is not set -# BR2_LINUX_KERNEL_APPENDED_UIMAGE is not set -# BR2_LINUX_KERNEL_ZIMAGE is not set -# BR2_LINUX_KERNEL_APPENDED_ZIMAGE is not set -# BR2_LINUX_KERNEL_VMLINUX is not set -# BR2_LINUX_KERNEL_IMAGE_TARGET_CUSTOM is not set # # Legacy config options From 1289bdbdd4d543742f401df27fea385420cc5941 Mon Sep 17 00:00:00 2001 From: Jeffrey Townsend Date: Tue, 31 May 2016 11:30:36 -0700 Subject: [PATCH 108/113] Menuconfig regenerated. --- .../buildroot/builds/buildroot.config-arm | 711 +++++++++++------- 1 file changed, 457 insertions(+), 254 deletions(-) diff --git a/packages/base/any/initrds/buildroot/builds/buildroot.config-arm b/packages/base/any/initrds/buildroot/builds/buildroot.config-arm index 6ba13a47..79404325 100644 --- a/packages/base/any/initrds/buildroot/builds/buildroot.config-arm +++ b/packages/base/any/initrds/buildroot/builds/buildroot.config-arm @@ -99,101 +99,79 @@ BR2_PACKAGE_OVERRIDE_FILE="$(TOPDIR)/local.mk" # # Toolchain # -BR2_TOOLCHAIN_BUILDROOT=y -# BR2_TOOLCHAIN_EXTERNAL is not set +# BR2_TOOLCHAIN_BUILDROOT is not set +BR2_TOOLCHAIN_EXTERNAL=y # BR2_TOOLCHAIN_CTNG is not set - -# -# Kernel Header Options -# # BR2_KERNEL_HEADERS_3_0 is not set # BR2_KERNEL_HEADERS_3_2 is not set # BR2_KERNEL_HEADERS_3_4 is not set # BR2_KERNEL_HEADERS_3_6 is not set -BR2_KERNEL_HEADERS_3_7=y +# BR2_KERNEL_HEADERS_3_7 is not set # BR2_KERNEL_HEADERS_VERSION is not set # BR2_KERNEL_HEADERS_SNAP is not set -BR2_DEFAULT_KERNEL_HEADERS="3.7.8" - -# -# uClibc Options -# # BR2_UCLIBC_VERSION_0_9_32 is not set -BR2_UCLIBC_VERSION_0_9_33=y +# BR2_UCLIBC_VERSION_0_9_33 is not set # BR2_UCLIBC_VERSION_SNAPSHOT is not set -BR2_UCLIBC_VERSION_STRING="0.9.33.2" -BR2_UCLIBC_CONFIG="toolchain/uClibc/uClibc-0.9.33.config" -# BR2_PTHREAD_DEBUG is not set -# BR2_UCLIBC_INSTALL_TEST_SUITE is not set -BR2_UCLIBC_ARM_TYPE="ARM926T" - -# -# Binutils Options -# # BR2_BINUTILS_VERSION_2_20_1 is not set # BR2_BINUTILS_VERSION_2_21 is not set -BR2_BINUTILS_VERSION_2_21_1=y +# BR2_BINUTILS_VERSION_2_21_1 is not set # BR2_BINUTILS_VERSION_2_22 is not set # BR2_BINUTILS_VERSION_2_23_1 is not set -BR2_BINUTILS_VERSION="2.21.1" -BR2_BINUTILS_EXTRA_CONFIG_OPTIONS="" - -# -# GCC Options -# # BR2_GCC_VERSION_4_3_X is not set # BR2_GCC_VERSION_4_4_X is not set # BR2_GCC_VERSION_4_5_X is not set -BR2_GCC_VERSION_4_6_X=y +# BR2_GCC_VERSION_4_6_X is not set # BR2_GCC_VERSION_4_7_X is not set # BR2_GCC_VERSION_SNAP is not set -BR2_GCC_SUPPORTS_FINEGRAINEDMTUNE=y -BR2_GCC_VERSION="4.6.3" -BR2_EXTRA_GCC_CONFIG_OPTIONS="" -# BR2_INSTALL_OBJC is not set -# BR2_INSTALL_FORTRAN is not set -BR2_GCC_SHARED_LIBGCC=y -BR2_GCC_ENABLE_TLS=y -# BR2_GCC_ENABLE_OPENMP is not set + +# +# Linaro toolchains available for Cortex-A{5,8,9,15} +# +# BR2_TOOLCHAIN_EXTERNAL_CODESOURCERY_ARM201203 is not set +# BR2_TOOLCHAIN_EXTERNAL_CODESOURCERY_ARM201109 is not set +# BR2_TOOLCHAIN_EXTERNAL_CODESOURCERY_ARM201103 is not set +BR2_TOOLCHAIN_EXTERNAL_CUSTOM=y +# BR2_TOOLCHAIN_EXTERNAL_DOWNLOAD is not set +BR2_TOOLCHAIN_EXTERNAL_PREINSTALLED=y +BR2_TOOLCHAIN_EXTERNAL_PATH="/usr/buildroot/toolchains/arm" +BR2_TOOLCHAIN_EXTERNAL_CUSTOM_PREFIX="arm-buildroot-linux-uclibcgnueabi" +BR2_TOOLCHAIN_EXTERNAL_PREFIX="arm-buildroot-linux-uclibcgnueabi" +BR2_TOOLCHAIN_EXTERNAL_UCLIBC=y +BR2_TOOLCHAIN_EXTERNAL_CUSTOM_UCLIBC=y +# BR2_TOOLCHAIN_EXTERNAL_CUSTOM_GLIBC is not set +# BR2_TOOLCHAIN_EXTERNAL_LARGEFILE is not set +# BR2_TOOLCHAIN_EXTERNAL_INET_IPV6 is not set +# BR2_TOOLCHAIN_EXTERNAL_WCHAR is not set +# BR2_TOOLCHAIN_EXTERNAL_LOCALE is not set +BR2_TOOLCHAIN_EXTERNAL_HAS_THREADS=y +BR2_TOOLCHAIN_EXTERNAL_HAS_THREADS_DEBUG=y +# BR2_TOOLCHAIN_EXTERNAL_INET_RPC is not set +# BR2_TOOLCHAIN_EXTERNAL_CXX is not set +BR2_TOOLCHAIN_EXTRA_EXTERNAL_LIBS="" # # Gdb Options # -# BR2_PACKAGE_GDB is not set -# BR2_PACKAGE_GDB_SERVER is not set -# BR2_PACKAGE_GDB_HOST is not set -BR2_LARGEFILE=y -BR2_INET_IPV6=y -BR2_TOOLCHAIN_HAS_NATIVE_RPC=y -BR2_USE_WCHAR=y + +# +# Gdb for the target needs WCHAR and threads support in toolchain +# +# BR2_TOOLCHAIN_EXTERNAL_GDB_SERVER_COPY is not set BR2_TOOLCHAIN_HAS_THREADS=y +BR2_TOOLCHAIN_HAS_THREADS_DEBUG=y BR2_TOOLCHAIN_HAS_THREADS_DEBUG_IF_NEEDED=y BR2_TOOLCHAIN_HAS_SHADOW_PASSWORDS=y # BR2_ENABLE_LOCALE_PURGE is not set -BR2_GENERATE_LOCALE="" BR2_NEEDS_GETTEXT=y BR2_USE_MMU=y BR2_PREFER_SOFT_FLOAT=y -BR2_SOFT_FLOAT=y BR2_TARGET_OPTIMIZATION="-pipe" BR2_TARGET_LDFLAGS="" # BR2_ECLIPSE_REGISTER is not set - -# -# Toolchain Options -# -BR2_TOOLCHAIN_BUILDROOT_LARGEFILE=y -BR2_TOOLCHAIN_BUILDROOT_INET_IPV6=y -BR2_TOOLCHAIN_BUILDROOT_INET_RPC=y -BR2_TOOLCHAIN_BUILDROOT_WCHAR=y -# BR2_TOOLCHAIN_BUILDROOT_LOCALE is not set -# BR2_TOOLCHAIN_BUILDROOT_CXX is not set -# BR2_TOOLCHAIN_BUILDROOT_USE_SSP is not set # BR2_PTHREADS_NONE is not set # BR2_PTHREADS is not set # BR2_PTHREADS_OLD is not set -BR2_PTHREADS_NATIVE=y -# BR2_ELF2FLT is not set +# BR2_PTHREADS_NATIVE is not set # # System configuration @@ -209,6 +187,10 @@ BR2_TARGET_GENERIC_PASSWD_METHOD="md5" # BR2_ROOTFS_DEVICE_CREATION_DYNAMIC_DEVTMPFS is not set BR2_ROOTFS_DEVICE_CREATION_DYNAMIC_MDEV=y # BR2_ROOTFS_DEVICE_CREATION_DYNAMIC_UDEV is not set + +# +# udev requires a toolchain with LARGEFILE + WCHAR support +# # BR2_INIT_BUSYBOX is not set # BR2_INIT_SYSV is not set @@ -240,7 +222,10 @@ BR2_PACKAGE_BUSYBOX_CONFIG="../busybox.config" # # Audio and video applications # -# BR2_PACKAGE_ALSA_UTILS is not set + +# +# alsa-utils requires a toolchain with LARGEFILE and threads support +# # BR2_PACKAGE_AUMIX is not set # @@ -248,8 +233,18 @@ BR2_PACKAGE_BUSYBOX_CONFIG="../busybox.config" # # BR2_PACKAGE_FAAD2 is not set # BR2_PACKAGE_FLAC is not set -# BR2_PACKAGE_FFMPEG is not set -# BR2_PACKAGE_GSTREAMER is not set + +# +# ffmpeg requires a toolchain with LARGEFILE and IPV6 support +# + +# +# gstreamer requires a toolchain with WCHAR support +# + +# +# gst-ffmpeg requires a toolchain with LARGEFILE and IPV6 support +# # BR2_PACKAGE_LAME is not set # BR2_PACKAGE_MADPLAY is not set @@ -257,10 +252,16 @@ BR2_PACKAGE_BUSYBOX_CONFIG="../busybox.config" # mpd requires a toolchain with C++ and WCHAR support # # BR2_PACKAGE_MPG123 is not set -# BR2_PACKAGE_MPLAYER is not set + +# +# mplayer requires a toolchain with LARGEFILE support +# # BR2_PACKAGE_MUSEPACK is not set # BR2_PACKAGE_OPUS_TOOLS is not set -# BR2_PACKAGE_PULSEAUDIO is not set + +# +# pulseaudio requires a toolchain with WCHAR, LARGEFILE and threads support +# # BR2_PACKAGE_VORBIS_TOOLS is not set # BR2_PACKAGE_WAVPACK is not set # BR2_PACKAGE_YAVTA is not set @@ -282,11 +283,17 @@ BR2_PACKAGE_XZ=y # # BR2_PACKAGE_CACHE_CALIBRATOR is not set # BR2_PACKAGE_DHRYSTONE is not set -# BR2_PACKAGE_DSTAT is not set + +# +# dstat requires a toolchain with WCHAR support +# # BR2_PACKAGE_DMALLOC is not set BR2_PACKAGE_KEXEC=y BR2_PACKAGE_KEXEC_ZLIB=y -# BR2_PACKAGE_LATENCYTOP is not set + +# +# latencytop requires a toolchain with WCHAR support +# # BR2_PACKAGE_LMBENCH is not set # BR2_PACKAGE_LTP_TESTSUITE is not set # BR2_PACKAGE_LTRACE is not set @@ -304,6 +311,10 @@ BR2_PACKAGE_KEXEC_ZLIB=y # BR2_PACKAGE_RT_TESTS is not set BR2_PACKAGE_STRACE=y # BR2_PACKAGE_STRESS is not set + +# +# sysprof requires a toolchain with WCHAR support +# # BR2_PACKAGE_WHETSTONE is not set # BR2_PACKAGE_PV is not set @@ -311,12 +322,25 @@ BR2_PACKAGE_STRACE=y # Development tools # # BR2_PACKAGE_BINUTILS is not set -# BR2_PACKAGE_BISON is not set + +# +# bison requires a toolchain with WCHAR support +# # BR2_PACKAGE_BSDIFF is not set -# BR2_PACKAGE_CVS is not set + +# +# bustle requires a toolchain with WCHAR support +# + +# +# cvs requires a toolchain with WCHAR support +# # BR2_PACKAGE_DISTCC is not set # BR2_PACKAGE_FLEX is not set -# BR2_PACKAGE_GETTEXT is not set + +# +# gettext requires a toolchain with WCHAR support +# # BR2_PACKAGE_GMP is not set # @@ -325,10 +349,16 @@ BR2_PACKAGE_STRACE=y # BR2_PACKAGE_MPC is not set # BR2_PACKAGE_MPFR is not set # BR2_PACKAGE_LIBTOOL is not set -# BR2_PACKAGE_M4 is not set + +# +# m4 requires a toolchain with WCHAR support +# # BR2_PACKAGE_PKGCONF is not set # BR2_PACKAGE_SSTRIP is not set -# BR2_PACKAGE_VALA is not set + +# +# vala requires a toolchain with WCHAR support +# # # Games @@ -343,7 +373,10 @@ BR2_PACKAGE_STRACE=y # # Graphic applications # -# BR2_PACKAGE_RRDTOOL is not set + +# +# rrdtool requires a toolchain with WCHAR support +# # # graphic libraries @@ -367,12 +400,18 @@ BR2_PACKAGE_STRACE=y # # other GUIs # -# BR2_PACKAGE_EFL is not set + +# +# EFL requires WCHAR support in toolchain +# # # qt requires a toolchain with C++ support enabled # -# BR2_PACKAGE_XORG7 is not set + +# +# X.org requires a toolchain with WCHAR support +# # # X libraries and helper libraries @@ -386,7 +425,10 @@ BR2_PACKAGE_STRACE=y # # X applications # -# BR2_PACKAGE_GOB2 is not set + +# +# gob2 requires a toolchain with WCHAR support +# # # midori requires C++, WCHAR in toolchain and libgtk2 @@ -397,34 +439,26 @@ BR2_PACKAGE_STRACE=y # # BR2_PACKAGE_CIFS_UTILS is not set # BR2_PACKAGE_CRAMFS is not set -# BR2_PACKAGE_CURLFTPFS is not set -BR2_PACKAGE_DOSFSTOOLS=y -BR2_PACKAGE_DOSFSTOOLS_MKDOSFS=y -BR2_PACKAGE_DOSFSTOOLS_DOSFSCK=y -BR2_PACKAGE_DOSFSTOOLS_DOSFSLABEL=y -BR2_PACKAGE_E2FSPROGS=y -# BR2_PACKAGE_E2FSPROGS_BADBLOCKS is not set -# BR2_PACKAGE_E2FSPROGS_CHATTR is not set -# BR2_PACKAGE_E2FSPROGS_DEBUGFS is not set -BR2_PACKAGE_E2FSPROGS_DUMPE2FS=y -# BR2_PACKAGE_E2FSPROGS_E2FREEFRAG is not set -BR2_PACKAGE_E2FSPROGS_E2FSCK=y -# BR2_PACKAGE_E2FSPROGS_E2IMAGE is not set -BR2_PACKAGE_E2FSPROGS_E2LABEL=y -# BR2_PACKAGE_E2FSPROGS_E2UNDO is not set -# BR2_PACKAGE_E2FSPROGS_E4DEFRAG is not set -# BR2_PACKAGE_E2FSPROGS_FILEFRAG is not set -# BR2_PACKAGE_E2FSPROGS_FINDFS is not set -# BR2_PACKAGE_E2FSPROGS_FSCK is not set -# BR2_PACKAGE_E2FSPROGS_LOGSAVE is not set -# BR2_PACKAGE_E2FSPROGS_LSATTR is not set -BR2_PACKAGE_E2FSPROGS_MKE2FS=y -# BR2_PACKAGE_E2FSPROGS_MKLOSTFOUND is not set -# BR2_PACKAGE_E2FSPROGS_RESIZE2FS is not set -BR2_PACKAGE_E2FSPROGS_TUNE2FS=y -BR2_PACKAGE_E2FSPROGS_UUIDGEN=y -# BR2_PACKAGE_FLASHBENCH is not set -# BR2_PACKAGE_GENEXT2FS is not set + +# +# curlftpfs requires a toolchain with LARGEFILE, WCHAR and threads support +# + +# +# dosfstools requires a toolchain with LARGEFILE support +# + +# +# e2fsprogs requires a toolchain with LARGEFILE + WCHAR support +# + +# +# flashbench requires a toolchain with LARGEFILE support +# + +# +# genext2fs requires a toolchain with LARGEFILE support +# # BR2_PACKAGE_GENROMFS is not set # BR2_PACKAGE_MAKEDEVS is not set BR2_PACKAGE_MTD=y @@ -452,7 +486,10 @@ BR2_PACKAGE_MTD_FLASH_UNLOCK=y # BR2_PACKAGE_MTD_NANDWRITE is not set # BR2_PACKAGE_MTD_NFTLDUMP is not set # BR2_PACKAGE_MTD_NFTL_FORMAT is not set -# BR2_PACKAGE_MTD_RECV_IMAGE is not set + +# +# recv_image requires a toolchain with IPv6 support +# # BR2_PACKAGE_MTD_RFDDUMP is not set # BR2_PACKAGE_MTD_RFDFORMAT is not set # BR2_PACKAGE_MTD_SERVE_IMAGE is not set @@ -469,16 +506,30 @@ BR2_PACKAGE_MTD_UBINFO=y BR2_PACKAGE_MTD_UBIRMVOL=y # BR2_PACKAGE_MTD_UBIRSVOL is not set BR2_PACKAGE_MTD_UBIUPDATEVOL=y -# BR2_PACKAGE_NFS_UTILS is not set -# BR2_PACKAGE_NTFS_3G is not set -BR2_PACKAGE_SQUASHFS=y -BR2_PACKAGE_SQUASHFS_GZIP=y -# BR2_PACKAGE_SQUASHFS_LZMA is not set -# BR2_PACKAGE_SQUASHFS_LZO is not set -# BR2_PACKAGE_SQUASHFS_XZ is not set -# BR2_PACKAGE_SSHFS is not set -# BR2_PACKAGE_UNIONFS is not set -# BR2_PACKAGE_XFSPROGS is not set + +# +# nfs-utils requires a toolchain with LARGEFILE support +# + +# +# ntfs-3g requires a toolchain with LARGEFILE and WCHAR support +# + +# +# squashfs requires a toolchain with LARGEFILE and threads support +# + +# +# sshfs requires a toolchain with LARGEFILE, WCHAR and threads support +# + +# +# unionfs requires a toolchain with LARGEFILE and threads support +# + +# +# xfsprogs requires a toolchain with LARGEFILE + WCHAR support +# # # Hardware handling @@ -493,11 +544,20 @@ BR2_PACKAGE_SQUASHFS_GZIP=y # BR2_PACKAGE_RPI_FIRMWARE is not set # BR2_PACKAGE_UX500_FIRMWARE is not set # BR2_PACKAGE_ZD1211_FIRMWARE is not set -# BR2_PACKAGE_CDRKIT is not set + +# +# cdrkit requires a toolchain with LARGEFILE support +# # BR2_PACKAGE_DBUS is not set -# BR2_PACKAGE_DMRAID is not set + +# +# dmraid requires a toolchain with LARGEFILE support +# # BR2_PACKAGE_DVB_APPS is not set -# BR2_PACKAGE_DVBSNOOP is not set + +# +# dvbsnoop requires a toolchain with LARGEFILE support +# # BR2_PACKAGE_EEPROG is not set # BR2_PACKAGE_EVTEST is not set # BR2_PACKAGE_FCONFIG is not set @@ -510,7 +570,10 @@ BR2_PACKAGE_SQUASHFS_GZIP=y # gdisk requires a toolchain with LARGEFILE/WCHAR/C++ support enabled # # BR2_PACKAGE_GPSD is not set -# BR2_PACKAGE_GVFS is not set + +# +# gvfs requires a toolchain with LARGEFILE and WCHAR support +# # BR2_PACKAGE_HWDATA is not set # BR2_PACKAGE_I2C_TOOLS is not set # BR2_PACKAGE_INPUT_EVENT_DAEMON is not set @@ -525,23 +588,39 @@ BR2_PACKAGE_SQUASHFS_GZIP=y # lshw requires a toolchain with C++, LARGEFILE & WCHAR support enabled # # BR2_PACKAGE_LSUIO is not set -BR2_PACKAGE_LVM2=y -# BR2_PACKAGE_LVM2_DMSETUP_ONLY is not set -# BR2_PACKAGE_LVM2_APP_LIBRARY is not set + +# +# lvm2 requires a toolchain with LARGEFILE support +# # BR2_PACKAGE_MDADM is not set # BR2_PACKAGE_MEDIA_CTL is not set -# BR2_PACKAGE_MEMTESTER is not set -# BR2_PACKAGE_MINICOM is not set + +# +# memtester requires a toolchain with LARGEFILE support +# + +# +# minicom requires a toolchain with WCHAR support +# # BR2_PACKAGE_NANOCOM is not set -# BR2_PACKAGE_NEARD is not set -# BR2_PACKAGE_OFONO is not set + +# +# neard requires a toolchain with WCHAR and threads support +# + +# +# ofono requires a toolchain with WCHAR and thread support +# # BR2_PACKAGE_OPEN2300 is not set # BR2_PACKAGE_OPENOCD is not set # # owl-linux requires a Linux kernel # -BR2_PACKAGE_PARTED=y + +# +# parted requires a toolchain with LARGEFILE+WCHAR support +# # BR2_PACKAGE_PCIUTILS is not set # BR2_PACKAGE_PICOCOM is not set # BR2_PACKAGE_RNG_TOOLS is not set @@ -552,7 +631,10 @@ BR2_PACKAGE_PARTED=y # BR2_PACKAGE_SANE_BACKENDS is not set # BR2_PACKAGE_SDPARM is not set # BR2_PACKAGE_SETSERIAL is not set -# BR2_PACKAGE_SG3_UTILS is not set + +# +# sg3-utils requires a toolchain with LARGEFILE and threads support +# # # smartmontools requires a toolchain with C++ support enabled @@ -583,55 +665,29 @@ BR2_PACKAGE_UBOOT_TOOLS_FWPRINTENV=y # # BR2_PACKAGE_ERLANG is not set # BR2_PACKAGE_HASERL is not set -# BR2_PACKAGE_JAMVM is not set + +# +# jamvm requires a toolchain with IPV6 support +# # BR2_PACKAGE_LUA is not set # BR2_PACKAGE_LUAJIT is not set # BR2_PACKAGE_PERL is not set # BR2_PACKAGE_PHP is not set -BR2_PACKAGE_PYTHON=y -BR2_PACKAGE_PYTHON_PY_ONLY=y + +# +# python requires a toolchain with WCHAR support +# +# BR2_PACKAGE_PYTHON_PY_ONLY is not set # BR2_PACKAGE_PYTHON_PYC_ONLY is not set # BR2_PACKAGE_PYTHON_PY_PYC is not set # -# core python modules +# python3 requires a toolchain with WCHAR support # # -# The following modules are unusual or require extra libraries +# ruby requires a toolchain with WCHAR support # -BR2_PACKAGE_PYTHON_BZIP2=y -# BR2_PACKAGE_PYTHON_BSDDB is not set -# BR2_PACKAGE_PYTHON_CODECSCJK is not set -# BR2_PACKAGE_PYTHON_CURSES is not set -# BR2_PACKAGE_PYTHON_PYEXPAT is not set -BR2_PACKAGE_PYTHON_READLINE=y -BR2_PACKAGE_PYTHON_SSL=y -# BR2_PACKAGE_PYTHON_UNICODEDATA is not set -# BR2_PACKAGE_PYTHON_SQLITE is not set -BR2_PACKAGE_PYTHON_ZLIB=y -# BR2_PACKAGE_PYTHON3 is not set - -# -# external python modules -# -# BR2_PACKAGE_PYTHON_BOTTLE is not set -# BR2_PACKAGE_PYTHON_DPKT is not set -# BR2_PACKAGE_PYTHON_ID3 is not set -# BR2_PACKAGE_PYTHON_MAD is not set -# BR2_PACKAGE_PYTHON_MELD3 is not set -# BR2_PACKAGE_PYTHON_NETIFACES is not set -# BR2_PACKAGE_PYTHON_NFC is not set -# BR2_PACKAGE_PYTHON_PROTOBUF is not set -# BR2_PACKAGE_PYTHON_PYGAME is not set -# BR2_PACKAGE_PYTHON_PYPARSING is not set -# BR2_PACKAGE_PYTHON_SERIAL is not set -# BR2_PACKAGE_PYTHON_SETUPTOOLS is not set -BR2_PACKAGE_PYTHON_PYPARTED=y -BR2_PACKAGE_PYTHON_YAML=y -BR2_PACKAGE_PYTHON_DNSPYTHON=y -BR2_PACKAGE_PYTHON_PYROUTE2=y -# BR2_PACKAGE_RUBY is not set # BR2_PACKAGE_TCL is not set # @@ -654,10 +710,16 @@ BR2_PACKAGE_PYTHON_PYROUTE2=y # BR2_PACKAGE_LIBID3TAG is not set # BR2_PACKAGE_LIBLO is not set # BR2_PACKAGE_LIBMAD is not set -# BR2_PACKAGE_LIBMPD is not set + +# +# libmpd requires a toolchain with WCHAR support +# # BR2_PACKAGE_LIBREPLAYGAIN is not set # BR2_PACKAGE_LIBSAMPLERATE is not set -# BR2_PACKAGE_LIBSNDFILE is not set + +# +# libsndfile requires a toolchain with LARGEFILE support +# # BR2_PACKAGE_LIBVORBIS is not set # BR2_PACKAGE_OPUS is not set # BR2_PACKAGE_PORTAUDIO is not set @@ -675,7 +737,10 @@ BR2_PACKAGE_PYTHON_PYROUTE2=y # # Compression and decompression # -# BR2_PACKAGE_LIBARCHIVE is not set + +# +# libarchive requires a toolchain with WCHAR support +# # BR2_PACKAGE_LZO is not set BR2_PACKAGE_ZLIB=y @@ -683,12 +748,14 @@ BR2_PACKAGE_ZLIB=y # Crypto # # BR2_PACKAGE_BEECRYPT is not set -# BR2_PACKAGE_GNUTLS is not set + +# +# gnutls requires a toolchain with WCHAR support +# BR2_PACKAGE_LIBGCRYPT=y BR2_PACKAGE_LIBGPG_ERROR=y # BR2_PACKAGE_LIBMCRYPT is not set # BR2_PACKAGE_LIBMHASH is not set -# BR2_PACKAGE_LIBNSS is not set BR2_PACKAGE_LIBSHA1=y # BR2_PACKAGE_NETTLE is not set # BR2_PACKAGE_OCF_LINUX is not set @@ -713,17 +780,26 @@ BR2_PACKAGE_OPENSSL_ENGINES=y # # Filesystem # -# BR2_PACKAGE_GAMIN is not set + +# +# gamin requires a toolchain with WCHAR support +# # BR2_PACKAGE_LIBCONFIG is not set # BR2_PACKAGE_LIBCONFUSE is not set -# BR2_PACKAGE_LIBFUSE is not set + +# +# libfuse requires a toolchain with LARGEFILE and threads support +# # BR2_PACKAGE_LIBLOCKFILE is not set # BR2_PACKAGE_LIBSYSFS is not set # # Graphics # -# BR2_PACKAGE_ATK is not set + +# +# atk requires a toolchain with WCHAR support +# # BR2_PACKAGE_CAIRO is not set # BR2_PACKAGE_FONTCONFIG is not set # BR2_PACKAGE_FREETYPE is not set @@ -734,7 +810,6 @@ BR2_PACKAGE_OPENSSL_ENGINES=y # BR2_PACKAGE_LIBDMTX is not set # BR2_PACKAGE_LIBEXIF is not set # BR2_PACKAGE_LIBGEOTIFF is not set -# BR2_PACKAGE_GDK_PIXBUF is not set # # libgtk2 requires a toolchain with WCHAR and C++ support @@ -795,9 +870,15 @@ BR2_PACKAGE_OPENSSL_ENGINES=y # BR2_PACKAGE_LIBNFC is not set # BR2_PACKAGE_LIBNFC_LLCP is not set # BR2_PACKAGE_LIBUSB is not set -# BR2_PACKAGE_LIBV4L is not set + +# +# libv4l requires a toolchain with LARGEFILE support +# # BR2_PACKAGE_MTDEV is not set -# BR2_PACKAGE_NEARDAL is not set + +# +# neardal requires a toolchain with WCHAR and threads support +# # BR2_PACKAGE_PCSC_LITE is not set # @@ -813,8 +894,14 @@ BR2_PACKAGE_OPENSSL_ENGINES=y # # Multimedia # -# BR2_PACKAGE_LIBDVDREAD is not set -# BR2_PACKAGE_LIBDVDNAV is not set + +# +# libdvdread requires a toolchain with LARGEFILE support +# + +# +# libdvdnav requires a toolchain with LARGEFILE and thread support +# # # libebml requires a toolchain with C++ support @@ -829,10 +916,16 @@ BR2_PACKAGE_OPENSSL_ENGINES=y # # libmatroska requires a toolchain with C++ support # -# BR2_PACKAGE_LIBMMS is not set + +# +# libmms requires a toolchain with WCHAR support +# # BR2_PACKAGE_LIBMPEG2 is not set # BR2_PACKAGE_LIBOGG is not set -# BR2_PACKAGE_LIBPLAYER is not set + +# +# libplayer requires a toolchain with LARGEFILE support +# # BR2_PACKAGE_LIBTHEORA is not set # @@ -846,7 +939,10 @@ BR2_PACKAGE_OPENSSL_ENGINES=y # # Networking # -# BR2_PACKAGE_GLIB_NETWORKING is not set + +# +# glib-networking requires a toolchain with WCHAR support +# # BR2_PACKAGE_LIBCGI is not set # @@ -863,28 +959,55 @@ BR2_PACKAGE_OPENSSL_ENGINES=y # BR2_PACKAGE_LIBOAUTH is not set # BR2_PACKAGE_LIBMICROHTTPD is not set # BR2_PACKAGE_NEON is not set -# BR2_PACKAGE_LIBMNL is not set + +# +# libmnl requires a toolchain with LARGEFILE support +# # BR2_PACKAGE_LIBMODBUS is not set # BR2_PACKAGE_LIBMBUS is not set -# BR2_PACKAGE_LIBNETFILTER_ACCT is not set -# BR2_PACKAGE_LIBNETFILTER_CONNTRACK is not set -# BR2_PACKAGE_LIBNETFILTER_CTHELPER is not set -# BR2_PACKAGE_LIBNETFILTER_CTTIMEOUT is not set + +# +# libnetfilter_acct requires a toolchain with LARGEFILE support +# + +# +# libnetfilter_conntrack requires a toolchain with LARGEFILE support +# + +# +# libnetfilter_cthelper requires a toolchain with LARGEFILE support +# + +# +# libnetfilter_cttimout requires a toolchain with LARGEFILE support +# # BR2_PACKAGE_LIBNETFILTER_LOG is not set -# BR2_PACKAGE_LIBNETFILTER_QUEUE is not set + +# +# libnetfilter_queue requires a toolchain with LARGEFILE and IPv6 support +# # BR2_PACKAGE_LIBNFNETLINK is not set # BR2_PACKAGE_LIBNL is not set -# BR2_PACKAGE_LIBOPING is not set + +# +# liboping requires a toolchain with IPv6 support enabled +# # BR2_PACKAGE_LIBPCAP is not set # BR2_PACKAGE_LIBOSIP2 is not set # BR2_PACKAGE_LIBRSYNC is not set -# BR2_PACKAGE_LIBSOUP is not set + +# +# libsoup requires a toolchain with WCHAR support +# # BR2_PACKAGE_LIBTIRPC is not set # # libtorrent requires a toolchain with C++ and threads support enabled # -# BR2_PACKAGE_LIBUPNP is not set + +# +# libupnp requires a toolchain with LARGEFILE support +# # BR2_PACKAGE_LIBVNCSERVER is not set # BR2_PACKAGE_ORTP is not set # BR2_PACKAGE_SLIRP is not set @@ -900,7 +1023,14 @@ BR2_PACKAGE_OPENSSL_ENGINES=y # BR2_PACKAGE_APR is not set # BR2_PACKAGE_APR_UTIL is not set # BR2_PACKAGE_LIBCOFI is not set -# BR2_PACKAGE_ELFUTILS is not set + +# +# classpath requires a toolchain with IPV6 support +# + +# +# elfutils requires a toolchain with LARGEFILE and WCHAR support +# # BR2_PACKAGE_FFTW is not set # BR2_PACKAGE_LIBARGTABLE2 is not set # BR2_PACKAGE_ARGP_STANDALONE is not set @@ -917,9 +1047,14 @@ BR2_PACKAGE_OPENSSL_ENGINES=y # BR2_PACKAGE_LIBEV is not set BR2_PACKAGE_LIBFFI=y # BR2_PACKAGE_GSL is not set -# BR2_PACKAGE_LIBGLIB2 is not set -# BR2_PACKAGE_LIBICAL is not set -# BR2_PACKAGE_LIBNSPR is not set + +# +# libglib2 requires a toolchain with WCHAR support +# + +# +# libical requires a toolchain with WCHAR support +# # # libsigc++ requires a toolchain with C++ support enabled @@ -930,7 +1065,6 @@ BR2_PACKAGE_LIBFFI=y # # linux-pam requires a toolchain with WCHAR and locale support # -# BR2_PACKAGE_LTTNG_LIBUST is not set # BR2_PACKAGE_MTDEV2TUIO is not set # BR2_PACKAGE_ORC is not set @@ -998,8 +1132,10 @@ BR2_PACKAGE_LIBYAML=y # BR2_PACKAGE_GOOGLEFONTDIRECTORY is not set # BR2_PACKAGE_MCRYPT is not set # BR2_PACKAGE_MOBILE_BROADBAND_PROVIDER_INFO is not set -# BR2_PACKAGE_SHARED_MIME_INFO is not set -# BR2_PACKAGE_SNOWBALL_INIT is not set + +# +# shared-mime-info requires a toolchain with WCHAR support +# # BR2_PACKAGE_SOUND_THEME_BOREALIS is not set # BR2_PACKAGE_SOUND_THEME_FREEDESKTOP is not set @@ -1010,20 +1146,33 @@ BR2_PACKAGE_LIBYAML=y # BR2_PACKAGE_ARPTABLES is not set # BR2_PACKAGE_AVAHI is not set # BR2_PACKAGE_AXEL is not set -# BR2_PACKAGE_BLUEZ_UTILS is not set + +# +# bluez-utils require a toolchain with WCHAR and thread support +# # BR2_PACKAGE_BOA is not set -BR2_PACKAGE_BIND=y -# BR2_PACKAGE_BIND_SERVER is not set -BR2_PACKAGE_BIND_TOOLS=y -# BR2_PACKAGE_BMON is not set + +# +# bind requires a toolchain with LARGEFILE and IPV6 support +# + +# +# bmon requires a toolchain with IPv6 support +# # BR2_PACKAGE_BRIDGE_UTILS is not set # BR2_PACKAGE_CAN_UTILS is not set -# BR2_PACKAGE_CONNMAN is not set + +# +# connman needs a toolchain with IPv6, WCHAR, thread and resolver support +# # # ctorrent requires a toolchain with C++ support enabled # -# BR2_PACKAGE_CONNTRACK_TOOLS is not set + +# +# conntrack-tools requires a toolchain with IPV6 and LARGEFILE support +# # BR2_PACKAGE_CUPS is not set # BR2_PACKAGE_DHCPDUMP is not set # BR2_PACKAGE_DNSMASQ is not set @@ -1032,14 +1181,23 @@ BR2_PACKAGE_DROPBEAR=y BR2_PACKAGE_DROPBEAR_SMALL=y # BR2_PACKAGE_DROPBEAR_WTMP is not set # BR2_PACKAGE_DROPBEAR_LASTLOG is not set -# BR2_PACKAGE_EBTABLES is not set + +# +# ebtables requires a toolchain with IPv6 support +# BR2_PACKAGE_ETHTOOL=y -# BR2_PACKAGE_GESFTPSERVER is not set + +# +# gesftpserver requires a toolchain with WCHAR and threads support +# # BR2_PACKAGE_HEIRLOOM_MAILX is not set # BR2_PACKAGE_HIAWATHA is not set # BR2_PACKAGE_HOSTAPD is not set # BR2_PACKAGE_HTTPING is not set -# BR2_PACKAGE_IFTOP is not set + +# +# iftop requires IPv6 and threads support in toolchain +# # BR2_PACKAGE_INADYN is not set # @@ -1047,7 +1205,10 @@ BR2_PACKAGE_ETHTOOL=y # BR2_PACKAGE_IPROUTE2=y # BR2_PACKAGE_IPSEC_TOOLS is not set -# BR2_PACKAGE_IPSET is not set + +# +# ipset requires a toolchain with LARGEFILE support +# # BR2_PACKAGE_IPTABLES is not set # BR2_PACKAGE_IW is not set @@ -1065,32 +1226,60 @@ BR2_PACKAGE_LRZSZ=y # BR2_PACKAGE_MII_DIAG is not set # BR2_PACKAGE_MROUTED is not set # BR2_PACKAGE_MSMTP is not set -# BR2_PACKAGE_MUTT is not set -# BR2_PACKAGE_NBD is not set + +# +# mutt requires a toolchain with WCHAR support +# + +# +# nbd requires a toolchain with WCHAR support +# # BR2_PACKAGE_NCFTP is not set -# BR2_PACKAGE_NDISC6 is not set + +# +# ndisc6 requires a toolchain with IPv6 support +# # BR2_PACKAGE_NETATALK is not set # BR2_PACKAGE_NETPLUG is not set # BR2_PACKAGE_NETSNMP is not set # BR2_PACKAGE_NETSTAT_NAT is not set -# BR2_PACKAGE_NFACCT is not set + +# +# NetworkManager requires a toolchain with IPV6, LARGEFILE, WCHAR and thread support +# + +# +# nfacct requires a toolchain with LARGEFILE support +# # BR2_PACKAGE_NOIP is not set # BR2_PACKAGE_NGIRCD is not set # BR2_PACKAGE_NGREP is not set # BR2_PACKAGE_NTP is not set # BR2_PACKAGE_NUTTCP is not set -# BR2_PACKAGE_OLSR is not set + +# +# olsr requires a toolchain with IPv6 and threads support +# # BR2_PACKAGE_OPENNTPD is not set # BR2_PACKAGE_OPENSSH is not set # BR2_PACKAGE_OPENSWAN is not set -# BR2_PACKAGE_OPENVPN is not set -# BR2_PACKAGE_PORTMAP is not set + +# +# openvpn requires a toolchain with IPV6 support +# + +# +# portmap requires a toolchain with RPC support +# # BR2_PACKAGE_PPPD is not set # BR2_PACKAGE_PPTP_LINUX is not set # BR2_PACKAGE_PROFTPD is not set # BR2_PACKAGE_PROXYCHAINS_NG is not set # BR2_PACKAGE_QUAGGA is not set -# BR2_PACKAGE_RADVD is not set + +# +# radvd requires a toolchain with IPV6 support +# # BR2_PACKAGE_RPCBIND is not set # BR2_PACKAGE_RSH_REDONE is not set # BR2_PACKAGE_RSYNC is not set @@ -1118,11 +1307,26 @@ BR2_PACKAGE_LRZSZ=y # BR2_PACKAGE_THTTPD is not set # BR2_PACKAGE_TINYHTTPD is not set # BR2_PACKAGE_TN5250 is not set -# BR2_PACKAGE_TRANSMISSION is not set -# BR2_PACKAGE_TVHEADEND is not set -# BR2_PACKAGE_UDPCAST is not set -# BR2_PACKAGE_ULOGD is not set -# BR2_PACKAGE_USHARE is not set + +# +# Transmission requires a toolchain with IPv6 and threads support +# + +# +# tvheadend requires a toolchain with LARGEFILE and IPv6 support +# + +# +# udpcast requires a toolchain with LARGEFILE support +# + +# +# ulogd requires a toolchain with IPV6 and LARGEFILE support +# + +# +# ushare requires a toolchain with LARGEFILE support +# # BR2_PACKAGE_VDE2 is not set # BR2_PACKAGE_VPNC is not set # BR2_PACKAGE_VSFTPD is not set @@ -1150,9 +1354,15 @@ BR2_PACKAGE_LRZSZ=y # BR2_PACKAGE_DIALOG is not set # BR2_PACKAGE_FILE is not set # BR2_PACKAGE_GNUPG is not set -# BR2_PACKAGE_INOTIFY_TOOLS is not set + +# +# inotify-tools requires a toolchain with LARGEFILE support +# # BR2_PACKAGE_LOCKFILE_PROGS is not set -# BR2_PACKAGE_LOGROTATE is not set + +# +# logrotate requires a toolchain with WCHAR support +# # BR2_PACKAGE_LOGSURFER is not set # BR2_PACKAGE_SCREEN is not set # BR2_PACKAGE_SUDO is not set @@ -1161,8 +1371,14 @@ BR2_PACKAGE_LRZSZ=y # # System tools # -# BR2_PACKAGE_ACL is not set -# BR2_PACKAGE_ATTR is not set + +# +# acl requires a toolchain with LARGEFILE support +# + +# +# attr requires a toolchain with LARGEFILE support +# # BR2_PACKAGE_BWM_NG is not set # BR2_PACKAGE_CPULOAD is not set # BR2_PACKAGE_HTOP is not set @@ -1170,39 +1386,26 @@ BR2_PACKAGE_LRZSZ=y # BR2_PACKAGE_KMOD is not set # BR2_PACKAGE_MONIT is not set # BR2_PACKAGE_NCDU is not set -# BR2_PACKAGE_POLKIT is not set -# BR2_PACKAGE_QUOTA is not set -# BR2_PACKAGE_SUPERVISOR is not set + +# +# polkit requires a toolchain with WCHAR support +# + +# +# quota requires a toolchain with LARGEFILE + WCHAR support +# + +# +# supervisor needs the python interpreter +# # # systemd not available (depends on /dev management with udev and ipv6 support, and thread support in toolchain) # -BR2_PACKAGE_UTIL_LINUX=y -# BR2_PACKAGE_UTIL_LINUX_MOUNT is not set -# BR2_PACKAGE_UTIL_LINUX_FSCK is not set -# BR2_PACKAGE_UTIL_LINUX_LIBMOUNT is not set -BR2_PACKAGE_UTIL_LINUX_LIBUUID=y -# BR2_PACKAGE_UTIL_LINUX_UUIDD is not set -BR2_PACKAGE_UTIL_LINUX_LIBBLKID=y -# BR2_PACKAGE_UTIL_LINUX_AGETTY is not set -# BR2_PACKAGE_UTIL_LINUX_CRAMFS is not set -# BR2_PACKAGE_UTIL_LINUX_SWITCH_ROOT is not set -# BR2_PACKAGE_UTIL_LINUX_PIVOT_ROOT is not set -# BR2_PACKAGE_UTIL_LINUX_FALLOCATE is not set -# BR2_PACKAGE_UTIL_LINUX_UNSHARE is not set -# BR2_PACKAGE_UTIL_LINUX_RENAME is not set -# BR2_PACKAGE_UTIL_LINUX_SCHEDUTILS is not set -# BR2_PACKAGE_UTIL_LINUX_WALL is not set -# BR2_PACKAGE_UTIL_LINUX_PARTX is not set -# BR2_PACKAGE_UTIL_LINUX_ARCH is not set -# BR2_PACKAGE_UTIL_LINUX_INIT is not set -# BR2_PACKAGE_UTIL_LINUX_KILL is not set -# BR2_PACKAGE_UTIL_LINUX_LAST is not set -# BR2_PACKAGE_UTIL_LINUX_MESG is not set -# BR2_PACKAGE_UTIL_LINUX_RAW is not set -# BR2_PACKAGE_UTIL_LINUX_RESET is not set -# BR2_PACKAGE_UTIL_LINUX_LOGIN_UTILS is not set -# BR2_PACKAGE_UTIL_LINUX_WRITE is not set + +# +# util-linux requires a toolchain with LARGEFILE + WCHAR support +# # # Text editors and viewers From 00b7a8aad1fcc6c1dae81b523cafeda938c753bd Mon Sep 17 00:00:00 2001 From: Jeffrey Townsend Date: Tue, 31 May 2016 11:31:09 -0700 Subject: [PATCH 109/113] Revert "Menuconfig regenerated." This reverts commit 1289bdbdd4d543742f401df27fea385420cc5941. --- .../buildroot/builds/buildroot.config-arm | 711 +++++++----------- 1 file changed, 254 insertions(+), 457 deletions(-) diff --git a/packages/base/any/initrds/buildroot/builds/buildroot.config-arm b/packages/base/any/initrds/buildroot/builds/buildroot.config-arm index 79404325..6ba13a47 100644 --- a/packages/base/any/initrds/buildroot/builds/buildroot.config-arm +++ b/packages/base/any/initrds/buildroot/builds/buildroot.config-arm @@ -99,79 +99,101 @@ BR2_PACKAGE_OVERRIDE_FILE="$(TOPDIR)/local.mk" # # Toolchain # -# BR2_TOOLCHAIN_BUILDROOT is not set -BR2_TOOLCHAIN_EXTERNAL=y +BR2_TOOLCHAIN_BUILDROOT=y +# BR2_TOOLCHAIN_EXTERNAL is not set # BR2_TOOLCHAIN_CTNG is not set + +# +# Kernel Header Options +# # BR2_KERNEL_HEADERS_3_0 is not set # BR2_KERNEL_HEADERS_3_2 is not set # BR2_KERNEL_HEADERS_3_4 is not set # BR2_KERNEL_HEADERS_3_6 is not set -# BR2_KERNEL_HEADERS_3_7 is not set +BR2_KERNEL_HEADERS_3_7=y # BR2_KERNEL_HEADERS_VERSION is not set # BR2_KERNEL_HEADERS_SNAP is not set +BR2_DEFAULT_KERNEL_HEADERS="3.7.8" + +# +# uClibc Options +# # BR2_UCLIBC_VERSION_0_9_32 is not set -# BR2_UCLIBC_VERSION_0_9_33 is not set +BR2_UCLIBC_VERSION_0_9_33=y # BR2_UCLIBC_VERSION_SNAPSHOT is not set +BR2_UCLIBC_VERSION_STRING="0.9.33.2" +BR2_UCLIBC_CONFIG="toolchain/uClibc/uClibc-0.9.33.config" +# BR2_PTHREAD_DEBUG is not set +# BR2_UCLIBC_INSTALL_TEST_SUITE is not set +BR2_UCLIBC_ARM_TYPE="ARM926T" + +# +# Binutils Options +# # BR2_BINUTILS_VERSION_2_20_1 is not set # BR2_BINUTILS_VERSION_2_21 is not set -# BR2_BINUTILS_VERSION_2_21_1 is not set +BR2_BINUTILS_VERSION_2_21_1=y # BR2_BINUTILS_VERSION_2_22 is not set # BR2_BINUTILS_VERSION_2_23_1 is not set +BR2_BINUTILS_VERSION="2.21.1" +BR2_BINUTILS_EXTRA_CONFIG_OPTIONS="" + +# +# GCC Options +# # BR2_GCC_VERSION_4_3_X is not set # BR2_GCC_VERSION_4_4_X is not set # BR2_GCC_VERSION_4_5_X is not set -# BR2_GCC_VERSION_4_6_X is not set +BR2_GCC_VERSION_4_6_X=y # BR2_GCC_VERSION_4_7_X is not set # BR2_GCC_VERSION_SNAP is not set - -# -# Linaro toolchains available for Cortex-A{5,8,9,15} -# -# BR2_TOOLCHAIN_EXTERNAL_CODESOURCERY_ARM201203 is not set -# BR2_TOOLCHAIN_EXTERNAL_CODESOURCERY_ARM201109 is not set -# BR2_TOOLCHAIN_EXTERNAL_CODESOURCERY_ARM201103 is not set -BR2_TOOLCHAIN_EXTERNAL_CUSTOM=y -# BR2_TOOLCHAIN_EXTERNAL_DOWNLOAD is not set -BR2_TOOLCHAIN_EXTERNAL_PREINSTALLED=y -BR2_TOOLCHAIN_EXTERNAL_PATH="/usr/buildroot/toolchains/arm" -BR2_TOOLCHAIN_EXTERNAL_CUSTOM_PREFIX="arm-buildroot-linux-uclibcgnueabi" -BR2_TOOLCHAIN_EXTERNAL_PREFIX="arm-buildroot-linux-uclibcgnueabi" -BR2_TOOLCHAIN_EXTERNAL_UCLIBC=y -BR2_TOOLCHAIN_EXTERNAL_CUSTOM_UCLIBC=y -# BR2_TOOLCHAIN_EXTERNAL_CUSTOM_GLIBC is not set -# BR2_TOOLCHAIN_EXTERNAL_LARGEFILE is not set -# BR2_TOOLCHAIN_EXTERNAL_INET_IPV6 is not set -# BR2_TOOLCHAIN_EXTERNAL_WCHAR is not set -# BR2_TOOLCHAIN_EXTERNAL_LOCALE is not set -BR2_TOOLCHAIN_EXTERNAL_HAS_THREADS=y -BR2_TOOLCHAIN_EXTERNAL_HAS_THREADS_DEBUG=y -# BR2_TOOLCHAIN_EXTERNAL_INET_RPC is not set -# BR2_TOOLCHAIN_EXTERNAL_CXX is not set -BR2_TOOLCHAIN_EXTRA_EXTERNAL_LIBS="" +BR2_GCC_SUPPORTS_FINEGRAINEDMTUNE=y +BR2_GCC_VERSION="4.6.3" +BR2_EXTRA_GCC_CONFIG_OPTIONS="" +# BR2_INSTALL_OBJC is not set +# BR2_INSTALL_FORTRAN is not set +BR2_GCC_SHARED_LIBGCC=y +BR2_GCC_ENABLE_TLS=y +# BR2_GCC_ENABLE_OPENMP is not set # # Gdb Options # - -# -# Gdb for the target needs WCHAR and threads support in toolchain -# -# BR2_TOOLCHAIN_EXTERNAL_GDB_SERVER_COPY is not set +# BR2_PACKAGE_GDB is not set +# BR2_PACKAGE_GDB_SERVER is not set +# BR2_PACKAGE_GDB_HOST is not set +BR2_LARGEFILE=y +BR2_INET_IPV6=y +BR2_TOOLCHAIN_HAS_NATIVE_RPC=y +BR2_USE_WCHAR=y BR2_TOOLCHAIN_HAS_THREADS=y -BR2_TOOLCHAIN_HAS_THREADS_DEBUG=y BR2_TOOLCHAIN_HAS_THREADS_DEBUG_IF_NEEDED=y BR2_TOOLCHAIN_HAS_SHADOW_PASSWORDS=y # BR2_ENABLE_LOCALE_PURGE is not set +BR2_GENERATE_LOCALE="" BR2_NEEDS_GETTEXT=y BR2_USE_MMU=y BR2_PREFER_SOFT_FLOAT=y +BR2_SOFT_FLOAT=y BR2_TARGET_OPTIMIZATION="-pipe" BR2_TARGET_LDFLAGS="" # BR2_ECLIPSE_REGISTER is not set + +# +# Toolchain Options +# +BR2_TOOLCHAIN_BUILDROOT_LARGEFILE=y +BR2_TOOLCHAIN_BUILDROOT_INET_IPV6=y +BR2_TOOLCHAIN_BUILDROOT_INET_RPC=y +BR2_TOOLCHAIN_BUILDROOT_WCHAR=y +# BR2_TOOLCHAIN_BUILDROOT_LOCALE is not set +# BR2_TOOLCHAIN_BUILDROOT_CXX is not set +# BR2_TOOLCHAIN_BUILDROOT_USE_SSP is not set # BR2_PTHREADS_NONE is not set # BR2_PTHREADS is not set # BR2_PTHREADS_OLD is not set -# BR2_PTHREADS_NATIVE is not set +BR2_PTHREADS_NATIVE=y +# BR2_ELF2FLT is not set # # System configuration @@ -187,10 +209,6 @@ BR2_TARGET_GENERIC_PASSWD_METHOD="md5" # BR2_ROOTFS_DEVICE_CREATION_DYNAMIC_DEVTMPFS is not set BR2_ROOTFS_DEVICE_CREATION_DYNAMIC_MDEV=y # BR2_ROOTFS_DEVICE_CREATION_DYNAMIC_UDEV is not set - -# -# udev requires a toolchain with LARGEFILE + WCHAR support -# # BR2_INIT_BUSYBOX is not set # BR2_INIT_SYSV is not set @@ -222,10 +240,7 @@ BR2_PACKAGE_BUSYBOX_CONFIG="../busybox.config" # # Audio and video applications # - -# -# alsa-utils requires a toolchain with LARGEFILE and threads support -# +# BR2_PACKAGE_ALSA_UTILS is not set # BR2_PACKAGE_AUMIX is not set # @@ -233,18 +248,8 @@ BR2_PACKAGE_BUSYBOX_CONFIG="../busybox.config" # # BR2_PACKAGE_FAAD2 is not set # BR2_PACKAGE_FLAC is not set - -# -# ffmpeg requires a toolchain with LARGEFILE and IPV6 support -# - -# -# gstreamer requires a toolchain with WCHAR support -# - -# -# gst-ffmpeg requires a toolchain with LARGEFILE and IPV6 support -# +# BR2_PACKAGE_FFMPEG is not set +# BR2_PACKAGE_GSTREAMER is not set # BR2_PACKAGE_LAME is not set # BR2_PACKAGE_MADPLAY is not set @@ -252,16 +257,10 @@ BR2_PACKAGE_BUSYBOX_CONFIG="../busybox.config" # mpd requires a toolchain with C++ and WCHAR support # # BR2_PACKAGE_MPG123 is not set - -# -# mplayer requires a toolchain with LARGEFILE support -# +# BR2_PACKAGE_MPLAYER is not set # BR2_PACKAGE_MUSEPACK is not set # BR2_PACKAGE_OPUS_TOOLS is not set - -# -# pulseaudio requires a toolchain with WCHAR, LARGEFILE and threads support -# +# BR2_PACKAGE_PULSEAUDIO is not set # BR2_PACKAGE_VORBIS_TOOLS is not set # BR2_PACKAGE_WAVPACK is not set # BR2_PACKAGE_YAVTA is not set @@ -283,17 +282,11 @@ BR2_PACKAGE_XZ=y # # BR2_PACKAGE_CACHE_CALIBRATOR is not set # BR2_PACKAGE_DHRYSTONE is not set - -# -# dstat requires a toolchain with WCHAR support -# +# BR2_PACKAGE_DSTAT is not set # BR2_PACKAGE_DMALLOC is not set BR2_PACKAGE_KEXEC=y BR2_PACKAGE_KEXEC_ZLIB=y - -# -# latencytop requires a toolchain with WCHAR support -# +# BR2_PACKAGE_LATENCYTOP is not set # BR2_PACKAGE_LMBENCH is not set # BR2_PACKAGE_LTP_TESTSUITE is not set # BR2_PACKAGE_LTRACE is not set @@ -311,10 +304,6 @@ BR2_PACKAGE_KEXEC_ZLIB=y # BR2_PACKAGE_RT_TESTS is not set BR2_PACKAGE_STRACE=y # BR2_PACKAGE_STRESS is not set - -# -# sysprof requires a toolchain with WCHAR support -# # BR2_PACKAGE_WHETSTONE is not set # BR2_PACKAGE_PV is not set @@ -322,25 +311,12 @@ BR2_PACKAGE_STRACE=y # Development tools # # BR2_PACKAGE_BINUTILS is not set - -# -# bison requires a toolchain with WCHAR support -# +# BR2_PACKAGE_BISON is not set # BR2_PACKAGE_BSDIFF is not set - -# -# bustle requires a toolchain with WCHAR support -# - -# -# cvs requires a toolchain with WCHAR support -# +# BR2_PACKAGE_CVS is not set # BR2_PACKAGE_DISTCC is not set # BR2_PACKAGE_FLEX is not set - -# -# gettext requires a toolchain with WCHAR support -# +# BR2_PACKAGE_GETTEXT is not set # BR2_PACKAGE_GMP is not set # @@ -349,16 +325,10 @@ BR2_PACKAGE_STRACE=y # BR2_PACKAGE_MPC is not set # BR2_PACKAGE_MPFR is not set # BR2_PACKAGE_LIBTOOL is not set - -# -# m4 requires a toolchain with WCHAR support -# +# BR2_PACKAGE_M4 is not set # BR2_PACKAGE_PKGCONF is not set # BR2_PACKAGE_SSTRIP is not set - -# -# vala requires a toolchain with WCHAR support -# +# BR2_PACKAGE_VALA is not set # # Games @@ -373,10 +343,7 @@ BR2_PACKAGE_STRACE=y # # Graphic applications # - -# -# rrdtool requires a toolchain with WCHAR support -# +# BR2_PACKAGE_RRDTOOL is not set # # graphic libraries @@ -400,18 +367,12 @@ BR2_PACKAGE_STRACE=y # # other GUIs # - -# -# EFL requires WCHAR support in toolchain -# +# BR2_PACKAGE_EFL is not set # # qt requires a toolchain with C++ support enabled # - -# -# X.org requires a toolchain with WCHAR support -# +# BR2_PACKAGE_XORG7 is not set # # X libraries and helper libraries @@ -425,10 +386,7 @@ BR2_PACKAGE_STRACE=y # # X applications # - -# -# gob2 requires a toolchain with WCHAR support -# +# BR2_PACKAGE_GOB2 is not set # # midori requires C++, WCHAR in toolchain and libgtk2 @@ -439,26 +397,34 @@ BR2_PACKAGE_STRACE=y # # BR2_PACKAGE_CIFS_UTILS is not set # BR2_PACKAGE_CRAMFS is not set - -# -# curlftpfs requires a toolchain with LARGEFILE, WCHAR and threads support -# - -# -# dosfstools requires a toolchain with LARGEFILE support -# - -# -# e2fsprogs requires a toolchain with LARGEFILE + WCHAR support -# - -# -# flashbench requires a toolchain with LARGEFILE support -# - -# -# genext2fs requires a toolchain with LARGEFILE support -# +# BR2_PACKAGE_CURLFTPFS is not set +BR2_PACKAGE_DOSFSTOOLS=y +BR2_PACKAGE_DOSFSTOOLS_MKDOSFS=y +BR2_PACKAGE_DOSFSTOOLS_DOSFSCK=y +BR2_PACKAGE_DOSFSTOOLS_DOSFSLABEL=y +BR2_PACKAGE_E2FSPROGS=y +# BR2_PACKAGE_E2FSPROGS_BADBLOCKS is not set +# BR2_PACKAGE_E2FSPROGS_CHATTR is not set +# BR2_PACKAGE_E2FSPROGS_DEBUGFS is not set +BR2_PACKAGE_E2FSPROGS_DUMPE2FS=y +# BR2_PACKAGE_E2FSPROGS_E2FREEFRAG is not set +BR2_PACKAGE_E2FSPROGS_E2FSCK=y +# BR2_PACKAGE_E2FSPROGS_E2IMAGE is not set +BR2_PACKAGE_E2FSPROGS_E2LABEL=y +# BR2_PACKAGE_E2FSPROGS_E2UNDO is not set +# BR2_PACKAGE_E2FSPROGS_E4DEFRAG is not set +# BR2_PACKAGE_E2FSPROGS_FILEFRAG is not set +# BR2_PACKAGE_E2FSPROGS_FINDFS is not set +# BR2_PACKAGE_E2FSPROGS_FSCK is not set +# BR2_PACKAGE_E2FSPROGS_LOGSAVE is not set +# BR2_PACKAGE_E2FSPROGS_LSATTR is not set +BR2_PACKAGE_E2FSPROGS_MKE2FS=y +# BR2_PACKAGE_E2FSPROGS_MKLOSTFOUND is not set +# BR2_PACKAGE_E2FSPROGS_RESIZE2FS is not set +BR2_PACKAGE_E2FSPROGS_TUNE2FS=y +BR2_PACKAGE_E2FSPROGS_UUIDGEN=y +# BR2_PACKAGE_FLASHBENCH is not set +# BR2_PACKAGE_GENEXT2FS is not set # BR2_PACKAGE_GENROMFS is not set # BR2_PACKAGE_MAKEDEVS is not set BR2_PACKAGE_MTD=y @@ -486,10 +452,7 @@ BR2_PACKAGE_MTD_FLASH_UNLOCK=y # BR2_PACKAGE_MTD_NANDWRITE is not set # BR2_PACKAGE_MTD_NFTLDUMP is not set # BR2_PACKAGE_MTD_NFTL_FORMAT is not set - -# -# recv_image requires a toolchain with IPv6 support -# +# BR2_PACKAGE_MTD_RECV_IMAGE is not set # BR2_PACKAGE_MTD_RFDDUMP is not set # BR2_PACKAGE_MTD_RFDFORMAT is not set # BR2_PACKAGE_MTD_SERVE_IMAGE is not set @@ -506,30 +469,16 @@ BR2_PACKAGE_MTD_UBINFO=y BR2_PACKAGE_MTD_UBIRMVOL=y # BR2_PACKAGE_MTD_UBIRSVOL is not set BR2_PACKAGE_MTD_UBIUPDATEVOL=y - -# -# nfs-utils requires a toolchain with LARGEFILE support -# - -# -# ntfs-3g requires a toolchain with LARGEFILE and WCHAR support -# - -# -# squashfs requires a toolchain with LARGEFILE and threads support -# - -# -# sshfs requires a toolchain with LARGEFILE, WCHAR and threads support -# - -# -# unionfs requires a toolchain with LARGEFILE and threads support -# - -# -# xfsprogs requires a toolchain with LARGEFILE + WCHAR support -# +# BR2_PACKAGE_NFS_UTILS is not set +# BR2_PACKAGE_NTFS_3G is not set +BR2_PACKAGE_SQUASHFS=y +BR2_PACKAGE_SQUASHFS_GZIP=y +# BR2_PACKAGE_SQUASHFS_LZMA is not set +# BR2_PACKAGE_SQUASHFS_LZO is not set +# BR2_PACKAGE_SQUASHFS_XZ is not set +# BR2_PACKAGE_SSHFS is not set +# BR2_PACKAGE_UNIONFS is not set +# BR2_PACKAGE_XFSPROGS is not set # # Hardware handling @@ -544,20 +493,11 @@ BR2_PACKAGE_MTD_UBIUPDATEVOL=y # BR2_PACKAGE_RPI_FIRMWARE is not set # BR2_PACKAGE_UX500_FIRMWARE is not set # BR2_PACKAGE_ZD1211_FIRMWARE is not set - -# -# cdrkit requires a toolchain with LARGEFILE support -# +# BR2_PACKAGE_CDRKIT is not set # BR2_PACKAGE_DBUS is not set - -# -# dmraid requires a toolchain with LARGEFILE support -# +# BR2_PACKAGE_DMRAID is not set # BR2_PACKAGE_DVB_APPS is not set - -# -# dvbsnoop requires a toolchain with LARGEFILE support -# +# BR2_PACKAGE_DVBSNOOP is not set # BR2_PACKAGE_EEPROG is not set # BR2_PACKAGE_EVTEST is not set # BR2_PACKAGE_FCONFIG is not set @@ -570,10 +510,7 @@ BR2_PACKAGE_MTD_UBIUPDATEVOL=y # gdisk requires a toolchain with LARGEFILE/WCHAR/C++ support enabled # # BR2_PACKAGE_GPSD is not set - -# -# gvfs requires a toolchain with LARGEFILE and WCHAR support -# +# BR2_PACKAGE_GVFS is not set # BR2_PACKAGE_HWDATA is not set # BR2_PACKAGE_I2C_TOOLS is not set # BR2_PACKAGE_INPUT_EVENT_DAEMON is not set @@ -588,39 +525,23 @@ BR2_PACKAGE_MTD_UBIUPDATEVOL=y # lshw requires a toolchain with C++, LARGEFILE & WCHAR support enabled # # BR2_PACKAGE_LSUIO is not set - -# -# lvm2 requires a toolchain with LARGEFILE support -# +BR2_PACKAGE_LVM2=y +# BR2_PACKAGE_LVM2_DMSETUP_ONLY is not set +# BR2_PACKAGE_LVM2_APP_LIBRARY is not set # BR2_PACKAGE_MDADM is not set # BR2_PACKAGE_MEDIA_CTL is not set - -# -# memtester requires a toolchain with LARGEFILE support -# - -# -# minicom requires a toolchain with WCHAR support -# +# BR2_PACKAGE_MEMTESTER is not set +# BR2_PACKAGE_MINICOM is not set # BR2_PACKAGE_NANOCOM is not set - -# -# neard requires a toolchain with WCHAR and threads support -# - -# -# ofono requires a toolchain with WCHAR and thread support -# +# BR2_PACKAGE_NEARD is not set +# BR2_PACKAGE_OFONO is not set # BR2_PACKAGE_OPEN2300 is not set # BR2_PACKAGE_OPENOCD is not set # # owl-linux requires a Linux kernel # - -# -# parted requires a toolchain with LARGEFILE+WCHAR support -# +BR2_PACKAGE_PARTED=y # BR2_PACKAGE_PCIUTILS is not set # BR2_PACKAGE_PICOCOM is not set # BR2_PACKAGE_RNG_TOOLS is not set @@ -631,10 +552,7 @@ BR2_PACKAGE_MTD_UBIUPDATEVOL=y # BR2_PACKAGE_SANE_BACKENDS is not set # BR2_PACKAGE_SDPARM is not set # BR2_PACKAGE_SETSERIAL is not set - -# -# sg3-utils requires a toolchain with LARGEFILE and threads support -# +# BR2_PACKAGE_SG3_UTILS is not set # # smartmontools requires a toolchain with C++ support enabled @@ -665,29 +583,55 @@ BR2_PACKAGE_UBOOT_TOOLS_FWPRINTENV=y # # BR2_PACKAGE_ERLANG is not set # BR2_PACKAGE_HASERL is not set - -# -# jamvm requires a toolchain with IPV6 support -# +# BR2_PACKAGE_JAMVM is not set # BR2_PACKAGE_LUA is not set # BR2_PACKAGE_LUAJIT is not set # BR2_PACKAGE_PERL is not set # BR2_PACKAGE_PHP is not set - -# -# python requires a toolchain with WCHAR support -# -# BR2_PACKAGE_PYTHON_PY_ONLY is not set +BR2_PACKAGE_PYTHON=y +BR2_PACKAGE_PYTHON_PY_ONLY=y # BR2_PACKAGE_PYTHON_PYC_ONLY is not set # BR2_PACKAGE_PYTHON_PY_PYC is not set # -# python3 requires a toolchain with WCHAR support +# core python modules # # -# ruby requires a toolchain with WCHAR support +# The following modules are unusual or require extra libraries # +BR2_PACKAGE_PYTHON_BZIP2=y +# BR2_PACKAGE_PYTHON_BSDDB is not set +# BR2_PACKAGE_PYTHON_CODECSCJK is not set +# BR2_PACKAGE_PYTHON_CURSES is not set +# BR2_PACKAGE_PYTHON_PYEXPAT is not set +BR2_PACKAGE_PYTHON_READLINE=y +BR2_PACKAGE_PYTHON_SSL=y +# BR2_PACKAGE_PYTHON_UNICODEDATA is not set +# BR2_PACKAGE_PYTHON_SQLITE is not set +BR2_PACKAGE_PYTHON_ZLIB=y +# BR2_PACKAGE_PYTHON3 is not set + +# +# external python modules +# +# BR2_PACKAGE_PYTHON_BOTTLE is not set +# BR2_PACKAGE_PYTHON_DPKT is not set +# BR2_PACKAGE_PYTHON_ID3 is not set +# BR2_PACKAGE_PYTHON_MAD is not set +# BR2_PACKAGE_PYTHON_MELD3 is not set +# BR2_PACKAGE_PYTHON_NETIFACES is not set +# BR2_PACKAGE_PYTHON_NFC is not set +# BR2_PACKAGE_PYTHON_PROTOBUF is not set +# BR2_PACKAGE_PYTHON_PYGAME is not set +# BR2_PACKAGE_PYTHON_PYPARSING is not set +# BR2_PACKAGE_PYTHON_SERIAL is not set +# BR2_PACKAGE_PYTHON_SETUPTOOLS is not set +BR2_PACKAGE_PYTHON_PYPARTED=y +BR2_PACKAGE_PYTHON_YAML=y +BR2_PACKAGE_PYTHON_DNSPYTHON=y +BR2_PACKAGE_PYTHON_PYROUTE2=y +# BR2_PACKAGE_RUBY is not set # BR2_PACKAGE_TCL is not set # @@ -710,16 +654,10 @@ BR2_PACKAGE_UBOOT_TOOLS_FWPRINTENV=y # BR2_PACKAGE_LIBID3TAG is not set # BR2_PACKAGE_LIBLO is not set # BR2_PACKAGE_LIBMAD is not set - -# -# libmpd requires a toolchain with WCHAR support -# +# BR2_PACKAGE_LIBMPD is not set # BR2_PACKAGE_LIBREPLAYGAIN is not set # BR2_PACKAGE_LIBSAMPLERATE is not set - -# -# libsndfile requires a toolchain with LARGEFILE support -# +# BR2_PACKAGE_LIBSNDFILE is not set # BR2_PACKAGE_LIBVORBIS is not set # BR2_PACKAGE_OPUS is not set # BR2_PACKAGE_PORTAUDIO is not set @@ -737,10 +675,7 @@ BR2_PACKAGE_UBOOT_TOOLS_FWPRINTENV=y # # Compression and decompression # - -# -# libarchive requires a toolchain with WCHAR support -# +# BR2_PACKAGE_LIBARCHIVE is not set # BR2_PACKAGE_LZO is not set BR2_PACKAGE_ZLIB=y @@ -748,14 +683,12 @@ BR2_PACKAGE_ZLIB=y # Crypto # # BR2_PACKAGE_BEECRYPT is not set - -# -# gnutls requires a toolchain with WCHAR support -# +# BR2_PACKAGE_GNUTLS is not set BR2_PACKAGE_LIBGCRYPT=y BR2_PACKAGE_LIBGPG_ERROR=y # BR2_PACKAGE_LIBMCRYPT is not set # BR2_PACKAGE_LIBMHASH is not set +# BR2_PACKAGE_LIBNSS is not set BR2_PACKAGE_LIBSHA1=y # BR2_PACKAGE_NETTLE is not set # BR2_PACKAGE_OCF_LINUX is not set @@ -780,26 +713,17 @@ BR2_PACKAGE_OPENSSL_ENGINES=y # # Filesystem # - -# -# gamin requires a toolchain with WCHAR support -# +# BR2_PACKAGE_GAMIN is not set # BR2_PACKAGE_LIBCONFIG is not set # BR2_PACKAGE_LIBCONFUSE is not set - -# -# libfuse requires a toolchain with LARGEFILE and threads support -# +# BR2_PACKAGE_LIBFUSE is not set # BR2_PACKAGE_LIBLOCKFILE is not set # BR2_PACKAGE_LIBSYSFS is not set # # Graphics # - -# -# atk requires a toolchain with WCHAR support -# +# BR2_PACKAGE_ATK is not set # BR2_PACKAGE_CAIRO is not set # BR2_PACKAGE_FONTCONFIG is not set # BR2_PACKAGE_FREETYPE is not set @@ -810,6 +734,7 @@ BR2_PACKAGE_OPENSSL_ENGINES=y # BR2_PACKAGE_LIBDMTX is not set # BR2_PACKAGE_LIBEXIF is not set # BR2_PACKAGE_LIBGEOTIFF is not set +# BR2_PACKAGE_GDK_PIXBUF is not set # # libgtk2 requires a toolchain with WCHAR and C++ support @@ -870,15 +795,9 @@ BR2_PACKAGE_OPENSSL_ENGINES=y # BR2_PACKAGE_LIBNFC is not set # BR2_PACKAGE_LIBNFC_LLCP is not set # BR2_PACKAGE_LIBUSB is not set - -# -# libv4l requires a toolchain with LARGEFILE support -# +# BR2_PACKAGE_LIBV4L is not set # BR2_PACKAGE_MTDEV is not set - -# -# neardal requires a toolchain with WCHAR and threads support -# +# BR2_PACKAGE_NEARDAL is not set # BR2_PACKAGE_PCSC_LITE is not set # @@ -894,14 +813,8 @@ BR2_PACKAGE_OPENSSL_ENGINES=y # # Multimedia # - -# -# libdvdread requires a toolchain with LARGEFILE support -# - -# -# libdvdnav requires a toolchain with LARGEFILE and thread support -# +# BR2_PACKAGE_LIBDVDREAD is not set +# BR2_PACKAGE_LIBDVDNAV is not set # # libebml requires a toolchain with C++ support @@ -916,16 +829,10 @@ BR2_PACKAGE_OPENSSL_ENGINES=y # # libmatroska requires a toolchain with C++ support # - -# -# libmms requires a toolchain with WCHAR support -# +# BR2_PACKAGE_LIBMMS is not set # BR2_PACKAGE_LIBMPEG2 is not set # BR2_PACKAGE_LIBOGG is not set - -# -# libplayer requires a toolchain with LARGEFILE support -# +# BR2_PACKAGE_LIBPLAYER is not set # BR2_PACKAGE_LIBTHEORA is not set # @@ -939,10 +846,7 @@ BR2_PACKAGE_OPENSSL_ENGINES=y # # Networking # - -# -# glib-networking requires a toolchain with WCHAR support -# +# BR2_PACKAGE_GLIB_NETWORKING is not set # BR2_PACKAGE_LIBCGI is not set # @@ -959,55 +863,28 @@ BR2_PACKAGE_OPENSSL_ENGINES=y # BR2_PACKAGE_LIBOAUTH is not set # BR2_PACKAGE_LIBMICROHTTPD is not set # BR2_PACKAGE_NEON is not set - -# -# libmnl requires a toolchain with LARGEFILE support -# +# BR2_PACKAGE_LIBMNL is not set # BR2_PACKAGE_LIBMODBUS is not set # BR2_PACKAGE_LIBMBUS is not set - -# -# libnetfilter_acct requires a toolchain with LARGEFILE support -# - -# -# libnetfilter_conntrack requires a toolchain with LARGEFILE support -# - -# -# libnetfilter_cthelper requires a toolchain with LARGEFILE support -# - -# -# libnetfilter_cttimout requires a toolchain with LARGEFILE support -# +# BR2_PACKAGE_LIBNETFILTER_ACCT is not set +# BR2_PACKAGE_LIBNETFILTER_CONNTRACK is not set +# BR2_PACKAGE_LIBNETFILTER_CTHELPER is not set +# BR2_PACKAGE_LIBNETFILTER_CTTIMEOUT is not set # BR2_PACKAGE_LIBNETFILTER_LOG is not set - -# -# libnetfilter_queue requires a toolchain with LARGEFILE and IPv6 support -# +# BR2_PACKAGE_LIBNETFILTER_QUEUE is not set # BR2_PACKAGE_LIBNFNETLINK is not set # BR2_PACKAGE_LIBNL is not set - -# -# liboping requires a toolchain with IPv6 support enabled -# +# BR2_PACKAGE_LIBOPING is not set # BR2_PACKAGE_LIBPCAP is not set # BR2_PACKAGE_LIBOSIP2 is not set # BR2_PACKAGE_LIBRSYNC is not set - -# -# libsoup requires a toolchain with WCHAR support -# +# BR2_PACKAGE_LIBSOUP is not set # BR2_PACKAGE_LIBTIRPC is not set # # libtorrent requires a toolchain with C++ and threads support enabled # - -# -# libupnp requires a toolchain with LARGEFILE support -# +# BR2_PACKAGE_LIBUPNP is not set # BR2_PACKAGE_LIBVNCSERVER is not set # BR2_PACKAGE_ORTP is not set # BR2_PACKAGE_SLIRP is not set @@ -1023,14 +900,7 @@ BR2_PACKAGE_OPENSSL_ENGINES=y # BR2_PACKAGE_APR is not set # BR2_PACKAGE_APR_UTIL is not set # BR2_PACKAGE_LIBCOFI is not set - -# -# classpath requires a toolchain with IPV6 support -# - -# -# elfutils requires a toolchain with LARGEFILE and WCHAR support -# +# BR2_PACKAGE_ELFUTILS is not set # BR2_PACKAGE_FFTW is not set # BR2_PACKAGE_LIBARGTABLE2 is not set # BR2_PACKAGE_ARGP_STANDALONE is not set @@ -1047,14 +917,9 @@ BR2_PACKAGE_OPENSSL_ENGINES=y # BR2_PACKAGE_LIBEV is not set BR2_PACKAGE_LIBFFI=y # BR2_PACKAGE_GSL is not set - -# -# libglib2 requires a toolchain with WCHAR support -# - -# -# libical requires a toolchain with WCHAR support -# +# BR2_PACKAGE_LIBGLIB2 is not set +# BR2_PACKAGE_LIBICAL is not set +# BR2_PACKAGE_LIBNSPR is not set # # libsigc++ requires a toolchain with C++ support enabled @@ -1065,6 +930,7 @@ BR2_PACKAGE_LIBFFI=y # # linux-pam requires a toolchain with WCHAR and locale support # +# BR2_PACKAGE_LTTNG_LIBUST is not set # BR2_PACKAGE_MTDEV2TUIO is not set # BR2_PACKAGE_ORC is not set @@ -1132,10 +998,8 @@ BR2_PACKAGE_LIBYAML=y # BR2_PACKAGE_GOOGLEFONTDIRECTORY is not set # BR2_PACKAGE_MCRYPT is not set # BR2_PACKAGE_MOBILE_BROADBAND_PROVIDER_INFO is not set - -# -# shared-mime-info requires a toolchain with WCHAR support -# +# BR2_PACKAGE_SHARED_MIME_INFO is not set +# BR2_PACKAGE_SNOWBALL_INIT is not set # BR2_PACKAGE_SOUND_THEME_BOREALIS is not set # BR2_PACKAGE_SOUND_THEME_FREEDESKTOP is not set @@ -1146,33 +1010,20 @@ BR2_PACKAGE_LIBYAML=y # BR2_PACKAGE_ARPTABLES is not set # BR2_PACKAGE_AVAHI is not set # BR2_PACKAGE_AXEL is not set - -# -# bluez-utils require a toolchain with WCHAR and thread support -# +# BR2_PACKAGE_BLUEZ_UTILS is not set # BR2_PACKAGE_BOA is not set - -# -# bind requires a toolchain with LARGEFILE and IPV6 support -# - -# -# bmon requires a toolchain with IPv6 support -# +BR2_PACKAGE_BIND=y +# BR2_PACKAGE_BIND_SERVER is not set +BR2_PACKAGE_BIND_TOOLS=y +# BR2_PACKAGE_BMON is not set # BR2_PACKAGE_BRIDGE_UTILS is not set # BR2_PACKAGE_CAN_UTILS is not set - -# -# connman needs a toolchain with IPv6, WCHAR, thread and resolver support -# +# BR2_PACKAGE_CONNMAN is not set # # ctorrent requires a toolchain with C++ support enabled # - -# -# conntrack-tools requires a toolchain with IPV6 and LARGEFILE support -# +# BR2_PACKAGE_CONNTRACK_TOOLS is not set # BR2_PACKAGE_CUPS is not set # BR2_PACKAGE_DHCPDUMP is not set # BR2_PACKAGE_DNSMASQ is not set @@ -1181,23 +1032,14 @@ BR2_PACKAGE_DROPBEAR=y BR2_PACKAGE_DROPBEAR_SMALL=y # BR2_PACKAGE_DROPBEAR_WTMP is not set # BR2_PACKAGE_DROPBEAR_LASTLOG is not set - -# -# ebtables requires a toolchain with IPv6 support -# +# BR2_PACKAGE_EBTABLES is not set BR2_PACKAGE_ETHTOOL=y - -# -# gesftpserver requires a toolchain with WCHAR and threads support -# +# BR2_PACKAGE_GESFTPSERVER is not set # BR2_PACKAGE_HEIRLOOM_MAILX is not set # BR2_PACKAGE_HIAWATHA is not set # BR2_PACKAGE_HOSTAPD is not set # BR2_PACKAGE_HTTPING is not set - -# -# iftop requires IPv6 and threads support in toolchain -# +# BR2_PACKAGE_IFTOP is not set # BR2_PACKAGE_INADYN is not set # @@ -1205,10 +1047,7 @@ BR2_PACKAGE_ETHTOOL=y # BR2_PACKAGE_IPROUTE2=y # BR2_PACKAGE_IPSEC_TOOLS is not set - -# -# ipset requires a toolchain with LARGEFILE support -# +# BR2_PACKAGE_IPSET is not set # BR2_PACKAGE_IPTABLES is not set # BR2_PACKAGE_IW is not set @@ -1226,60 +1065,32 @@ BR2_PACKAGE_LRZSZ=y # BR2_PACKAGE_MII_DIAG is not set # BR2_PACKAGE_MROUTED is not set # BR2_PACKAGE_MSMTP is not set - -# -# mutt requires a toolchain with WCHAR support -# - -# -# nbd requires a toolchain with WCHAR support -# +# BR2_PACKAGE_MUTT is not set +# BR2_PACKAGE_NBD is not set # BR2_PACKAGE_NCFTP is not set - -# -# ndisc6 requires a toolchain with IPv6 support -# +# BR2_PACKAGE_NDISC6 is not set # BR2_PACKAGE_NETATALK is not set # BR2_PACKAGE_NETPLUG is not set # BR2_PACKAGE_NETSNMP is not set # BR2_PACKAGE_NETSTAT_NAT is not set - -# -# NetworkManager requires a toolchain with IPV6, LARGEFILE, WCHAR and thread support -# - -# -# nfacct requires a toolchain with LARGEFILE support -# +# BR2_PACKAGE_NFACCT is not set # BR2_PACKAGE_NOIP is not set # BR2_PACKAGE_NGIRCD is not set # BR2_PACKAGE_NGREP is not set # BR2_PACKAGE_NTP is not set # BR2_PACKAGE_NUTTCP is not set - -# -# olsr requires a toolchain with IPv6 and threads support -# +# BR2_PACKAGE_OLSR is not set # BR2_PACKAGE_OPENNTPD is not set # BR2_PACKAGE_OPENSSH is not set # BR2_PACKAGE_OPENSWAN is not set - -# -# openvpn requires a toolchain with IPV6 support -# - -# -# portmap requires a toolchain with RPC support -# +# BR2_PACKAGE_OPENVPN is not set +# BR2_PACKAGE_PORTMAP is not set # BR2_PACKAGE_PPPD is not set # BR2_PACKAGE_PPTP_LINUX is not set # BR2_PACKAGE_PROFTPD is not set # BR2_PACKAGE_PROXYCHAINS_NG is not set # BR2_PACKAGE_QUAGGA is not set - -# -# radvd requires a toolchain with IPV6 support -# +# BR2_PACKAGE_RADVD is not set # BR2_PACKAGE_RPCBIND is not set # BR2_PACKAGE_RSH_REDONE is not set # BR2_PACKAGE_RSYNC is not set @@ -1307,26 +1118,11 @@ BR2_PACKAGE_LRZSZ=y # BR2_PACKAGE_THTTPD is not set # BR2_PACKAGE_TINYHTTPD is not set # BR2_PACKAGE_TN5250 is not set - -# -# Transmission requires a toolchain with IPv6 and threads support -# - -# -# tvheadend requires a toolchain with LARGEFILE and IPv6 support -# - -# -# udpcast requires a toolchain with LARGEFILE support -# - -# -# ulogd requires a toolchain with IPV6 and LARGEFILE support -# - -# -# ushare requires a toolchain with LARGEFILE support -# +# BR2_PACKAGE_TRANSMISSION is not set +# BR2_PACKAGE_TVHEADEND is not set +# BR2_PACKAGE_UDPCAST is not set +# BR2_PACKAGE_ULOGD is not set +# BR2_PACKAGE_USHARE is not set # BR2_PACKAGE_VDE2 is not set # BR2_PACKAGE_VPNC is not set # BR2_PACKAGE_VSFTPD is not set @@ -1354,15 +1150,9 @@ BR2_PACKAGE_LRZSZ=y # BR2_PACKAGE_DIALOG is not set # BR2_PACKAGE_FILE is not set # BR2_PACKAGE_GNUPG is not set - -# -# inotify-tools requires a toolchain with LARGEFILE support -# +# BR2_PACKAGE_INOTIFY_TOOLS is not set # BR2_PACKAGE_LOCKFILE_PROGS is not set - -# -# logrotate requires a toolchain with WCHAR support -# +# BR2_PACKAGE_LOGROTATE is not set # BR2_PACKAGE_LOGSURFER is not set # BR2_PACKAGE_SCREEN is not set # BR2_PACKAGE_SUDO is not set @@ -1371,14 +1161,8 @@ BR2_PACKAGE_LRZSZ=y # # System tools # - -# -# acl requires a toolchain with LARGEFILE support -# - -# -# attr requires a toolchain with LARGEFILE support -# +# BR2_PACKAGE_ACL is not set +# BR2_PACKAGE_ATTR is not set # BR2_PACKAGE_BWM_NG is not set # BR2_PACKAGE_CPULOAD is not set # BR2_PACKAGE_HTOP is not set @@ -1386,26 +1170,39 @@ BR2_PACKAGE_LRZSZ=y # BR2_PACKAGE_KMOD is not set # BR2_PACKAGE_MONIT is not set # BR2_PACKAGE_NCDU is not set - -# -# polkit requires a toolchain with WCHAR support -# - -# -# quota requires a toolchain with LARGEFILE + WCHAR support -# - -# -# supervisor needs the python interpreter -# +# BR2_PACKAGE_POLKIT is not set +# BR2_PACKAGE_QUOTA is not set +# BR2_PACKAGE_SUPERVISOR is not set # # systemd not available (depends on /dev management with udev and ipv6 support, and thread support in toolchain) # - -# -# util-linux requires a toolchain with LARGEFILE + WCHAR support -# +BR2_PACKAGE_UTIL_LINUX=y +# BR2_PACKAGE_UTIL_LINUX_MOUNT is not set +# BR2_PACKAGE_UTIL_LINUX_FSCK is not set +# BR2_PACKAGE_UTIL_LINUX_LIBMOUNT is not set +BR2_PACKAGE_UTIL_LINUX_LIBUUID=y +# BR2_PACKAGE_UTIL_LINUX_UUIDD is not set +BR2_PACKAGE_UTIL_LINUX_LIBBLKID=y +# BR2_PACKAGE_UTIL_LINUX_AGETTY is not set +# BR2_PACKAGE_UTIL_LINUX_CRAMFS is not set +# BR2_PACKAGE_UTIL_LINUX_SWITCH_ROOT is not set +# BR2_PACKAGE_UTIL_LINUX_PIVOT_ROOT is not set +# BR2_PACKAGE_UTIL_LINUX_FALLOCATE is not set +# BR2_PACKAGE_UTIL_LINUX_UNSHARE is not set +# BR2_PACKAGE_UTIL_LINUX_RENAME is not set +# BR2_PACKAGE_UTIL_LINUX_SCHEDUTILS is not set +# BR2_PACKAGE_UTIL_LINUX_WALL is not set +# BR2_PACKAGE_UTIL_LINUX_PARTX is not set +# BR2_PACKAGE_UTIL_LINUX_ARCH is not set +# BR2_PACKAGE_UTIL_LINUX_INIT is not set +# BR2_PACKAGE_UTIL_LINUX_KILL is not set +# BR2_PACKAGE_UTIL_LINUX_LAST is not set +# BR2_PACKAGE_UTIL_LINUX_MESG is not set +# BR2_PACKAGE_UTIL_LINUX_RAW is not set +# BR2_PACKAGE_UTIL_LINUX_RESET is not set +# BR2_PACKAGE_UTIL_LINUX_LOGIN_UTILS is not set +# BR2_PACKAGE_UTIL_LINUX_WRITE is not set # # Text editors and viewers From bef0167e4731e3bfcf7a7fcbec9d27caa24a44c9 Mon Sep 17 00:00:00 2001 From: Jeffrey Townsend Date: Tue, 31 May 2016 11:41:25 -0700 Subject: [PATCH 110/113] Menuconfig regenerated. --- .../buildroot/builds/buildroot.config-arm | 94 ++++++++----------- 1 file changed, 37 insertions(+), 57 deletions(-) diff --git a/packages/base/any/initrds/buildroot/builds/buildroot.config-arm b/packages/base/any/initrds/buildroot/builds/buildroot.config-arm index 6ba13a47..f43a9f30 100644 --- a/packages/base/any/initrds/buildroot/builds/buildroot.config-arm +++ b/packages/base/any/initrds/buildroot/builds/buildroot.config-arm @@ -99,101 +99,81 @@ BR2_PACKAGE_OVERRIDE_FILE="$(TOPDIR)/local.mk" # # Toolchain # -BR2_TOOLCHAIN_BUILDROOT=y -# BR2_TOOLCHAIN_EXTERNAL is not set +# BR2_TOOLCHAIN_BUILDROOT is not set +BR2_TOOLCHAIN_EXTERNAL=y # BR2_TOOLCHAIN_CTNG is not set - -# -# Kernel Header Options -# # BR2_KERNEL_HEADERS_3_0 is not set # BR2_KERNEL_HEADERS_3_2 is not set # BR2_KERNEL_HEADERS_3_4 is not set # BR2_KERNEL_HEADERS_3_6 is not set -BR2_KERNEL_HEADERS_3_7=y +# BR2_KERNEL_HEADERS_3_7 is not set # BR2_KERNEL_HEADERS_VERSION is not set # BR2_KERNEL_HEADERS_SNAP is not set -BR2_DEFAULT_KERNEL_HEADERS="3.7.8" - -# -# uClibc Options -# # BR2_UCLIBC_VERSION_0_9_32 is not set -BR2_UCLIBC_VERSION_0_9_33=y +# BR2_UCLIBC_VERSION_0_9_33 is not set # BR2_UCLIBC_VERSION_SNAPSHOT is not set -BR2_UCLIBC_VERSION_STRING="0.9.33.2" -BR2_UCLIBC_CONFIG="toolchain/uClibc/uClibc-0.9.33.config" -# BR2_PTHREAD_DEBUG is not set -# BR2_UCLIBC_INSTALL_TEST_SUITE is not set -BR2_UCLIBC_ARM_TYPE="ARM926T" - -# -# Binutils Options -# # BR2_BINUTILS_VERSION_2_20_1 is not set # BR2_BINUTILS_VERSION_2_21 is not set -BR2_BINUTILS_VERSION_2_21_1=y +# BR2_BINUTILS_VERSION_2_21_1 is not set # BR2_BINUTILS_VERSION_2_22 is not set # BR2_BINUTILS_VERSION_2_23_1 is not set -BR2_BINUTILS_VERSION="2.21.1" -BR2_BINUTILS_EXTRA_CONFIG_OPTIONS="" - -# -# GCC Options -# # BR2_GCC_VERSION_4_3_X is not set # BR2_GCC_VERSION_4_4_X is not set # BR2_GCC_VERSION_4_5_X is not set -BR2_GCC_VERSION_4_6_X=y +# BR2_GCC_VERSION_4_6_X is not set # BR2_GCC_VERSION_4_7_X is not set # BR2_GCC_VERSION_SNAP is not set -BR2_GCC_SUPPORTS_FINEGRAINEDMTUNE=y -BR2_GCC_VERSION="4.6.3" -BR2_EXTRA_GCC_CONFIG_OPTIONS="" -# BR2_INSTALL_OBJC is not set -# BR2_INSTALL_FORTRAN is not set -BR2_GCC_SHARED_LIBGCC=y -BR2_GCC_ENABLE_TLS=y -# BR2_GCC_ENABLE_OPENMP is not set + +# +# Linaro toolchains available for Cortex-A{5,8,9,15} +# +# BR2_TOOLCHAIN_EXTERNAL_CODESOURCERY_ARM201203 is not set +# BR2_TOOLCHAIN_EXTERNAL_CODESOURCERY_ARM201109 is not set +# BR2_TOOLCHAIN_EXTERNAL_CODESOURCERY_ARM201103 is not set +BR2_TOOLCHAIN_EXTERNAL_CUSTOM=y +# BR2_TOOLCHAIN_EXTERNAL_DOWNLOAD is not set +BR2_TOOLCHAIN_EXTERNAL_PREINSTALLED=y +BR2_TOOLCHAIN_EXTERNAL_PATH="/usr/buildroot/toolchains/arm" +BR2_TOOLCHAIN_EXTERNAL_CUSTOM_PREFIX="arm-buildroot-linux-uclibcgnueabi" +BR2_TOOLCHAIN_EXTERNAL_PREFIX="arm-buildroot-linux-uclibcgnueabi" +BR2_TOOLCHAIN_EXTERNAL_UCLIBC=y +BR2_TOOLCHAIN_EXTERNAL_CUSTOM_UCLIBC=y +# BR2_TOOLCHAIN_EXTERNAL_CUSTOM_GLIBC is not set +BR2_TOOLCHAIN_EXTERNAL_LARGEFILE=y +BR2_TOOLCHAIN_EXTERNAL_INET_IPV6=y +BR2_TOOLCHAIN_EXTERNAL_WCHAR=y +# BR2_TOOLCHAIN_EXTERNAL_LOCALE is not set +BR2_TOOLCHAIN_EXTERNAL_HAS_THREADS=y +# BR2_TOOLCHAIN_EXTERNAL_HAS_THREADS_DEBUG is not set +BR2_TOOLCHAIN_EXTERNAL_INET_RPC=y +# BR2_TOOLCHAIN_EXTERNAL_CXX is not set +BR2_TOOLCHAIN_EXTRA_EXTERNAL_LIBS="" # # Gdb Options # -# BR2_PACKAGE_GDB is not set -# BR2_PACKAGE_GDB_SERVER is not set -# BR2_PACKAGE_GDB_HOST is not set +# BR2_TOOLCHAIN_EXTERNAL_GDB_SERVER_COPY is not set + +# +# gdb support needs pthread debug support in toolchain +# BR2_LARGEFILE=y BR2_INET_IPV6=y BR2_TOOLCHAIN_HAS_NATIVE_RPC=y BR2_USE_WCHAR=y BR2_TOOLCHAIN_HAS_THREADS=y -BR2_TOOLCHAIN_HAS_THREADS_DEBUG_IF_NEEDED=y BR2_TOOLCHAIN_HAS_SHADOW_PASSWORDS=y # BR2_ENABLE_LOCALE_PURGE is not set -BR2_GENERATE_LOCALE="" BR2_NEEDS_GETTEXT=y BR2_USE_MMU=y BR2_PREFER_SOFT_FLOAT=y -BR2_SOFT_FLOAT=y BR2_TARGET_OPTIMIZATION="-pipe" BR2_TARGET_LDFLAGS="" # BR2_ECLIPSE_REGISTER is not set - -# -# Toolchain Options -# -BR2_TOOLCHAIN_BUILDROOT_LARGEFILE=y -BR2_TOOLCHAIN_BUILDROOT_INET_IPV6=y -BR2_TOOLCHAIN_BUILDROOT_INET_RPC=y -BR2_TOOLCHAIN_BUILDROOT_WCHAR=y -# BR2_TOOLCHAIN_BUILDROOT_LOCALE is not set -# BR2_TOOLCHAIN_BUILDROOT_CXX is not set -# BR2_TOOLCHAIN_BUILDROOT_USE_SSP is not set # BR2_PTHREADS_NONE is not set # BR2_PTHREADS is not set # BR2_PTHREADS_OLD is not set -BR2_PTHREADS_NATIVE=y -# BR2_ELF2FLT is not set +# BR2_PTHREADS_NATIVE is not set # # System configuration From eb3f20d316341b2503b50221f087737e0567698e Mon Sep 17 00:00:00 2001 From: Jeffrey Townsend Date: Tue, 31 May 2016 11:42:08 -0700 Subject: [PATCH 111/113] Invoke submake properly. --- packages/base/any/initrds/buildroot/builds/Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/base/any/initrds/buildroot/builds/Makefile b/packages/base/any/initrds/buildroot/builds/Makefile index 232471e4..43e84c48 100644 --- a/packages/base/any/initrds/buildroot/builds/Makefile +++ b/packages/base/any/initrds/buildroot/builds/Makefile @@ -79,15 +79,15 @@ setup-pyparted: define buildroot_arch buildroot-$(1): - make -C $(BUILDROOT_SOURCE) O=../buildroot-$(1) LD_LIBRARY_PATH=/usr/buildroot/toolchains/$(1)/lib + $(MAKE)-C $(BUILDROOT_SOURCE) O=../buildroot-$(1) LD_LIBRARY_PATH=/usr/buildroot/toolchains/$(1)/lib buildroot-menuconfig-$(1): - make -C $(BUILDROOT_SOURCE) menuconfig O=../buildroot-$(1) + $(MAKE) -C $(BUILDROOT_SOURCE) menuconfig O=../buildroot-$(1) cp buildroot-$(1)/.config buildroot.config-$(1) endef $(foreach a,$(ARCHS),$(eval $(call buildroot_arch,$(a)))) busybox-menuconfig: - make -C $(BUILDROOT_SOURCE) busybox-menuconfig O=../buildroot-powerpc + $(MAKE) -C $(BUILDROOT_SOURCE) busybox-menuconfig O=../buildroot-powerpc cp buildroot-powerpc/build/busybox-*/.config busybox.config From 8da0bea2efac8566fab9bff62b759ba3f0ad3d94 Mon Sep 17 00:00:00 2001 From: Jeffrey Townsend Date: Tue, 31 May 2016 11:50:42 -0700 Subject: [PATCH 112/113] Upgrade builder images. --- docker/tools/onlbuilder | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docker/tools/onlbuilder b/docker/tools/onlbuilder index 4f6cfc06..3bb33210 100755 --- a/docker/tools/onlbuilder +++ b/docker/tools/onlbuilder @@ -17,8 +17,8 @@ g_current_user = getpass.getuser() g_current_uid = os.getuid() g_timestamp = datetime.datetime.now().strftime("%Y-%m-%d.%H%M%S") -g_builder7_image_name="opennetworklinux/builder7:1.1" -g_builder8_image_name="opennetworklinux/builder8:1.2" +g_builder7_image_name="opennetworklinux/builder7:1.2" +g_builder8_image_name="opennetworklinux/builder8:1.3" g_default_image_name=g_builder7_image_name g_default_container_name = "%s_%s" % (g_current_user, g_timestamp) From 643fe5010270c52c3d063824cf9480d4ad6fc6da Mon Sep 17 00:00:00 2001 From: Jeffrey Townsend Date: Tue, 31 May 2016 12:49:24 -0700 Subject: [PATCH 113/113] Derp. --- packages/base/any/initrds/buildroot/builds/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/base/any/initrds/buildroot/builds/Makefile b/packages/base/any/initrds/buildroot/builds/Makefile index 43e84c48..609e382d 100644 --- a/packages/base/any/initrds/buildroot/builds/Makefile +++ b/packages/base/any/initrds/buildroot/builds/Makefile @@ -79,7 +79,7 @@ setup-pyparted: define buildroot_arch buildroot-$(1): - $(MAKE)-C $(BUILDROOT_SOURCE) O=../buildroot-$(1) LD_LIBRARY_PATH=/usr/buildroot/toolchains/$(1)/lib + $(MAKE) -C $(BUILDROOT_SOURCE) O=../buildroot-$(1) LD_LIBRARY_PATH=/usr/buildroot/toolchains/$(1)/lib buildroot-menuconfig-$(1): $(MAKE) -C $(BUILDROOT_SOURCE) menuconfig O=../buildroot-$(1)