mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH 00/19] Add Linux dcache implementation
@ 2018-04-03  7:48 Sascha Hauer
  2018-04-03  7:48 ` [PATCH 01/19] rename file_operations -> cdev_operations Sascha Hauer
                   ` (18 more replies)
  0 siblings, 19 replies; 23+ messages in thread
From: Sascha Hauer @ 2018-04-03  7:48 UTC (permalink / raw)
  To: Barebox List

This series adds the Linux dcache implementation to barebox.

Until now every filesystem driver resolves the full path to a file for
itself. This leads to code duplication and is error prone since
resolving paths is a complicated task. Also it can narrow down the
lookup performance since barebox only knows ASCII paths and has no way
of caching lookups. Since with this barebox provides a interface to
dentries much like the Linux Kernel does it gets easier to share
filesystem code between barebox and Linux.

With this series we get the Linux dcache implementation. The path
resolving code from fs/namei.c is nearly taken as-is, minus the RCU and
locking code. Dcaching is made simple as of now: We simply cache
everything and never release any dentries. Although we do reference
counting for inodes and dentries it is effectively not used yet.  We
never free anything until a fs is unmounted in which case we free
everything no matter if references are taken or not.

This patch fundamentally changes the way lookups are done in the
filesystem drivers and I found no sane way to maintain a backwards
compatible code path for not yet converted filesystem drivers. This
means *all* filesystems are marked as broken with the introduction of
the dcache implementation.

I won't apply this series for now (except for the preparatory pathces).
The most important filesystems are already converted with this series,
but there are a few missing like FAT and squashfs and some more no so
prominent ones.

Overall I planned this change for longer now and I can say the new code
feels good. The performance is better, links are resolved more correctly
and the individual filesystem implementations get simpler. I'll continue
on this series soon, but it'll need some time to fix the remaining
filesystems (of course, feel free to do some of the work to speed things
up;)

Sascha

Sascha Hauer (19):
  rename file_operations -> cdev_operations
  ubifs: remove dead code
  ubifs: Remove Linux struct definitions we already have
  ubifs: remove dead code
  fs: Add super_operations
  fs: Move mem_write/mem_read to devfs-core
  fs: Cleanup whitespace damage
  fs: Fix finding correct directory for mkdir/rmdir
  glob: do not unnecessarily opendir() a directory
  ls: Do not depend on normalise_path()
  loadenv: Do not depend on normalise_path()
  fs: dcache implementation
  fs: ramfs: Switch to dcache implementation
  fs: devfs: Switch to dcache implementation
  fs: ext4: Switch to dcache implementation
  fs: ubifs: Switch to dcache implementation
  fs: nfs: Switch to dcache implementation
  fs: tftp: Switch to dcache implementation
  block: Adjust cache sizes

 arch/arm/mach-mxs/ocotp.c     |    2 +-
 arch/sandbox/board/hostfile.c |    2 +-
 commands/loadenv.c            |    6 +-
 commands/ls.c                 |    9 +-
 commands/mem.c                |    2 +-
 commands/stddev.c             |    8 +-
 common/block.c                |    6 +-
 common/firmware.c             |    2 +-
 drivers/base/regmap/regmap.c  |    2 +-
 drivers/eeprom/at24.c         |    2 +-
 drivers/eeprom/at25.c         |    2 +-
 drivers/hw_random/core.c      |    2 +-
 drivers/mfd/act8846.c         |    2 +-
 drivers/mfd/lp3972.c          |    2 +-
 drivers/mfd/mc34704.c         |    2 +-
 drivers/mfd/mc9sdz60.c        |    2 +-
 drivers/mfd/stmpe-i2c.c       |    2 +-
 drivers/mfd/twl-core.c        |    2 +-
 drivers/misc/jtag.c           |    2 +-
 drivers/misc/sram.c           |    2 +-
 drivers/mtd/core.c            |    2 +-
 drivers/mtd/mtdoob.c          |    2 +-
 drivers/mtd/mtdraw.c          |    4 +-
 drivers/mtd/nand/nand-bb.c    |    2 +-
 drivers/mtd/ubi/barebox.c     |    4 +-
 drivers/net/e1000/eeprom.c    |    4 +-
 drivers/net/ksz8864rmn.c      |    2 +-
 drivers/net/phy/mdio_bus.c    |    2 +-
 drivers/nvmem/core.c          |    2 +-
 drivers/video/fb.c            |    2 +-
 drivers/w1/slaves/w1_ds2431.c |    2 +-
 drivers/w1/slaves/w1_ds2433.c |    2 +-
 fs/Kconfig                    |    8 +
 fs/Makefile                   |    2 +-
 fs/devfs-core.c               |   70 +-
 fs/devfs.c                    |  150 +-
 fs/ext4/ext_barebox.c         |  280 ++--
 fs/ext4/ext_common.h          |    3 +
 fs/fat/Kconfig                |    1 +
 fs/fs.c                       | 3696 ++++++++++++++++++++++++++---------------
 fs/libfs.c                    |   87 +
 fs/nfs.c                      |  542 +++---
 fs/pstore/Kconfig             |    1 +
 fs/ramfs.c                    |  412 ++---
 fs/squashfs/Kconfig           |    1 +
 fs/tftp.c                     |   96 +-
 fs/ubifs/Makefile             |    2 +-
 fs/ubifs/dir.c                |  410 +++++
 fs/ubifs/super.c              |  157 +-
 fs/ubifs/ubifs.c              |  816 +--------
 fs/ubifs/ubifs.h              |  547 +-----
 include/console.h             |    2 +-
 include/dirent.h              |    3 +
 include/driver.h              |    4 +-
 include/fs.h                  |   25 +-
 include/linux/dcache.h        |  109 +-
 include/linux/fs.h            |  136 +-
 include/linux/mount.h         |    3 +
 include/linux/namei.h         |   52 +
 include/linux/stat.h          |    2 +
 include/mfd/twl-core.h        |    2 +-
 lib/glob.c                    |   15 +-
 62 files changed, 3960 insertions(+), 3765 deletions(-)
 create mode 100644 fs/libfs.c
 create mode 100644 fs/ubifs/dir.c
 create mode 100644 include/linux/namei.h

-- 
2.16.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 01/19] rename file_operations -> cdev_operations
  2018-04-03  7:48 [PATCH 00/19] Add Linux dcache implementation Sascha Hauer
@ 2018-04-03  7:48 ` Sascha Hauer
  2018-04-03  7:48 ` [PATCH 02/19] ubifs: remove dead code Sascha Hauer
                   ` (17 subsequent siblings)
  18 siblings, 0 replies; 23+ messages in thread
From: Sascha Hauer @ 2018-04-03  7:48 UTC (permalink / raw)
  To: Barebox List

Linux also has struct file_operations which are something different.
Rename our file_operations to cdev_operations which better matches
what we have.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 arch/arm/mach-mxs/ocotp.c     | 2 +-
 arch/sandbox/board/hostfile.c | 2 +-
 commands/mem.c                | 2 +-
 commands/stddev.c             | 8 ++++----
 common/block.c                | 2 +-
 common/firmware.c             | 2 +-
 drivers/base/regmap/regmap.c  | 2 +-
 drivers/eeprom/at24.c         | 2 +-
 drivers/eeprom/at25.c         | 2 +-
 drivers/hw_random/core.c      | 2 +-
 drivers/mfd/act8846.c         | 2 +-
 drivers/mfd/lp3972.c          | 2 +-
 drivers/mfd/mc34704.c         | 2 +-
 drivers/mfd/mc9sdz60.c        | 2 +-
 drivers/mfd/stmpe-i2c.c       | 2 +-
 drivers/mfd/twl-core.c        | 2 +-
 drivers/misc/jtag.c           | 2 +-
 drivers/misc/sram.c           | 2 +-
 drivers/mtd/core.c            | 2 +-
 drivers/mtd/mtdoob.c          | 2 +-
 drivers/mtd/mtdraw.c          | 4 ++--
 drivers/mtd/nand/nand-bb.c    | 2 +-
 drivers/mtd/ubi/barebox.c     | 4 ++--
 drivers/net/e1000/eeprom.c    | 4 ++--
 drivers/net/ksz8864rmn.c      | 2 +-
 drivers/net/phy/mdio_bus.c    | 2 +-
 drivers/nvmem/core.c          | 2 +-
 drivers/video/fb.c            | 2 +-
 drivers/w1/slaves/w1_ds2431.c | 2 +-
 drivers/w1/slaves/w1_ds2433.c | 2 +-
 fs/devfs-core.c               | 2 +-
 include/console.h             | 2 +-
 include/driver.h              | 4 ++--
 include/mfd/twl-core.h        | 2 +-
 34 files changed, 41 insertions(+), 41 deletions(-)

diff --git a/arch/arm/mach-mxs/ocotp.c b/arch/arm/mach-mxs/ocotp.c
index 72f3e8240b..b41fde9919 100644
--- a/arch/arm/mach-mxs/ocotp.c
+++ b/arch/arm/mach-mxs/ocotp.c
@@ -172,7 +172,7 @@ free_mem:
 	return ret;
 }
 
-static struct file_operations mxs_ocotp_ops = {
+static struct cdev_operations mxs_ocotp_ops = {
 	.read	= mxs_ocotp_cdev_read,
 	.lseek	= dev_lseek_default,
 };
diff --git a/arch/sandbox/board/hostfile.c b/arch/sandbox/board/hostfile.c
index e7d92ea031..3fc1503799 100644
--- a/arch/sandbox/board/hostfile.c
+++ b/arch/sandbox/board/hostfile.c
@@ -64,7 +64,7 @@ static void hf_info(struct device_d *dev)
 	printf("file: %s\n", priv->filename);
 }
 
-static struct file_operations hf_fops = {
+static struct cdev_operations hf_fops = {
 	.read  = hf_read,
 	.write = hf_write,
 	.lseek = dev_lseek_default,
diff --git a/commands/mem.c b/commands/mem.c
index 29eaa80b23..eb91ade05a 100644
--- a/commands/mem.c
+++ b/commands/mem.c
@@ -81,7 +81,7 @@ int mem_parse_options(int argc, char *argv[], char *optstr, int *mode,
 	return 0;
 }
 
-static struct file_operations memops = {
+static struct cdev_operations memops = {
 	.read  = mem_read,
 	.write = mem_write,
 	.memmap = generic_memmap_rw,
diff --git a/commands/stddev.c b/commands/stddev.c
index 93da2c7398..4d1b6f5108 100644
--- a/commands/stddev.c
+++ b/commands/stddev.c
@@ -25,7 +25,7 @@ static ssize_t zero_read(struct cdev *cdev, void *buf, size_t count, loff_t offs
 	return count;
 }
 
-static struct file_operations zeroops = {
+static struct cdev_operations zeroops = {
 	.read  = zero_read,
 	.lseek = dev_lseek_default,
 };
@@ -53,7 +53,7 @@ static ssize_t full_read(struct cdev *cdev, void *buf, size_t count, loff_t offs
 	return count;
 }
 
-static struct file_operations fullops = {
+static struct cdev_operations fullops = {
 	.read  = full_read,
 	.lseek = dev_lseek_default,
 };
@@ -80,7 +80,7 @@ static ssize_t null_write(struct cdev *cdev, const void *buf, size_t count, loff
 	return count;
 }
 
-static struct file_operations nullops = {
+static struct cdev_operations nullops = {
 	.write = null_write,
 	.lseek = dev_lseek_default,
 };
@@ -108,7 +108,7 @@ static ssize_t prng_read(struct cdev *cdev, void *buf, size_t count, loff_t offs
 	return count;
 }
 
-static struct file_operations prngops = {
+static struct cdev_operations prngops = {
 	.read  = prng_read,
 	.lseek = dev_lseek_default,
 };
diff --git a/common/block.c b/common/block.c
index e2ba9d4296..55d8d1637e 100644
--- a/common/block.c
+++ b/common/block.c
@@ -332,7 +332,7 @@ static int block_op_flush(struct cdev *cdev)
 	return writebuffer_flush(blk);
 }
 
-static struct file_operations block_ops = {
+static struct cdev_operations block_ops = {
 	.read	= block_op_read,
 #ifdef CONFIG_BLOCK_WRITE
 	.write	= block_op_write,
diff --git a/common/firmware.c b/common/firmware.c
index 664f9107d0..250fef5378 100644
--- a/common/firmware.c
+++ b/common/firmware.c
@@ -153,7 +153,7 @@ static int firmware_close(struct cdev *cdev)
 	return 0;
 }
 
-static struct file_operations firmware_ops = {
+static struct cdev_operations firmware_ops = {
 	.open = firmware_open,
 	.write = firmware_write,
 	.close = firmware_close,
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index 67d95fe30a..8bbc2373fc 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -352,7 +352,7 @@ static ssize_t regmap_cdev_write(struct cdev *cdev, const void *buf, size_t coun
 	return count;
 }
 
-static struct file_operations regmap_fops = {
+static struct cdev_operations regmap_fops = {
 	.lseek	= dev_lseek_default,
 	.read	= regmap_cdev_read,
 	.write	= regmap_cdev_write,
diff --git a/drivers/eeprom/at24.c b/drivers/eeprom/at24.c
index 11f23319b6..4fae3a12e4 100644
--- a/drivers/eeprom/at24.c
+++ b/drivers/eeprom/at24.c
@@ -52,7 +52,7 @@ struct at24_data {
 	struct at24_platform_data chip;
 
 	struct cdev		cdev;
-	struct file_operations	fops;
+	struct cdev_operations	fops;
 
 	u8 *writebuf;
 	unsigned write_max;
diff --git a/drivers/eeprom/at25.c b/drivers/eeprom/at25.c
index 9f16f964a8..a9050d6c16 100644
--- a/drivers/eeprom/at25.c
+++ b/drivers/eeprom/at25.c
@@ -232,7 +232,7 @@ static ssize_t at25_ee_write(struct cdev *cdev,
 	return written ? written : status;
 }
 
-static struct file_operations at25_fops = {
+static struct cdev_operations at25_fops = {
 	.read	= at25_ee_read,
 	.write	= at25_ee_write,
 	.lseek	= dev_lseek_default,
diff --git a/drivers/hw_random/core.c b/drivers/hw_random/core.c
index ef2a988c76..1c68a379f7 100644
--- a/drivers/hw_random/core.c
+++ b/drivers/hw_random/core.c
@@ -61,7 +61,7 @@ static ssize_t rng_dev_read(struct cdev *cdev, void *buf, size_t size,
 	return cur;
 }
 
-static struct file_operations rng_chrdev_ops = {
+static struct cdev_operations rng_chrdev_ops = {
 	.read  = rng_dev_read,
 	.lseek = dev_lseek_default,
 };
diff --git a/drivers/mfd/act8846.c b/drivers/mfd/act8846.c
index 60029acf76..dfca0498b1 100644
--- a/drivers/mfd/act8846.c
+++ b/drivers/mfd/act8846.c
@@ -117,7 +117,7 @@ static ssize_t act8846_write(struct cdev *cdev, const void *_buf, size_t count,
 	return count;
 }
 
-static struct file_operations act8846_fops = {
+static struct cdev_operations act8846_fops = {
 	.lseek	= dev_lseek_default,
 	.read	= act8846_read,
 	.write	= act8846_write,
diff --git a/drivers/mfd/lp3972.c b/drivers/mfd/lp3972.c
index ee794df2d8..054713b942 100644
--- a/drivers/mfd/lp3972.c
+++ b/drivers/mfd/lp3972.c
@@ -70,7 +70,7 @@ static ssize_t lp_read(struct cdev *cdev, void *_buf, size_t count, loff_t offse
 	return count;
 }
 
-static struct file_operations lp_fops = {
+static struct cdev_operations lp_fops = {
 	.lseek	= dev_lseek_default,
 	.read	= lp_read,
 };
diff --git a/drivers/mfd/mc34704.c b/drivers/mfd/mc34704.c
index 3dc85f5474..bfda169aaa 100644
--- a/drivers/mfd/mc34704.c
+++ b/drivers/mfd/mc34704.c
@@ -100,7 +100,7 @@ static ssize_t mc34704_write(struct cdev *cdev, const void *_buf, size_t count,
 	return count;
 }
 
-static struct file_operations mc34704_fops = {
+static struct cdev_operations mc34704_fops = {
 	.lseek	= dev_lseek_default,
 	.read	= mc34704_read,
 	.write	= mc34704_write,
diff --git a/drivers/mfd/mc9sdz60.c b/drivers/mfd/mc9sdz60.c
index 0d2c56b480..9993efc5de 100644
--- a/drivers/mfd/mc9sdz60.c
+++ b/drivers/mfd/mc9sdz60.c
@@ -112,7 +112,7 @@ static ssize_t mc_write(struct cdev *cdev, const void *_buf, size_t count, loff_
 	return count;
 }
 
-static struct file_operations mc_fops = {
+static struct cdev_operations mc_fops = {
 	.lseek	= dev_lseek_default,
 	.read	= mc_read,
 	.write	= mc_write,
diff --git a/drivers/mfd/stmpe-i2c.c b/drivers/mfd/stmpe-i2c.c
index fb91ffa008..51c56bbf56 100644
--- a/drivers/mfd/stmpe-i2c.c
+++ b/drivers/mfd/stmpe-i2c.c
@@ -101,7 +101,7 @@ static ssize_t stmpe_write(struct cdev *cdev, const void *_buf, size_t count, lo
 	return count;
 }
 
-static struct file_operations stmpe_fops = {
+static struct cdev_operations stmpe_fops = {
 	.lseek	= dev_lseek_default,
 	.read	= stmpe_read,
 	.write	= stmpe_write,
diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
index 20bde2cf89..fb435f510f 100644
--- a/drivers/mfd/twl-core.c
+++ b/drivers/mfd/twl-core.c
@@ -149,7 +149,7 @@ static ssize_t twl_write(struct cdev *cdev, const void *_buf, size_t count,
 	return count;
 }
 
-struct file_operations twl_fops = {
+struct cdev_operations twl_fops = {
 	.lseek	= dev_lseek_default,
 	.read	= twl_read,
 	.write	= twl_write,
diff --git a/drivers/misc/jtag.c b/drivers/misc/jtag.c
index f5d0c72ed5..9accefa342 100644
--- a/drivers/misc/jtag.c
+++ b/drivers/misc/jtag.c
@@ -265,7 +265,7 @@ static int jtag_ioctl(struct cdev *inode, int cmd, void *arg)
 	return ret;
 }
 
-static struct file_operations jtag_operations = {
+static struct cdev_operations jtag_operations = {
 	.ioctl = jtag_ioctl,
 };
 
diff --git a/drivers/misc/sram.c b/drivers/misc/sram.c
index 4fb6f801d2..27b4c681fd 100644
--- a/drivers/misc/sram.c
+++ b/drivers/misc/sram.c
@@ -25,7 +25,7 @@ struct sram {
 	struct cdev cdev;
 };
 
-static struct file_operations memops = {
+static struct cdev_operations memops = {
 	.read  = mem_read,
 	.write = mem_write,
 	.memmap = generic_memmap_rw,
diff --git a/drivers/mtd/core.c b/drivers/mtd/core.c
index 1950ee87ee..d2012b5f70 100644
--- a/drivers/mtd/core.c
+++ b/drivers/mtd/core.c
@@ -438,7 +438,7 @@ int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)
 	return ret_code >= mtd->bitflip_threshold ? -EUCLEAN : 0;
 }
 
-static struct file_operations mtd_ops = {
+static struct cdev_operations mtd_ops = {
 	.read   = mtd_op_read,
 #ifdef CONFIG_MTD_WRITE
 	.write  = mtd_op_write,
diff --git a/drivers/mtd/mtdoob.c b/drivers/mtd/mtdoob.c
index 86076f028d..ffaf9506f3 100644
--- a/drivers/mtd/mtdoob.c
+++ b/drivers/mtd/mtdoob.c
@@ -63,7 +63,7 @@ static ssize_t mtd_op_read_oob(struct cdev *cdev, void *buf, size_t count,
 	return mtd->oobsize;
 }
 
-static struct file_operations mtd_ops_oob = {
+static struct cdev_operations mtd_ops_oob = {
 	.read   = mtd_op_read_oob,
 	.ioctl  = mtd_ioctl,
 	.lseek  = dev_lseek_default,
diff --git a/drivers/mtd/mtdraw.c b/drivers/mtd/mtdraw.c
index ab360b7862..4f7c3b836c 100644
--- a/drivers/mtd/mtdraw.c
+++ b/drivers/mtd/mtdraw.c
@@ -287,7 +287,7 @@ static ssize_t mtdraw_erase(struct cdev *cdev, loff_t count, loff_t offset)
 }
 #endif
 
-static const struct file_operations mtd_raw_fops = {
+static const struct cdev_operations mtd_raw_fops = {
 	.read		= mtdraw_read,
 	.write		= mtdraw_write,
 	.erase		= mtdraw_erase,
@@ -305,7 +305,7 @@ static int add_mtdraw_device(struct mtd_info *mtd, const char *devname, void **p
 	mtdraw->writebuf = xmalloc(RAW_WRITEBUF_SIZE);
 	mtdraw->mtd = mtd;
 
-	mtdraw->cdev.ops = (struct file_operations *)&mtd_raw_fops;
+	mtdraw->cdev.ops = (struct cdev_operations *)&mtd_raw_fops;
 	mtdraw->cdev.size = mtd_div_by_wb(mtd->size, mtd) *
 		(mtd->writesize + mtd->oobsize);
 	mtdraw->cdev.name = basprintf("%s.raw", mtd->cdev.name);
diff --git a/drivers/mtd/nand/nand-bb.c b/drivers/mtd/nand/nand-bb.c
index a1523c3c89..c1977381d4 100644
--- a/drivers/mtd/nand/nand-bb.c
+++ b/drivers/mtd/nand/nand-bb.c
@@ -264,7 +264,7 @@ static loff_t nand_bb_lseek(struct cdev *cdev, loff_t __offset)
 	return -EINVAL;
 }
 
-static struct file_operations nand_bb_ops = {
+static struct cdev_operations nand_bb_ops = {
 	.open   = nand_bb_open,
 	.close  = nand_bb_close,
 	.read  	= nand_bb_read,
diff --git a/drivers/mtd/ubi/barebox.c b/drivers/mtd/ubi/barebox.c
index d67e566db6..65f5456455 100644
--- a/drivers/mtd/ubi/barebox.c
+++ b/drivers/mtd/ubi/barebox.c
@@ -218,7 +218,7 @@ static int ubi_volume_cdev_ioctl(struct cdev *cdev, int cmd, void *buf)
 	return err;
 }
 
-static struct file_operations ubi_volume_fops = {
+static struct cdev_operations ubi_volume_fops = {
 	.open	= ubi_volume_cdev_open,
 	.close	= ubi_volume_cdev_close,
 	.read   = ubi_volume_cdev_read,
@@ -467,7 +467,7 @@ static int ubi_cdev_ioctl(struct cdev *cdev, int cmd, void *buf)
 	return 0;
 }
 
-static struct file_operations ubi_fops = {
+static struct cdev_operations ubi_fops = {
 	.ioctl	= ubi_cdev_ioctl,
 };
 
diff --git a/drivers/net/e1000/eeprom.c b/drivers/net/e1000/eeprom.c
index 319910103e..3f39db7164 100644
--- a/drivers/net/e1000/eeprom.c
+++ b/drivers/net/e1000/eeprom.c
@@ -1294,7 +1294,7 @@ exit:
 	return ret;
 }
 
-static struct file_operations e1000_invm_ops = {
+static struct cdev_operations e1000_invm_ops = {
 	.read	= e1000_invm_cdev_read,
 	.write	= e1000_invm_cdev_write,
 	.lseek	= dev_lseek_default,
@@ -1320,7 +1320,7 @@ static ssize_t e1000_eeprom_cdev_read(struct cdev *cdev, void *buf,
 		return (count / 2) * 2;
 };
 
-static struct file_operations e1000_eeprom_ops = {
+static struct cdev_operations e1000_eeprom_ops = {
 	.read = e1000_eeprom_cdev_read,
 	.lseek = dev_lseek_default,
 };
diff --git a/drivers/net/ksz8864rmn.c b/drivers/net/ksz8864rmn.c
index 860af448ea..8b9d66019b 100644
--- a/drivers/net/ksz8864rmn.c
+++ b/drivers/net/ksz8864rmn.c
@@ -120,7 +120,7 @@ static ssize_t micel_switch_write(struct cdev *cdev, const void *_buf, size_t co
 	return count;
 }
 
-static struct file_operations micrel_switch_ops = {
+static struct cdev_operations micrel_switch_ops = {
 	.read  = micel_switch_read,
 	.write = micel_switch_write,
 	.lseek = dev_lseek_default,
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index d209716a14..5d4218f7c0 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -285,7 +285,7 @@ static ssize_t phydev_write(struct cdev *cdev, const void *_buf, size_t count, l
 	return count;
 }
 
-static struct file_operations phydev_ops = {
+static struct cdev_operations phydev_ops = {
 	.read  = phydev_read,
 	.write = phydev_write,
 	.lseek = dev_lseek_default,
diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index 4e50a8843f..172fa8b720 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -82,7 +82,7 @@ static ssize_t nvmem_cdev_write(struct cdev *cdev, const void *buf, size_t count
 	return retlen;
 }
 
-static struct file_operations nvmem_chrdev_ops = {
+static struct cdev_operations nvmem_chrdev_ops = {
 	.read  = nvmem_cdev_read,
 	.write  = nvmem_cdev_write,
 	.lseek = dev_lseek_default,
diff --git a/drivers/video/fb.c b/drivers/video/fb.c
index 004df1e604..5e829e832d 100644
--- a/drivers/video/fb.c
+++ b/drivers/video/fb.c
@@ -221,7 +221,7 @@ static int fb_set_modename(struct param_d *param, void *priv)
 	return 0;
 }
 
-static struct file_operations fb_ops = {
+static struct cdev_operations fb_ops = {
 	.read	= mem_read,
 	.write	= mem_write,
 	.memmap	= generic_memmap_rw,
diff --git a/drivers/w1/slaves/w1_ds2431.c b/drivers/w1/slaves/w1_ds2431.c
index e3e929670d..13691d7bab 100644
--- a/drivers/w1/slaves/w1_ds2431.c
+++ b/drivers/w1/slaves/w1_ds2431.c
@@ -257,7 +257,7 @@ out_up:
 #define ds2431_cdev_write NULL
 #endif
 
-static struct file_operations ds2431_ops = {
+static struct cdev_operations ds2431_ops = {
 	.read	= ds2431_cdev_read,
 	.write	= ds2431_cdev_write,
 	.lseek	= dev_lseek_default,
diff --git a/drivers/w1/slaves/w1_ds2433.c b/drivers/w1/slaves/w1_ds2433.c
index a907c6bf3c..f521a46a75 100644
--- a/drivers/w1/slaves/w1_ds2433.c
+++ b/drivers/w1/slaves/w1_ds2433.c
@@ -156,7 +156,7 @@ out_up:
 #define ds2433_cdev_write NULL
 #endif
 
-static struct file_operations ds2433_ops = {
+static struct cdev_operations ds2433_ops = {
 	.read	= ds2433_cdev_read,
 	.write	= ds2433_cdev_write,
 	.lseek	= dev_lseek_default,
diff --git a/fs/devfs-core.c b/fs/devfs-core.c
index ea5887c720..d06a534b57 100644
--- a/fs/devfs-core.c
+++ b/fs/devfs-core.c
@@ -457,7 +457,7 @@ static ssize_t loop_write(struct cdev *cdev, const void *buf, size_t count,
 	return write(priv->fd, buf, count);
 }
 
-static const struct file_operations loop_ops = {
+static const struct cdev_operations loop_ops = {
 	.read = loop_read,
 	.write = loop_write,
 	.memmap = generic_memmap_rw,
diff --git a/include/console.h b/include/console.h
index a8b2663a4c..3c14e35935 100644
--- a/include/console.h
+++ b/include/console.h
@@ -63,7 +63,7 @@ struct console_device {
 	const char *linux_console_name;
 
 	struct cdev devfs;
-	struct file_operations fops;
+	struct cdev_operations fops;
 };
 
 int console_register(struct console_device *cdev);
diff --git a/include/driver.h b/include/driver.h
index f37805db17..91653b7946 100644
--- a/include/driver.h
+++ b/include/driver.h
@@ -420,7 +420,7 @@ int platform_driver_register(struct driver_d *drv);
 
 int platform_device_register(struct device_d *new_device);
 
-struct file_operations {
+struct cdev_operations {
 	/*! Called in response of reading from this device. Required */
 	ssize_t (*read)(struct cdev*, void* buf, size_t count, loff_t offset, ulong flags);
 
@@ -441,7 +441,7 @@ struct file_operations {
 #define MAX_PARTUUID_STR	sizeof("00112233-4455-6677-8899-AABBCCDDEEFF")
 
 struct cdev {
-	const struct file_operations *ops;
+	const struct cdev_operations *ops;
 	void *priv;
 	struct device_d *dev;
 	struct device_node *device_node;
diff --git a/include/mfd/twl-core.h b/include/mfd/twl-core.h
index f090032b3f..88d29f019b 100644
--- a/include/mfd/twl-core.h
+++ b/include/mfd/twl-core.h
@@ -21,7 +21,7 @@ struct twlcore {
 	struct i2c_client	*client;
 };
 
-extern struct file_operations twl_fops;
+extern struct cdev_operations twl_fops;
 
 extern int twlcore_reg_read(struct twlcore *twlcore, u16 reg, u8 *val);
 extern int twlcore_reg_write(struct twlcore *twlcore, u16 reg, u8 val);
-- 
2.16.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 02/19] ubifs: remove dead code
  2018-04-03  7:48 [PATCH 00/19] Add Linux dcache implementation Sascha Hauer
  2018-04-03  7:48 ` [PATCH 01/19] rename file_operations -> cdev_operations Sascha Hauer
@ 2018-04-03  7:48 ` Sascha Hauer
  2018-04-03  7:48 ` [PATCH 03/19] ubifs: Remove Linux struct definitions we already have Sascha Hauer
                   ` (16 subsequent siblings)
  18 siblings, 0 replies; 23+ messages in thread
From: Sascha Hauer @ 2018-04-03  7:48 UTC (permalink / raw)
  To: Barebox List

Remove stuff that was added to UBIFS for U-Boot which we do not need
because we already have it in the Linux header files.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 fs/ubifs/ubifs.h | 187 -------------------------------------------------------
 1 file changed, 187 deletions(-)

diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
index 5c5a82637e..5589f99401 100644
--- a/fs/ubifs/ubifs.h
+++ b/fs/ubifs/ubifs.h
@@ -96,193 +96,6 @@ void *kmemdup(const void *src, size_t len, gfp_t gfp);
 /* uapi/linux/limits.h */
 #define XATTR_LIST_MAX 65536	/* size of extended attribute namelist (64k) */
 
-#ifndef __BAREBOX__
-/* linux/include/time.h */
-#define NSEC_PER_SEC	1000000000L
-#define get_seconds()	0
-#define CURRENT_TIME_SEC	((struct timespec) { get_seconds(), 0 })
-
-struct timespec {
-	time_t	tv_sec;		/* seconds */
-	long	tv_nsec;	/* nanoseconds */
-};
-
-static struct timespec current_fs_time(struct super_block *sb)
-{
-	struct timespec now;
-	now.tv_sec = 0;
-	now.tv_nsec = 0;
-	return now;
-};
-
-/* linux/include/dcache.h */
-
-/*
- * "quick string" -- eases parameter passing, but more importantly
- * saves "metadata" about the string (ie length and the hash).
- *
- * hash comes first so it snuggles against d_parent in the
- * dentry.
- */
-struct qstr {
-	unsigned int hash;
-	unsigned int len;
-#ifndef __BAREBOX__
-	const char *name;
-#else
-	char *name;
-#endif
-};
-
-/* include/linux/fs.h */
-
-/* Possible states of 'frozen' field */
-enum {
-	SB_UNFROZEN = 0,		/* FS is unfrozen */
-	SB_FREEZE_WRITE	= 1,		/* Writes, dir ops, ioctls frozen */
-	SB_FREEZE_PAGEFAULT = 2,	/* Page faults stopped as well */
-	SB_FREEZE_FS = 3,		/* For internal FS use (e.g. to stop
-					 * internal threads if needed) */
-	SB_FREEZE_COMPLETE = 4,		/* ->freeze_fs finished successfully */
-};
-
-#define SB_FREEZE_LEVELS (SB_FREEZE_COMPLETE - 1)
-
-struct sb_writers {
-#ifndef __BAREBOX__
-	/* Counters for counting writers at each level */
-	struct percpu_counter	counter[SB_FREEZE_LEVELS];
-#endif
-	wait_queue_head_t	wait;		/* queue for waiting for
-						   writers / faults to finish */
-	int			frozen;		/* Is sb frozen? */
-	wait_queue_head_t	wait_unfrozen;	/* queue for waiting for
-						   sb to be thawed */
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
-	struct lockdep_map	lock_map[SB_FREEZE_LEVELS];
-#endif
-};
-
-struct address_space {
-	struct inode		*host;		/* owner: inode, block_device */
-#ifndef __BAREBOX__
-	struct radix_tree_root	page_tree;	/* radix tree of all pages */
-#endif
-	spinlock_t		tree_lock;	/* and lock protecting it */
-	unsigned int		i_mmap_writable;/* count VM_SHARED mappings */
-	struct rb_root		i_mmap;		/* tree of private and shared mappings */
-	struct list_head	i_mmap_nonlinear;/*list VM_NONLINEAR mappings */
-	struct mutex		i_mmap_mutex;	/* protect tree, count, list */
-	/* Protected by tree_lock together with the radix tree */
-	unsigned long		nrpages;	/* number of total pages */
-	pgoff_t			writeback_index;/* writeback starts here */
-	const struct address_space_operations *a_ops;	/* methods */
-	unsigned long		flags;		/* error bits/gfp mask */
-#ifndef __BAREBOX__
-	struct backing_dev_info *backing_dev_info; /* device readahead, etc */
-#endif
-	spinlock_t		private_lock;	/* for use by the address_space */
-	struct list_head	private_list;	/* ditto */
-	void			*private_data;	/* ditto */
-} __attribute__((aligned(sizeof(long))));
-
-/*
- * Keep mostly read-only and often accessed (especially for
- * the RCU path lookup and 'stat' data) fields at the beginning
- * of the 'struct inode'
- */
-struct inode {
-	umode_t			i_mode;
-	unsigned short		i_opflags;
-	kuid_t			i_uid;
-	kgid_t			i_gid;
-	unsigned int		i_flags;
-
-#ifdef CONFIG_FS_POSIX_ACL
-	struct posix_acl	*i_acl;
-	struct posix_acl	*i_default_acl;
-#endif
-
-	const struct inode_operations	*i_op;
-	struct super_block	*i_sb;
-	struct address_space	*i_mapping;
-
-#ifdef CONFIG_SECURITY
-	void			*i_security;
-#endif
-
-	/* Stat data, not accessed from path walking */
-	unsigned long		i_ino;
-	/*
-	 * Filesystems may only read i_nlink directly.  They shall use the
-	 * following functions for modification:
-	 *
-	 *    (set|clear|inc|drop)_nlink
-	 *    inode_(inc|dec)_link_count
-	 */
-	union {
-		const unsigned int i_nlink;
-		unsigned int __i_nlink;
-	};
-	dev_t			i_rdev;
-	loff_t			i_size;
-	struct timespec		i_atime;
-	struct timespec		i_mtime;
-	struct timespec		i_ctime;
-	spinlock_t		i_lock;	/* i_blocks, i_bytes, maybe i_size */
-	unsigned short          i_bytes;
-	unsigned int		i_blkbits;
-	blkcnt_t		i_blocks;
-
-#ifdef __NEED_I_SIZE_ORDERED
-	seqcount_t		i_size_seqcount;
-#endif
-
-	/* Misc */
-	unsigned long		i_state;
-	struct mutex		i_mutex;
-
-	unsigned long		dirtied_when;	/* jiffies of first dirtying */
-
-	struct hlist_node	i_hash;
-	struct list_head	i_wb_list;	/* backing dev IO list */
-	struct list_head	i_lru;		/* inode LRU list */
-	struct list_head	i_sb_list;
-	union {
-		struct hlist_head	i_dentry;
-		struct rcu_head		i_rcu;
-	};
-	u64			i_version;
-	atomic_t		i_count;
-	atomic_t		i_dio_count;
-	atomic_t		i_writecount;
-	const struct file_operations	*i_fop;	/* former ->i_op->default_file_ops */
-	struct file_lock	*i_flock;
-	struct address_space	i_data;
-#ifdef CONFIG_QUOTA
-	struct dquot		*i_dquot[MAXQUOTAS];
-#endif
-	struct list_head	i_devices;
-	union {
-		struct pipe_inode_info	*i_pipe;
-		struct block_device	*i_bdev;
-		struct cdev		*i_cdev;
-	};
-
-	__u32			i_generation;
-
-#ifdef CONFIG_FSNOTIFY
-	__u32			i_fsnotify_mask; /* all events this inode cares about */
-	struct hlist_head	i_fsnotify_marks;
-#endif
-
-#ifdef CONFIG_IMA
-	atomic_t		i_readcount; /* struct files open RO */
-#endif
-	void			*i_private; /* fs or device private pointer */
-};
-#endif
-
 struct super_operations {
    	struct inode *(*alloc_inode)(struct super_block *sb);
 	void (*destroy_inode)(struct inode *);
-- 
2.16.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 03/19] ubifs: Remove Linux struct definitions we already have
  2018-04-03  7:48 [PATCH 00/19] Add Linux dcache implementation Sascha Hauer
  2018-04-03  7:48 ` [PATCH 01/19] rename file_operations -> cdev_operations Sascha Hauer
  2018-04-03  7:48 ` [PATCH 02/19] ubifs: remove dead code Sascha Hauer
@ 2018-04-03  7:48 ` Sascha Hauer
  2018-04-03  7:48 ` [PATCH 04/19] ubifs: remove dead code Sascha Hauer
                   ` (15 subsequent siblings)
  18 siblings, 0 replies; 23+ messages in thread
From: Sascha Hauer @ 2018-04-03  7:48 UTC (permalink / raw)
  To: Barebox List

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 fs/ubifs/ubifs.h | 318 +------------------------------------------------------
 1 file changed, 1 insertion(+), 317 deletions(-)

diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
index 5589f99401..1391bd7283 100644
--- a/fs/ubifs/ubifs.h
+++ b/fs/ubifs/ubifs.h
@@ -42,6 +42,7 @@
 #include <linux/math64.h>
 #include <linux/rbtree.h>
 #include <linux/mtd/ubi.h>
+#include <linux/pagemap.h>
 #include <asm/atomic.h>
 #include <asm-generic/atomic-long.h>
 #include "ubifs-media.h"
@@ -131,328 +132,11 @@ struct super_operations {
 	long (*free_cached_objects)(struct super_block *, long, int);
 };
 
-#ifndef __BAREBOX__
-struct super_block {
-	struct list_head	s_list;		/* Keep this first */
-	dev_t			s_dev;		/* search index; _not_ kdev_t */
-	unsigned char		s_blocksize_bits;
-	unsigned long		s_blocksize;
-	loff_t			s_maxbytes;	/* Max file size */
-	struct file_system_type	*s_type;
-	const struct super_operations	*s_op;
-	const struct dquot_operations	*dq_op;
-	const struct quotactl_ops	*s_qcop;
-	const struct export_operations *s_export_op;
-	unsigned long		s_flags;
-	unsigned long		s_magic;
-	struct dentry		*s_root;
-	struct rw_semaphore	s_umount;
-	int			s_count;
-	atomic_t		s_active;
-#ifdef CONFIG_SECURITY
-	void                    *s_security;
-#endif
-	const struct xattr_handler **s_xattr;
-
-	struct list_head	s_inodes;	/* all inodes */
-#ifndef __BAREBOX__
-	struct hlist_bl_head	s_anon;		/* anonymous dentries for (nfs) exporting */
-#endif
-	struct list_head	s_mounts;	/* list of mounts; _not_ for fs use */
-	struct block_device	*s_bdev;
-#ifndef __BAREBOX__
-	struct backing_dev_info *s_bdi;
-#endif
-	struct mtd_info		*s_mtd;
-	struct hlist_node	s_instances;
-#ifndef __BAREBOX__
-	struct quota_info	s_dquot;	/* Diskquota specific options */
-#endif
-
-	struct sb_writers	s_writers;
-
-	char s_id[32];				/* Informational name */
-	u8 s_uuid[16];				/* UUID */
-
-	void 			*s_fs_info;	/* Filesystem private info */
-	unsigned int		s_max_links;
-#ifndef __BAREBOX__
-	fmode_t			s_mode;
-#endif
-
-	/* Granularity of c/m/atime in ns.
-	   Cannot be worse than a second */
-	u32		   s_time_gran;
-
-	/*
-	 * The next field is for VFS *only*. No filesystems have any business
-	 * even looking at it. You had been warned.
-	 */
-	struct mutex s_vfs_rename_mutex;	/* Kludge */
-
-	/*
-	 * Filesystem subtype.  If non-empty the filesystem type field
-	 * in /proc/mounts will be "type.subtype"
-	 */
-	char *s_subtype;
-
-#ifndef __BAREBOX__
-	/*
-	 * Saved mount options for lazy filesystems using
-	 * generic_show_options()
-	 */
-	char __rcu *s_options;
-#endif
-	const struct dentry_operations *s_d_op; /* default d_op for dentries */
-
-	/*
-	 * Saved pool identifier for cleancache (-1 means none)
-	 */
-	int cleancache_poolid;
-
-#ifndef __BAREBOX__
-	struct shrinker s_shrink;	/* per-sb shrinker handle */
-#endif
-
-	/* Number of inodes with nlink == 0 but still referenced */
-	atomic_long_t s_remove_count;
-
-	/* Being remounted read-only */
-	int s_readonly_remount;
-
-	/* AIO completions deferred from interrupt context */
-	struct workqueue_struct *s_dio_done_wq;
-
-#ifndef __BAREBOX__
-	/*
-	 * Keep the lru lists last in the structure so they always sit on their
-	 * own individual cachelines.
-	 */
-	struct list_lru		s_dentry_lru ____cacheline_aligned_in_smp;
-	struct list_lru		s_inode_lru ____cacheline_aligned_in_smp;
-#endif
-	struct rcu_head		rcu;
-};
-
-struct file_system_type {
-	const char *name;
-	int fs_flags;
-#define FS_REQUIRES_DEV		1
-#define FS_BINARY_MOUNTDATA	2
-#define FS_HAS_SUBTYPE		4
-#define FS_USERNS_MOUNT		8	/* Can be mounted by userns root */
-#define FS_USERNS_DEV_MOUNT	16 /* A userns mount does not imply MNT_NODEV */
-#define FS_RENAME_DOES_D_MOVE	32768	/* FS will handle d_move() during rename() internally. */
-	struct dentry *(*mount) (struct file_system_type *, int,
-		       const char *, void *);
-	void (*kill_sb) (struct super_block *);
-	struct module *owner;
-	struct file_system_type * next;
-	struct hlist_head fs_supers;
-
-#ifndef __BAREBOX__
-	struct lock_class_key s_lock_key;
-	struct lock_class_key s_umount_key;
-	struct lock_class_key s_vfs_rename_key;
-	struct lock_class_key s_writers_key[SB_FREEZE_LEVELS];
-
-	struct lock_class_key i_lock_key;
-	struct lock_class_key i_mutex_key;
-	struct lock_class_key i_mutex_dir_key;
-#endif
-};
-
-/* include/linux/mount.h */
-struct vfsmount {
-	struct dentry *mnt_root;	/* root of the mounted tree */
-	struct super_block *mnt_sb;	/* pointer to superblock */
-	int mnt_flags;
-};
-
-struct path {
-	struct vfsmount *mnt;
-	struct dentry *dentry;
-};
-
-struct file {
-	struct path		f_path;
-#define f_dentry	f_path.dentry
-#define f_vfsmnt	f_path.mnt
-	const struct file_operations	*f_op;
-	unsigned int 		f_flags;
-	loff_t			f_pos;
-	unsigned int		f_uid, f_gid;
-
-	u64			f_version;
-#ifdef CONFIG_SECURITY
-	void			*f_security;
-#endif
-	/* needed for tty driver, and maybe others */
-	void			*private_data;
-
-#ifdef CONFIG_EPOLL
-	/* Used by fs/eventpoll.c to link all the hooks to this file */
-	struct list_head	f_ep_links;
-	spinlock_t		f_ep_lock;
-#endif /* #ifdef CONFIG_EPOLL */
-#ifdef CONFIG_DEBUG_WRITECOUNT
-	unsigned long f_mnt_write_state;
-#endif
-};
-#endif
-
 /*
  * get_seconds() not really needed in the read-only implmentation
  */
 #define get_seconds()		0
 
-/* 4k page size */
-#define PAGE_CACHE_SHIFT	12
-#define PAGE_CACHE_SIZE		(1 << PAGE_CACHE_SHIFT)
-
-#ifndef __BAREBOX__
-/* Page cache limit. The filesystems should put that into their s_maxbytes
-   limits, otherwise bad things can happen in VM. */
-#if BITS_PER_LONG==32
-#define MAX_LFS_FILESIZE	(((u64)PAGE_CACHE_SIZE << (BITS_PER_LONG-1))-1)
-#elif BITS_PER_LONG==64
-#define MAX_LFS_FILESIZE 	0x7fffffffffffffffUL
-#endif
-
-/*
- * These are the fs-independent mount-flags: up to 32 flags are supported
- */
-#define MS_RDONLY	 1	/* Mount read-only */
-#define MS_NOSUID	 2	/* Ignore suid and sgid bits */
-#define MS_NODEV	 4	/* Disallow access to device special files */
-#define MS_NOEXEC	 8	/* Disallow program execution */
-#define MS_SYNCHRONOUS	16	/* Writes are synced at once */
-#define MS_REMOUNT	32	/* Alter flags of a mounted FS */
-#define MS_MANDLOCK	64	/* Allow mandatory locks on an FS */
-#define MS_DIRSYNC	128	/* Directory modifications are synchronous */
-#define MS_NOATIME	1024	/* Do not update access times. */
-#define MS_NODIRATIME	2048	/* Do not update directory access times */
-#define MS_BIND		4096
-#define MS_MOVE		8192
-#define MS_REC		16384
-#define MS_VERBOSE	32768	/* War is peace. Verbosity is silence.
-				   MS_VERBOSE is deprecated. */
-#define MS_SILENT	32768
-#define MS_POSIXACL	(1<<16)	/* VFS does not apply the umask */
-#define MS_UNBINDABLE	(1<<17)	/* change to unbindable */
-#define MS_PRIVATE	(1<<18)	/* change to private */
-#define MS_SLAVE	(1<<19)	/* change to slave */
-#define MS_SHARED	(1<<20)	/* change to shared */
-#define MS_RELATIME	(1<<21)	/* Update atime relative to mtime/ctime. */
-#define MS_KERNMOUNT	(1<<22) /* this is a kern_mount call */
-#define MS_I_VERSION	(1<<23) /* Update inode I_version field */
-#define MS_ACTIVE	(1<<30)
-#define MS_NOUSER	(1<<31)
-
-#define I_NEW			8
-
-/* Inode flags - they have nothing to superblock flags now */
-
-#define S_SYNC		1	/* Writes are synced at once */
-#define S_NOATIME	2	/* Do not update access times */
-#define S_APPEND	4	/* Append-only file */
-#define S_IMMUTABLE	8	/* Immutable file */
-#define S_DEAD		16	/* removed, but still open directory */
-#define S_NOQUOTA	32	/* Inode is not counted to quota */
-#define S_DIRSYNC	64	/* Directory modifications are synchronous */
-#define S_NOCMTIME	128	/* Do not update file c/mtime */
-#define S_SWAPFILE	256	/* Do not truncate: swapon got its bmaps */
-#define S_PRIVATE	512	/* Inode is fs-internal */
-
-/* include/linux/stat.h */
-
-#define S_IFMT  00170000
-#define S_IFSOCK 0140000
-#define S_IFLNK	 0120000
-#define S_IFREG  0100000
-#define S_IFBLK  0060000
-#define S_IFDIR  0040000
-#define S_IFCHR  0020000
-#define S_IFIFO  0010000
-#define S_ISUID  0004000
-#define S_ISGID  0002000
-#define S_ISVTX  0001000
-
-/* include/linux/fs.h */
-
-/*
- * File types
- *
- * NOTE! These match bits 12..15 of stat.st_mode
- * (ie "(i_mode >> 12) & 15").
- */
-#define DT_UNKNOWN	0
-#define DT_FIFO		1
-#define DT_CHR		2
-#define DT_DIR		4
-#define DT_BLK		6
-#define DT_REG		8
-#define DT_LNK		10
-#define DT_SOCK		12
-#define DT_WHT		14
-
-#define I_DIRTY_SYNC		1
-#define I_DIRTY_DATASYNC	2
-#define I_DIRTY_PAGES		4
-#define I_NEW			8
-#define I_WILL_FREE		16
-#define I_FREEING		32
-#define I_CLEAR			64
-#define __I_LOCK		7
-#define I_LOCK			(1 << __I_LOCK)
-#define __I_SYNC		8
-#define I_SYNC			(1 << __I_SYNC)
-
-#define I_DIRTY (I_DIRTY_SYNC | I_DIRTY_DATASYNC | I_DIRTY_PAGES)
-
-/* linux/include/dcache.h */
-
-#define DNAME_INLINE_LEN_MIN 36
-
-struct dentry {
-	unsigned int d_flags;		/* protected by d_lock */
-	spinlock_t d_lock;		/* per dentry lock */
-	struct inode *d_inode;		/* Where the name belongs to - NULL is
-					 * negative */
-	/*
-	 * The next three fields are touched by __d_lookup.  Place them here
-	 * so they all fit in a cache line.
-	 */
-	struct hlist_node d_hash;	/* lookup hash list */
-	struct dentry *d_parent;	/* parent directory */
-	struct qstr d_name;
-
-	struct list_head d_lru;		/* LRU list */
-	/*
-	 * d_child and d_rcu can share memory
-	 */
-	struct list_head d_subdirs;	/* our children */
-	struct list_head d_alias;	/* inode alias list */
-	unsigned long d_time;		/* used by d_revalidate */
-	struct super_block *d_sb;	/* The root of the dentry tree */
-	void *d_fsdata;			/* fs-specific data */
-#ifdef CONFIG_PROFILING
-	struct dcookie_struct *d_cookie; /* cookie, if any */
-#endif
-	int d_mounted;
-	unsigned char d_iname[DNAME_INLINE_LEN_MIN];	/* small names */
-};
-#endif
-static inline ino_t parent_ino(struct dentry *dentry)
-{
-	ino_t res;
-
-	spin_lock(&dentry->d_lock);
-	res = dentry->d_parent->d_inode->i_ino;
-	spin_unlock(&dentry->d_lock);
-	return res;
-}
-
 /* debug.c */
 
 #define module_param_named(...)
-- 
2.16.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 04/19] ubifs: remove dead code
  2018-04-03  7:48 [PATCH 00/19] Add Linux dcache implementation Sascha Hauer
                   ` (2 preceding siblings ...)
  2018-04-03  7:48 ` [PATCH 03/19] ubifs: Remove Linux struct definitions we already have Sascha Hauer
@ 2018-04-03  7:48 ` Sascha Hauer
  2018-04-03  7:48 ` [PATCH 05/19] fs: Add super_operations Sascha Hauer
                   ` (14 subsequent siblings)
  18 siblings, 0 replies; 23+ messages in thread
From: Sascha Hauer @ 2018-04-03  7:48 UTC (permalink / raw)
  To: Barebox List

Remove code that was added to UBIFS for U-Boot but that is not needed
for barebox.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 fs/ubifs/ubifs.c | 475 -------------------------------------------------------
 1 file changed, 475 deletions(-)

diff --git a/fs/ubifs/ubifs.c b/fs/ubifs/ubifs.c
index 0bb1c26d7d..a525b044b8 100644
--- a/fs/ubifs/ubifs.c
+++ b/fs/ubifs/ubifs.c
@@ -273,135 +273,6 @@ int __init ubifs_compressors_init(void)
  * ubifsls...
  */
 
-#ifndef __BAREBOX__
-static int filldir(struct ubifs_info *c, const char *name, int namlen,
-		   u64 ino, unsigned int d_type)
-{
-	struct inode *inode;
-	char filetime[32];
-
-	switch (d_type) {
-	case UBIFS_ITYPE_REG:
-		printf("\t");
-		break;
-	case UBIFS_ITYPE_DIR:
-		printf("<DIR>\t");
-		break;
-	case UBIFS_ITYPE_LNK:
-		printf("<LNK>\t");
-		break;
-	default:
-		printf("other\t");
-		break;
-	}
-
-	inode = ubifs_iget(c->vfs_sb, ino);
-	if (IS_ERR(inode)) {
-		printf("%s: Error in ubifs_iget(), ino=%lld ret=%p!\n",
-		       __func__, ino, inode);
-		return -1;
-	}
-	ctime_r((time_t *)&inode->i_mtime, filetime);
-	printf("%9lld  %24.24s  ", inode->i_size, filetime);
-#ifndef __BAREBOX__
-	ubifs_iput(inode);
-#endif
-
-	printf("%s\n", name);
-
-	return 0;
-}
-
-static int ubifs_printdir(struct file *file, void *dirent)
-{
-	int err, over = 0;
-	struct qstr nm;
-	union ubifs_key key;
-	struct ubifs_dent_node *dent;
-	struct inode *dir = file->f_path.dentry->d_inode;
-	struct ubifs_info *c = dir->i_sb->s_fs_info;
-
-	dbg_gen("dir ino %lu, f_pos %#llx", dir->i_ino, file->f_pos);
-
-	if (file->f_pos > UBIFS_S_KEY_HASH_MASK || file->f_pos == 2)
-		/*
-		 * The directory was seek'ed to a senseless position or there
-		 * are no more entries.
-		 */
-		return 0;
-
-	if (file->f_pos == 1) {
-		/* Find the first entry in TNC and save it */
-		lowest_dent_key(c, &key, dir->i_ino);
-		nm.name = NULL;
-		dent = ubifs_tnc_next_ent(c, &key, &nm);
-		if (IS_ERR(dent)) {
-			err = PTR_ERR(dent);
-			goto out;
-		}
-
-		file->f_pos = key_hash_flash(c, &dent->key);
-		file->private_data = dent;
-	}
-
-	dent = file->private_data;
-	if (!dent) {
-		/*
-		 * The directory was seek'ed to and is now readdir'ed.
-		 * Find the entry corresponding to @file->f_pos or the
-		 * closest one.
-		 */
-		dent_key_init_hash(c, &key, dir->i_ino, file->f_pos);
-		nm.name = NULL;
-		dent = ubifs_tnc_next_ent(c, &key, &nm);
-		if (IS_ERR(dent)) {
-			err = PTR_ERR(dent);
-			goto out;
-		}
-		file->f_pos = key_hash_flash(c, &dent->key);
-		file->private_data = dent;
-	}
-
-	while (1) {
-		dbg_gen("feed '%s', ino %llu, new f_pos %#x",
-			dent->name, (unsigned long long)le64_to_cpu(dent->inum),
-			key_hash_flash(c, &dent->key));
-		ubifs_assert(le64_to_cpu(dent->ch.sqnum) > ubifs_inode(dir)->creat_sqnum);
-
-		nm.len = le16_to_cpu(dent->nlen);
-		over = filldir(c, (char *)dent->name, nm.len,
-			       le64_to_cpu(dent->inum), dent->type);
-		if (over)
-			return 0;
-
-		/* Switch to the next entry */
-		key_read(c, &dent->key, &key);
-		nm.name = (char *)dent->name;
-		dent = ubifs_tnc_next_ent(c, &key, &nm);
-		if (IS_ERR(dent)) {
-			err = PTR_ERR(dent);
-			goto out;
-		}
-
-		kfree(file->private_data);
-		file->f_pos = key_hash_flash(c, &dent->key);
-		file->private_data = dent;
-		cond_resched();
-	}
-
-out:
-	if (err != -ENOENT) {
-		ubifs_err(c, "cannot find next direntry, error %d", err);
-		return err;
-	}
-
-	kfree(file->private_data);
-	file->private_data = NULL;
-	file->f_pos = 2;
-	return 0;
-}
-#endif
-
 static int ubifs_finddir(struct super_block *sb, char *dirname,
 			 unsigned long root_inum, unsigned long *inum)
 {
@@ -549,117 +420,6 @@ static unsigned long ubifs_findfile(struct super_block *sb, const char *filename
 	return 0;
 }
 
-#ifndef __BAREBOX__
-int ubifs_set_blk_dev(block_dev_desc_t *rbdd, disk_partition_t *info)
-{
-	if (rbdd) {
-		debug("UBIFS cannot be used with normal block devices\n");
-		return -1;
-	}
-
-	/*
-	 * Should never happen since get_device_and_partition() already checks
-	 * this, but better safe then sorry.
-	 */
-	if (!ubifs_is_mounted()) {
-		debug("UBIFS not mounted, use ubifsmount to mount volume first!\n");
-		return -1;
-	}
-
-	return 0;
-}
-
-int ubifs_ls(const char *filename)
-{
-	struct ubifs_info *c = ubifs_sb->s_fs_info;
-	struct file *file;
-	struct dentry *dentry;
-	struct inode *dir;
-	void *dirent = NULL;
-	unsigned long inum;
-	int ret = 0;
-
-	c->ubi = ubi_open_volume(c->vi.ubi_num, c->vi.vol_id, UBI_READONLY);
-	inum = ubifs_findfile(ubifs_sb, (char *)filename);
-	if (!inum) {
-		ret = -1;
-		goto out;
-	}
-
-	file = kzalloc(sizeof(struct file), 0);
-	dentry = kzalloc(sizeof(struct dentry), 0);
-	dir = kzalloc(sizeof(struct inode), 0);
-	if (!file || !dentry || !dir) {
-		printf("%s: Error, no memory for malloc!\n", __func__);
-		ret = -ENOMEM;
-		goto out_mem;
-	}
-
-	dir->i_sb = ubifs_sb;
-	file->f_path.dentry = dentry;
-	file->f_path.dentry->d_parent = dentry;
-	file->f_path.dentry->d_inode = dir;
-	file->f_path.dentry->d_inode->i_ino = inum;
-	file->f_pos = 1;
-	file->private_data = NULL;
-	ubifs_printdir(file, dirent);
-
-out_mem:
-	if (file)
-		free(file);
-	if (dentry)
-		free(dentry);
-	if (dir)
-		free(dir);
-
-out:
-	ubi_close_volume(c->ubi);
-	return ret;
-}
-
-int ubifs_exists(const char *filename)
-{
-	struct ubifs_info *c = ubifs_sb->s_fs_info;
-	unsigned long inum;
-
-	c->ubi = ubi_open_volume(c->vi.ubi_num, c->vi.vol_id, UBI_READONLY);
-	inum = ubifs_findfile(ubifs_sb, (char *)filename);
-	ubi_close_volume(c->ubi);
-
-	return inum != 0;
-}
-
-int ubifs_size(const char *filename, loff_t *size)
-{
-	struct ubifs_info *c = ubifs_sb->s_fs_info;
-	unsigned long inum;
-	struct inode *inode;
-	int err = 0;
-
-	c->ubi = ubi_open_volume(c->vi.ubi_num, c->vi.vol_id, UBI_READONLY);
-
-	inum = ubifs_findfile(ubifs_sb, (char *)filename);
-	if (!inum) {
-		err = -1;
-		goto out;
-	}
-
-	inode = ubifs_iget(ubifs_sb, inum);
-	if (IS_ERR(inode)) {
-		printf("%s: Error reading inode %ld!\n", __func__, inum);
-		err = PTR_ERR(inode);
-		goto out;
-	}
-
-	*size = inode->i_size;
-
-	ubifs_iput(inode);
-out:
-	ubi_close_volume(c->ubi);
-	return err;
-}
-#endif
-
 /*
  * ubifsload...
  */
@@ -718,241 +478,6 @@ dump:
 	return -EINVAL;
 }
 
-#ifndef __BAREBOX__
-static int do_readpage(struct ubifs_info *c, struct inode *inode,
-		       struct page *page, int last_block_size)
-{
-	void *addr;
-	int err = 0, i;
-	unsigned int block, beyond;
-	struct ubifs_data_node *dn;
-	loff_t i_size = inode->i_size;
-
-	dbg_gen("ino %lu, pg %lu, i_size %lld",
-		inode->i_ino, page->index, i_size);
-
-	addr = kmap(page);
-
-	block = page->index << UBIFS_BLOCKS_PER_PAGE_SHIFT;
-	beyond = (i_size + UBIFS_BLOCK_SIZE - 1) >> UBIFS_BLOCK_SHIFT;
-	if (block >= beyond) {
-		/* Reading beyond inode */
-		memset(addr, 0, PAGE_CACHE_SIZE);
-		goto out;
-	}
-
-	dn = kmalloc(UBIFS_MAX_DATA_NODE_SZ, GFP_NOFS);
-	if (!dn)
-		return -ENOMEM;
-
-	i = 0;
-	while (1) {
-		int ret;
-
-		if (block >= beyond) {
-			/* Reading beyond inode */
-			err = -ENOENT;
-			memset(addr, 0, UBIFS_BLOCK_SIZE);
-		} else {
-			/*
-			 * Reading last block? Make sure to not write beyond
-			 * the requested size in the destination buffer.
-			 */
-			if (((block + 1) == beyond) || last_block_size) {
-				void *buff;
-				int dlen;
-
-				/*
-				 * We need to buffer the data locally for the
-				 * last block. This is to not pad the
-				 * destination area to a multiple of
-				 * UBIFS_BLOCK_SIZE.
-				 */
-				buff = kzalloc(UBIFS_BLOCK_SIZE, 0);
-				if (!buff) {
-					printf("%s: Error, malloc fails!\n",
-					       __func__);
-					err = -ENOMEM;
-					break;
-				}
-
-				/* Read block-size into temp buffer */
-				ret = read_block(inode, buff, block, dn);
-				if (ret) {
-					err = ret;
-					if (err != -ENOENT) {
-						free(buff);
-						break;
-					}
-				}
-
-				if (last_block_size)
-					dlen = last_block_size;
-				else
-					dlen = le32_to_cpu(dn->size);
-
-				/* Now copy required size back to dest */
-				memcpy(addr, buff, dlen);
-
-				free(buff);
-			} else {
-				ret = read_block(inode, addr, block, dn);
-				if (ret) {
-					err = ret;
-					if (err != -ENOENT)
-						break;
-				}
-			}
-		}
-		if (++i >= UBIFS_BLOCKS_PER_PAGE)
-			break;
-		block += 1;
-		addr += UBIFS_BLOCK_SIZE;
-	}
-	if (err) {
-		if (err == -ENOENT) {
-			/* Not found, so it must be a hole */
-			dbg_gen("hole");
-			goto out_free;
-		}
-		ubifs_err(c, "cannot read page %lu of inode %lu, error %d",
-			  page->index, inode->i_ino, err);
-		goto error;
-	}
-
-out_free:
-	kfree(dn);
-out:
-	return 0;
-
-error:
-	kfree(dn);
-	return err;
-}
-
-int ubifs_read(const char *filename, void *buf, loff_t offset,
-	       loff_t size, loff_t *actread)
-{
-	struct ubifs_info *c = ubifs_sb->s_fs_info;
-	unsigned long inum;
-	struct inode *inode;
-	struct page page;
-	int err = 0;
-	int i;
-	int count;
-	int last_block_size = 0;
-
-	*actread = 0;
-
-	if (offset & (PAGE_SIZE - 1)) {
-		printf("ubifs: Error offset must be a multple of %d\n",
-		       PAGE_SIZE);
-		return -1;
-	}
-
-	c->ubi = ubi_open_volume(c->vi.ubi_num, c->vi.vol_id, UBI_READONLY);
-	/* ubifs_findfile will resolve symlinks, so we know that we get
-	 * the real file here */
-	inum = ubifs_findfile(ubifs_sb, (char *)filename);
-	if (!inum) {
-		err = -1;
-		goto out;
-	}
-
-	/*
-	 * Read file inode
-	 */
-	inode = ubifs_iget(ubifs_sb, inum);
-	if (IS_ERR(inode)) {
-		printf("%s: Error reading inode %ld!\n", __func__, inum);
-		err = PTR_ERR(inode);
-		goto out;
-	}
-
-	if (offset > inode->i_size) {
-		printf("ubifs: Error offset (%lld) > file-size (%lld)\n",
-		       offset, size);
-		err = -1;
-		goto put_inode;
-	}
-
-	/*
-	 * If no size was specified or if size bigger than filesize
-	 * set size to filesize
-	 */
-	if ((size == 0) || (size > (inode->i_size - offset)))
-		size = inode->i_size - offset;
-
-	count = (size + UBIFS_BLOCK_SIZE - 1) >> UBIFS_BLOCK_SHIFT;
-
-	page.addr = buf;
-	page.index = offset / PAGE_SIZE;
-	page.inode = inode;
-	for (i = 0; i < count; i++) {
-		/*
-		 * Make sure to not read beyond the requested size
-		 */
-		if (((i + 1) == count) && (size < inode->i_size))
-			last_block_size = size - (i * PAGE_SIZE);
-
-		err = do_readpage(c, inode, &page, last_block_size);
-		if (err)
-			break;
-
-		page.addr += PAGE_SIZE;
-		page.index++;
-	}
-
-	if (err) {
-		printf("Error reading file '%s'\n", filename);
-		*actread = i * PAGE_SIZE;
-	} else {
-		*actread = size;
-	}
-
-put_inode:
-	ubifs_iput(inode);
-
-out:
-	ubi_close_volume(c->ubi);
-	return err;
-}
-
-void ubifs_close(void)
-{
-}
-
-/* Compat wrappers for common/cmd_ubifs.c */
-int ubifs_load(char *filename, u32 addr, u32 size)
-{
-	loff_t actread;
-	int err;
-
-	printf("Loading file '%s' to addr 0x%08x...\n", filename, addr);
-
-	err = ubifs_read(filename, (void *)addr, 0, size, &actread);
-	if (err == 0) {
-		setenv_hex("filesize", actread);
-		printf("Done\n");
-	}
-
-	return err;
-}
-#endif
-
-void uboot_ubifs_umount(void)
-{
-	if (ubifs_sb) {
-		printf("Unmounting UBIFS volume %s!\n",
-		       ((struct ubifs_info *)(ubifs_sb->s_fs_info))->vi.name);
-		ubifs_umount(ubifs_sb->s_fs_info);
-		ubifs_sb = NULL;
-	}
-}
-
-
-
-
 struct ubifs_file {
 	struct inode *inode;
 	void *buf;
-- 
2.16.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 05/19] fs: Add super_operations
  2018-04-03  7:48 [PATCH 00/19] Add Linux dcache implementation Sascha Hauer
                   ` (3 preceding siblings ...)
  2018-04-03  7:48 ` [PATCH 04/19] ubifs: remove dead code Sascha Hauer
@ 2018-04-03  7:48 ` Sascha Hauer
  2018-04-03  7:48 ` [PATCH 06/19] fs: Move mem_write/mem_read to devfs-core Sascha Hauer
                   ` (13 subsequent siblings)
  18 siblings, 0 replies; 23+ messages in thread
From: Sascha Hauer @ 2018-04-03  7:48 UTC (permalink / raw)
  To: Barebox List

Add a struct super_operations we can use later when we get a fs
implementation closer to Linux. Only add the functions we'll likely
need though.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 fs/ubifs/super.c   |  4 ----
 fs/ubifs/ubifs.h   | 35 -----------------------------------
 include/linux/fs.h |  5 +++++
 3 files changed, 5 insertions(+), 39 deletions(-)

diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
index ce6e95e373..b4eb76202b 100644
--- a/fs/ubifs/super.c
+++ b/fs/ubifs/super.c
@@ -556,7 +556,6 @@ out:
 done:
 	clear_inode(inode);
 }
-#endif
 
 static void ubifs_dirty_inode(struct inode *inode, int flags)
 {
@@ -569,7 +568,6 @@ static void ubifs_dirty_inode(struct inode *inode, int flags)
 	}
 }
 
-#ifndef __BAREBOX__
 static int ubifs_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
 	struct ubifs_info *c = dentry->d_sb->s_fs_info;
@@ -2107,9 +2105,7 @@ const struct super_operations ubifs_super_operations = {
 	.write_inode   = ubifs_write_inode,
 	.evict_inode   = ubifs_evict_inode,
 	.statfs        = ubifs_statfs,
-#endif
 	.dirty_inode   = ubifs_dirty_inode,
-#ifndef __BAREBOX__
 	.remount_fs    = ubifs_remount_fs,
 	.show_options  = ubifs_show_options,
 	.sync_fs       = ubifs_sync_fs,
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
index 1391bd7283..22b24a1161 100644
--- a/fs/ubifs/ubifs.h
+++ b/fs/ubifs/ubifs.h
@@ -97,41 +97,6 @@ void *kmemdup(const void *src, size_t len, gfp_t gfp);
 /* uapi/linux/limits.h */
 #define XATTR_LIST_MAX 65536	/* size of extended attribute namelist (64k) */
 
-struct super_operations {
-   	struct inode *(*alloc_inode)(struct super_block *sb);
-	void (*destroy_inode)(struct inode *);
-
-   	void (*dirty_inode) (struct inode *, int flags);
-#ifndef __BAREBOX__
-	int (*write_inode) (struct inode *, struct writeback_control *wbc);
-#endif
-	int (*drop_inode) (struct inode *);
-	void (*evict_inode) (struct inode *);
-	void (*put_super) (struct super_block *);
-	int (*sync_fs)(struct super_block *sb, int wait);
-	int (*freeze_fs) (struct super_block *);
-	int (*unfreeze_fs) (struct super_block *);
-#ifndef __BAREBOX__
-	int (*statfs) (struct dentry *, struct kstatfs *);
-#endif
-	int (*remount_fs) (struct super_block *, int *, char *);
-	void (*umount_begin) (struct super_block *);
-
-#ifndef __BAREBOX__
-	int (*show_options)(struct seq_file *, struct dentry *);
-	int (*show_devname)(struct seq_file *, struct dentry *);
-	int (*show_path)(struct seq_file *, struct dentry *);
-	int (*show_stats)(struct seq_file *, struct dentry *);
-#endif
-#ifdef CONFIG_QUOTA
-	ssize_t (*quota_read)(struct super_block *, int, char *, size_t, loff_t);
-	ssize_t (*quota_write)(struct super_block *, int, const char *, size_t, loff_t);
-#endif
-	int (*bdev_try_to_free_page)(struct super_block*, struct page*, gfp_t);
-	long (*nr_cached_objects)(struct super_block *, int);
-	long (*free_cached_objects)(struct super_block *, long, int);
-};
-
 /*
  * get_seconds() not really needed in the read-only implmentation
  */
diff --git a/include/linux/fs.h b/include/linux/fs.h
index c1a5802eea..153c464470 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -252,6 +252,11 @@ struct file {
 #endif
 };
 
+struct super_operations {
+	struct inode *(*alloc_inode)(struct super_block *sb);
+	void (*destroy_inode)(struct inode *);
+};
+
 /*
  * Inode flags - they have no relation to superblock flags now
  */
-- 
2.16.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 06/19] fs: Move mem_write/mem_read to devfs-core
  2018-04-03  7:48 [PATCH 00/19] Add Linux dcache implementation Sascha Hauer
                   ` (4 preceding siblings ...)
  2018-04-03  7:48 ` [PATCH 05/19] fs: Add super_operations Sascha Hauer
@ 2018-04-03  7:48 ` Sascha Hauer
  2018-04-03  7:48 ` [PATCH 07/19] fs: Cleanup whitespace damage Sascha Hauer
                   ` (12 subsequent siblings)
  18 siblings, 0 replies; 23+ messages in thread
From: Sascha Hauer @ 2018-04-03  7:48 UTC (permalink / raw)
  To: Barebox List

fs.c is already heavily filled with code. Move mem_write/mem_read
to devfs-core where it fits better.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 fs/devfs-core.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 fs/fs.c         | 66 -------------------------------------------------------
 2 files changed, 68 insertions(+), 66 deletions(-)

diff --git a/fs/devfs-core.c b/fs/devfs-core.c
index d06a534b57..6b5e6da6a8 100644
--- a/fs/devfs-core.c
+++ b/fs/devfs-core.c
@@ -513,3 +513,71 @@ void cdev_remove_loop(struct cdev *cdev)
 	free(cdev->name);
 	free(cdev);
 }
+
+static void memcpy_sz(void *dst, const void *src, size_t count, int rwsize)
+{
+	/* no rwsize specification given. Do whatever memcpy likes best */
+	if (!rwsize) {
+		memcpy(dst, src, count);
+		return;
+	}
+
+	rwsize = rwsize >> O_RWSIZE_SHIFT;
+
+	count /= rwsize;
+
+	while (count-- > 0) {
+		switch (rwsize) {
+		case 1:
+			*((u8 *)dst) = *((u8 *)src);
+			break;
+		case 2:
+			*((u16 *)dst) = *((u16 *)src);
+			break;
+		case 4:
+			*((u32  *)dst) = *((u32  *)src);
+			break;
+		case 8:
+			*((u64  *)dst) = *((u64  *)src);
+			break;
+		}
+		dst += rwsize;
+		src += rwsize;
+	}
+}
+
+ssize_t mem_read(struct cdev *cdev, void *buf, size_t count, loff_t offset,
+		 unsigned long flags)
+{
+	unsigned long size;
+	struct device_d *dev;
+
+	if (!cdev->dev || cdev->dev->num_resources < 1)
+		return -1;
+	dev = cdev->dev;
+
+	size = min((resource_size_t)count,
+			resource_size(&dev->resource[0]) -
+			(resource_size_t)offset);
+	memcpy_sz(buf, dev_get_mem_region(dev, 0) + offset, size, flags & O_RWSIZE_MASK);
+	return size;
+}
+EXPORT_SYMBOL(mem_read);
+
+ssize_t mem_write(struct cdev *cdev, const void *buf, size_t count, loff_t offset,
+		  unsigned long flags)
+{
+	unsigned long size;
+	struct device_d *dev;
+
+	if (!cdev->dev || cdev->dev->num_resources < 1)
+		return -1;
+	dev = cdev->dev;
+
+	size = min((resource_size_t)count,
+			resource_size(&dev->resource[0]) -
+			(resource_size_t)offset);
+	memcpy_sz(dev_get_mem_region(dev, 0) + offset, buf, size, flags & O_RWSIZE_MASK);
+	return size;
+}
+EXPORT_SYMBOL(mem_write);
diff --git a/fs/fs.c b/fs/fs.c
index 5135112c8b..ca4fe70e15 100644
--- a/fs/fs.c
+++ b/fs/fs.c
@@ -1739,72 +1739,6 @@ out:
 }
 EXPORT_SYMBOL(rmdir);
 
-static void memcpy_sz(void *dst, const void *src, size_t count, int rwsize)
-{
-	/* no rwsize specification given. Do whatever memcpy likes best */
-	if (!rwsize) {
-		memcpy(dst, src, count);
-		return;
-	}
-
-	rwsize = rwsize >> O_RWSIZE_SHIFT;
-
-	count /= rwsize;
-
-	while (count-- > 0) {
-		switch (rwsize) {
-		case 1:
-			*((u8 *)dst) = *((u8 *)src);
-			break;
-		case 2:
-			*((u16 *)dst) = *((u16 *)src);
-			break;
-		case 4:
-			*((u32  *)dst) = *((u32  *)src);
-			break;
-		case 8:
-			*((u64  *)dst) = *((u64  *)src);
-			break;
-		}
-		dst += rwsize;
-		src += rwsize;
-	}
-}
-
-ssize_t mem_read(struct cdev *cdev, void *buf, size_t count, loff_t offset, ulong flags)
-{
-	ulong size;
-	struct device_d *dev;
-
-	if (!cdev->dev || cdev->dev->num_resources < 1)
-		return -1;
-	dev = cdev->dev;
-
-	size = min((resource_size_t)count,
-			resource_size(&dev->resource[0]) -
-			(resource_size_t)offset);
-	memcpy_sz(buf, dev_get_mem_region(dev, 0) + offset, size, flags & O_RWSIZE_MASK);
-	return size;
-}
-EXPORT_SYMBOL(mem_read);
-
-ssize_t mem_write(struct cdev *cdev, const void *buf, size_t count, loff_t offset, ulong flags)
-{
-	ulong size;
-	struct device_d *dev;
-
-	if (!cdev->dev || cdev->dev->num_resources < 1)
-		return -1;
-	dev = cdev->dev;
-
-	size = min((resource_size_t)count,
-			resource_size(&dev->resource[0]) -
-			(resource_size_t)offset);
-	memcpy_sz(dev_get_mem_region(dev, 0) + offset, buf, size, flags & O_RWSIZE_MASK);
-	return size;
-}
-EXPORT_SYMBOL(mem_write);
-
 /*
  * cdev_get_mount_path - return the path a cdev is mounted on
  *
-- 
2.16.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 07/19] fs: Cleanup whitespace damage
  2018-04-03  7:48 [PATCH 00/19] Add Linux dcache implementation Sascha Hauer
                   ` (5 preceding siblings ...)
  2018-04-03  7:48 ` [PATCH 06/19] fs: Move mem_write/mem_read to devfs-core Sascha Hauer
@ 2018-04-03  7:48 ` Sascha Hauer
  2018-04-03  7:48 ` [PATCH 08/19] fs: Fix finding correct directory for mkdir/rmdir Sascha Hauer
                   ` (11 subsequent siblings)
  18 siblings, 0 replies; 23+ messages in thread
From: Sascha Hauer @ 2018-04-03  7:48 UTC (permalink / raw)
  To: Barebox List

fs.c has some whitespaces where there should be tabs. Fix it.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 fs/fs.c | 26 +++++++++++++-------------
 1 file changed, 13 insertions(+), 13 deletions(-)

diff --git a/fs/fs.c b/fs/fs.c
index ca4fe70e15..92f336b821 100644
--- a/fs/fs.c
+++ b/fs/fs.c
@@ -99,13 +99,13 @@ char *normalise_path(const char *pathname)
 
 	slashes[0] = in = out = path;
 
-        while (*in) {
-                if(*in == '/') {
+	while (*in) {
+		if(*in == '/') {
 			slashes[sl++] = out;
-                        *out++ = *in++;
-                        while(*in == '/')
-                                in++;
-                } else {
+			*out++ = *in++;
+			while(*in == '/')
+				in++;
+		} else {
 			if (*in == '.' && (*(in + 1) == '/' || !*(in + 1))) {
 				sl--;
 				if (sl < 0)
@@ -123,16 +123,16 @@ char *normalise_path(const char *pathname)
 				continue;
 			}
                         *out++ = *in++;
-                }
-        }
+		}
+	}
 
 	*out-- = 0;
 
-        /*
-         * Remove trailing slash
-         */
-        if (*out == '/')
-                *out = 0;
+	/*
+	 * Remove trailing slash
+	 */
+	if (*out == '/')
+		*out = 0;
 
 	if (!*path) {
 		*path = '/';
-- 
2.16.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 08/19] fs: Fix finding correct directory for mkdir/rmdir
  2018-04-03  7:48 [PATCH 00/19] Add Linux dcache implementation Sascha Hauer
                   ` (6 preceding siblings ...)
  2018-04-03  7:48 ` [PATCH 07/19] fs: Cleanup whitespace damage Sascha Hauer
@ 2018-04-03  7:48 ` Sascha Hauer
  2018-04-03  7:48 ` [PATCH 09/19] glob: do not unnecessarily opendir() a directory Sascha Hauer
                   ` (10 subsequent siblings)
  18 siblings, 0 replies; 23+ messages in thread
From: Sascha Hauer @ 2018-04-03  7:48 UTC (permalink / raw)
  To: Barebox List

When there are links in the path mkdir/rmdir are called with then
canonicalize_path is needed which resolves the links.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 fs/fs.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/fs/fs.c b/fs/fs.c
index 92f336b821..b66cc9b178 100644
--- a/fs/fs.c
+++ b/fs/fs.c
@@ -1660,7 +1660,7 @@ int mkdir (const char *pathname, mode_t mode)
 {
 	struct fs_driver_d *fsdrv;
 	struct fs_device_d *fsdev;
-	char *p = normalise_path(pathname);
+	char *p = canonicalize_path(pathname);
 	char *freep = p;
 	int ret;
 	struct stat s;
@@ -1700,7 +1700,7 @@ int rmdir (const char *pathname)
 {
 	struct fs_driver_d *fsdrv;
 	struct fs_device_d *fsdev;
-	char *p = normalise_path(pathname);
+	char *p = canonicalize_path(pathname);
 	char *freep = p;
 	int ret;
 	struct stat s;
-- 
2.16.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 09/19] glob: do not unnecessarily opendir() a directory
  2018-04-03  7:48 [PATCH 00/19] Add Linux dcache implementation Sascha Hauer
                   ` (7 preceding siblings ...)
  2018-04-03  7:48 ` [PATCH 08/19] fs: Fix finding correct directory for mkdir/rmdir Sascha Hauer
@ 2018-04-03  7:48 ` Sascha Hauer
  2018-04-03  7:48 ` [PATCH 10/19] ls: Do not depend on normalise_path() Sascha Hauer
                   ` (9 subsequent siblings)
  18 siblings, 0 replies; 23+ messages in thread
From: Sascha Hauer @ 2018-04-03  7:48 UTC (permalink / raw)
  To: Barebox List

opendir() can trigger automounts, so do not use it when the
pattern we examine doesn't have any wildcards.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 lib/glob.c | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/lib/glob.c b/lib/glob.c
index 5a997ca092..32f7afdce8 100644
--- a/lib/glob.c
+++ b/lib/glob.c
@@ -313,7 +313,7 @@ static int prefix_array(const char *dirname, char **array, size_t n,
 static int glob_in_dir(const char *pattern, const char *directory,
 		int flags, int (*errfunc) __P((const char *, int)), glob_t *pglob)
 {
-	__ptr_t stream;
+	__ptr_t stream = NULL;
 
 	struct globlink {
 		struct globlink *next;
@@ -323,7 +323,13 @@ static int glob_in_dir(const char *pattern, const char *directory,
 	size_t nfound = 0;
 	int meta;
 
-	stream = opendir(directory);
+	meta = glob_pattern_p(pattern, !(flags & GLOB_NOESCAPE));
+
+	if (meta)
+		flags |= GLOB_MAGCHAR;
+
+	if (meta)
+		stream = opendir(directory);
 
 	if (stream == NULL) {
 		if ((errfunc != NULL && (*errfunc) (directory, errno)) ||
@@ -331,11 +337,6 @@ static int glob_in_dir(const char *pattern, const char *directory,
 			return GLOB_ABORTED;
 	}
 
-	meta = glob_pattern_p(pattern, !(flags & GLOB_NOESCAPE));
-
-	if (meta)
-		flags |= GLOB_MAGCHAR;
-
 	while (1) {
 		const char *name;
 		size_t len;
-- 
2.16.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 10/19] ls: Do not depend on normalise_path()
  2018-04-03  7:48 [PATCH 00/19] Add Linux dcache implementation Sascha Hauer
                   ` (8 preceding siblings ...)
  2018-04-03  7:48 ` [PATCH 09/19] glob: do not unnecessarily opendir() a directory Sascha Hauer
@ 2018-04-03  7:48 ` Sascha Hauer
  2018-04-03  7:48 ` [PATCH 11/19] loadenv: " Sascha Hauer
                   ` (8 subsequent siblings)
  18 siblings, 0 replies; 23+ messages in thread
From: Sascha Hauer @ 2018-04-03  7:48 UTC (permalink / raw)
  To: Barebox List

When we want to show a directory we want to show the path
ls is passed, not the normalised one.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 commands/ls.c | 9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)

diff --git a/commands/ls.c b/commands/ls.c
index 771477b6e0..e54991862d 100644
--- a/commands/ls.c
+++ b/commands/ls.c
@@ -115,11 +115,8 @@ int ls(const char *path, ulong flags)
 			continue;
 		}
 
-		if (s.st_mode & S_IFDIR) {
-			char *norm = normalise_path(tmp);
-			ls(norm, flags);
-			free(norm);
-		}
+		if (s.st_mode & S_IFDIR)
+			ls(tmp, flags);
 	}
 
 out:
@@ -158,7 +155,7 @@ static int do_ls(int argc, char *argv[])
 		flags |= LS_SHOWARG;
 
 	if (optind == argc) {
-		ret = ls(getcwd(), flags);
+		ret = ls(".", flags);
 		return ret ? 1 : 0;
 	}
 
-- 
2.16.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 11/19] loadenv: Do not depend on normalise_path()
  2018-04-03  7:48 [PATCH 00/19] Add Linux dcache implementation Sascha Hauer
                   ` (9 preceding siblings ...)
  2018-04-03  7:48 ` [PATCH 10/19] ls: Do not depend on normalise_path() Sascha Hauer
@ 2018-04-03  7:48 ` Sascha Hauer
  2018-04-03  7:48 ` [PATCH 12/19] fs: dcache implementation Sascha Hauer
                   ` (7 subsequent siblings)
  18 siblings, 0 replies; 23+ messages in thread
From: Sascha Hauer @ 2018-04-03  7:48 UTC (permalink / raw)
  To: Barebox List

normalise_path() will go away, so do without it.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 commands/loadenv.c | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/commands/loadenv.c b/commands/loadenv.c
index 44e96c3b60..6469affadb 100644
--- a/commands/loadenv.c
+++ b/commands/loadenv.c
@@ -62,20 +62,16 @@ static int do_loadenv(int argc, char *argv[])
 	if (argc - optind < 1) {
 		filename = default_environment_path_get();
 	} else {
-		char *str = normalise_path(argv[optind]);
-
 		/*
 		 * /dev/defaultenv use to contain the defaultenvironment.
 		 * we do not have this file anymore, but maintain compatibility
 		 * to the 'loadenv -s /dev/defaultenv' command to restore the
 		 * default environment for some time.
 		 */
-		if (!strcmp(str, "/dev/defaultenv"))
+		if (!strcmp(argv[optind], "/dev/defaultenv"))
 			defaultenv = 1;
 		else
 			filename = argv[optind];
-
-		free(str);
 	}
 
 	if (scrub) {
-- 
2.16.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 12/19] fs: dcache implementation
  2018-04-03  7:48 [PATCH 00/19] Add Linux dcache implementation Sascha Hauer
                   ` (10 preceding siblings ...)
  2018-04-03  7:48 ` [PATCH 11/19] loadenv: " Sascha Hauer
@ 2018-04-03  7:48 ` Sascha Hauer
  2018-04-03  7:48 ` [PATCH 13/19] fs: ramfs: Switch to " Sascha Hauer
                   ` (6 subsequent siblings)
  18 siblings, 0 replies; 23+ messages in thread
From: Sascha Hauer @ 2018-04-03  7:48 UTC (permalink / raw)
  To: Barebox List

This adds the Linux dcache implementation to barebox.

Until now every filesystem driver resolves the full path to a file for
itself. This leads to code duplication and is error prone since
resolving paths is a complicated task. Also it can narrow down the
lookup performance since barebox only knows ASCII paths and has no way
of caching lookups.

With this patch we get the Linux dcache implementation. The path
resolving code from fs/namei.c is nearly taken as-is, minus the RCU
and locking code. Dcaching is made simple as of now: We simply cache
everything and never release any dentries. Although we do reference
counting for inodes and dentries it is effectively not used yet.
We never free anything until a fs is unmounted in which case we free
everything no matter if references are taken or not.

This patch fundamentally changes the way lookups are done in the
filesystem drivers and I found no sane way to maintain a backwards
compatible code path for not yet converted filesystem drivers. This
means *all* filesystems are marked as broken in this patch, they need
to be fixed one by one afterwards.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 fs/Kconfig             |   12 +
 fs/Makefile            |    2 +-
 fs/ext4/Kconfig        |    1 +
 fs/fat/Kconfig         |    1 +
 fs/fs.c                | 3584 ++++++++++++++++++++++++++++++++----------------
 fs/libfs.c             |   87 ++
 fs/pstore/Kconfig      |    1 +
 fs/squashfs/Kconfig    |    1 +
 fs/ubifs/Kconfig       |    1 +
 include/dirent.h       |    3 +
 include/fs.h           |   25 +-
 include/linux/dcache.h |  109 +-
 include/linux/fs.h     |  131 +-
 include/linux/mount.h  |    3 +
 include/linux/namei.h  |   52 +
 include/linux/stat.h   |    2 +
 16 files changed, 2746 insertions(+), 1269 deletions(-)
 create mode 100644 fs/libfs.c
 create mode 100644 include/linux/namei.h

diff --git a/fs/Kconfig b/fs/Kconfig
index 3512000556..c3a78eaae5 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -12,6 +12,7 @@ config FS_AUTOMOUNT
 config FS_CRAMFS
 	bool
 	select ZLIB
+	depends on BROKEN
 	prompt "cramfs support"
 
 source fs/ext4/Kconfig
@@ -19,15 +20,18 @@ source fs/ext4/Kconfig
 config FS_RAMFS
 	bool
 	default y
+	depends on BROKEN
 	prompt "ramfs support"
 
 config FS_DEVFS
 	bool
 	default y
+	depends on BROKEN
 	prompt "devfs support"
 
 config FS_TFTP
 	bool
+	depends on BROKEN
 	prompt "tftp support"
 	depends on NET
 
@@ -35,14 +39,17 @@ config FS_OMAP4_USBBOOT
 	bool
 	prompt "Filesystem over usb boot"
 	depends on OMAP4_USBBOOT
+	depends on BROKEN
 
 config FS_NFS
 	depends on NET
+	depends on BROKEN
 	bool
 	prompt "nfs support"
 
 config FS_EFI
 	depends on EFI_BOOTUP
+	depends on BROKEN
 	bool
 	prompt "EFI filesystem support"
 	help
@@ -51,6 +58,7 @@ config FS_EFI
 
 config FS_EFIVARFS
 	depends on EFI_BOOTUP
+	depends on BROKEN
 	bool
 	prompt "EFI variable filesystem support (efivarfs)"
 	help
@@ -62,6 +70,7 @@ source fs/ubifs/Kconfig
 config FS_BPKFS
 	bool
 	select CRC32
+	depends on BROKEN
 	prompt "BPKFS support"
 	help
 	  Simple update file format developed for Somfy, tools and library are
@@ -78,10 +87,12 @@ config FS_BPKFS
 config FS_UIMAGEFS
 	bool
 	select CRC32
+	depends on BROKEN
 	prompt "uImage FS support"
 
 config FS_SMHFS
 	depends on ARM_SEMIHOSTING
+	depends on BROKEN
 	bool
 	prompt "Semihosting FS support"
 	help
@@ -95,6 +106,7 @@ source fs/squashfs/Kconfig
 config FS_RATP
 	bool
 	depends on RATP
+	depends on BROKEN
 	prompt "RATP filesystem support"
 	help
 	  This enables support for transferring files over RATP. A host can
diff --git a/fs/Makefile b/fs/Makefile
index 8e3fd78e92..d3e46c2525 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -4,7 +4,7 @@ obj-$(CONFIG_FS_RAMFS)	+= ramfs.o
 obj-y			+= devfs-core.o
 obj-$(CONFIG_FS_DEVFS)	+= devfs.o
 obj-$(CONFIG_FS_FAT)	+= fat/
-obj-y	+= fs.o
+obj-y	+= fs.o libfs.o
 obj-$(CONFIG_FS_UBIFS)	+= ubifs/
 obj-$(CONFIG_FS_TFTP)	+= tftp.o
 obj-$(CONFIG_FS_OMAP4_USBBOOT)	+= omap4_usbbootfs.o
diff --git a/fs/ext4/Kconfig b/fs/ext4/Kconfig
index f36043d9a7..ad1bf58536 100644
--- a/fs/ext4/Kconfig
+++ b/fs/ext4/Kconfig
@@ -1,3 +1,4 @@
 config FS_EXT4
 	bool
+	depends on BROKEN
 	prompt "ext4 filesystem support"
diff --git a/fs/fat/Kconfig b/fs/fat/Kconfig
index 0699728494..6fc486a207 100644
--- a/fs/fat/Kconfig
+++ b/fs/fat/Kconfig
@@ -1,4 +1,5 @@
 menuconfig FS_FAT
+	depends on BROKEN
 	bool
 	prompt "FAT filesystem support"
 
diff --git a/fs/fs.c b/fs/fs.c
index b66cc9b178..aa4a69a3eb 100644
--- a/fs/fs.c
+++ b/fs/fs.c
@@ -36,6 +36,7 @@
 #include <block.h>
 #include <libfile.h>
 #include <parseopt.h>
+#include <linux/namei.h>
 
 char *mkmodestr(unsigned long mode, char *str)
 {
@@ -69,8 +70,12 @@ char *mkmodestr(unsigned long mode, char *str)
 EXPORT_SYMBOL(mkmodestr);
 
 static char *cwd;
+static struct dentry *cwd_dentry;
+static struct vfsmount *cwd_mnt;
 
 static FILE *files;
+static struct dentry *d_root;
+static struct vfsmount *mnt_root;
 
 static int init_fs(void)
 {
@@ -84,226 +89,40 @@ static int init_fs(void)
 
 postcore_initcall(init_fs);
 
-char *normalise_path(const char *pathname)
-{
-	char *path = xzalloc(strlen(pathname) + strlen(cwd) + 2);
-        char *in, *out, *slashes[32];
-	int sl = 0;
-
-	debug("in: %s\n", pathname);
-
-	if (*pathname != '/')
-		strcpy(path, cwd);
-	strcat(path, "/");
-	strcat(path, pathname);
-
-	slashes[0] = in = out = path;
-
-	while (*in) {
-		if(*in == '/') {
-			slashes[sl++] = out;
-			*out++ = *in++;
-			while(*in == '/')
-				in++;
-		} else {
-			if (*in == '.' && (*(in + 1) == '/' || !*(in + 1))) {
-				sl--;
-				if (sl < 0)
-					sl = 0;
-				out = slashes[sl];
-				in++;
-				continue;
-			}
-			if (*in == '.' && *(in + 1) == '.') {
-				sl -= 2;
-				if (sl < 0)
-					sl = 0;
-				out = slashes[sl];
-				in += 2;
-				continue;
-			}
-                        *out++ = *in++;
-		}
-	}
-
-	*out-- = 0;
-
-	/*
-	 * Remove trailing slash
-	 */
-	if (*out == '/')
-		*out = 0;
-
-	if (!*path) {
-		*path = '/';
-		*(path + 1) = 0;
-	}
-
-	return path;
-}
-EXPORT_SYMBOL(normalise_path);
-
-static int __lstat(const char *filename, struct stat *s);
 static struct fs_device_d *get_fsdevice_by_path(const char *path);
 
-static char *__canonicalize_path(const char *_pathname, int level)
-{
-	char *path, *freep;
-	char *outpath;
-	int ret;
-	struct stat s;
-
-	if (level > 10)
-		return ERR_PTR(-ELOOP);
-
-	path = freep = xstrdup(_pathname);
-
-	if (*path == '/' || !strcmp(cwd, "/"))
-		outpath = xstrdup("");
-	else
-		outpath = __canonicalize_path(cwd, level + 1);
-
-	while (1) {
-		char *p = strsep(&path, "/");
-		char *tmp;
-		char link[PATH_MAX] = {};
-		struct fs_device_d *fsdev;
-
-		if (!p)
-			break;
-		if (p[0] == '\0')
-			continue;
-		if (!strcmp(p, "."))
-			continue;
-		if (!strcmp(p, "..")) {
-			tmp = xstrdup(dirname(outpath));
-			free(outpath);
-			outpath = tmp;
-			continue;
-		}
-
-		tmp = basprintf("%s/%s", outpath, p);
-		free(outpath);
-		outpath = tmp;
-
-		/*
-		 * Don't bother filesystems without link support
-		 * with an additional stat() call.
-		 */
-		fsdev = get_fsdevice_by_path(outpath);
-		if (!fsdev || !fsdev->driver->readlink)
-			continue;
-
-		ret = __lstat(outpath, &s);
-		if (ret)
-			goto out;
-
-		if (!S_ISLNK(s.st_mode))
-			continue;
-
-		ret = readlink(outpath, link, PATH_MAX - 1);
-		if (ret < 0)
-			goto out;
-
-		if (link[0] == '/') {
-			free(outpath);
-			outpath = __canonicalize_path(link, level + 1);
-		} else {
-			tmp = basprintf("%s/%s", dirname(outpath), link);
-			free(outpath);
-			outpath = __canonicalize_path(tmp, level + 1);
-			free(tmp);
-		}
-
-		if (IS_ERR(outpath))
-			goto out;
-	}
-out:
-	free(freep);
-
-	if (!*outpath) {
-		free(outpath);
-		outpath = xstrdup("/");
-	}
-
-	return outpath;
-}
+LIST_HEAD(fs_device_list);
 
-/*
- * canonicalize_path - resolve links in path
- * @pathname: The input path
- *
- * This function resolves all links in @pathname and returns
- * a path without links in it.
- *
- * Return: Path with links resolved. Allocated, must be freed after use.
- */
-char *canonicalize_path(const char *pathname)
+struct vfsmount *mntget(struct vfsmount *mnt)
 {
-	char *r, *p = __canonicalize_path(pathname, 0);
-
-	if (IS_ERR(p))
-		return ERR_CAST(p);
+	if (!mnt)
+		return NULL;
 
-	r = normalise_path(p);
-	free(p);
+	mnt->ref++;
 
-	return r;
+	return mnt;
 }
 
-/*
- * canonicalize_dir - resolve links in path
- * @pathname: The input path
- *
- * This function resolves all links except the last one. Needed to give
- * access to the link itself.
- *
- * Return: Path with links resolved. Allocated, must be freed after use.
- */
-static char *canonicalize_dir(const char *pathname)
+void mntput(struct vfsmount *mnt)
 {
-	char *f, *d, *r, *ret, *p;
-	char *freep1, *freep2;
-
-	freep1 = xstrdup(pathname);
-	freep2 = xstrdup(pathname);
-	f = basename(freep1);
-	d = dirname(freep2);
-
-	p = __canonicalize_path(d, 0);
-	if (IS_ERR(p)) {
-		ret = ERR_CAST(p);
-		goto out;
-	}
-
-	r = basprintf("%s/%s", p, f);
-
-	ret = normalise_path(r);
-
-	free(r);
-	free(p);
-out:
-	free(freep1);
-	free(freep2);
+	if (!mnt)
+		return;
 
-	return ret;
+	mnt->ref--;
 }
 
-LIST_HEAD(fs_device_list);
-static struct fs_device_d *fs_dev_root;
-
-static struct fs_device_d *get_fsdevice_by_path(const char *path)
+struct vfsmount *lookup_mnt(struct path *path)
 {
-	struct fs_device_d *fsdev = NULL;
+	struct fs_device_d *fsdev;
 
 	for_each_fs_device(fsdev) {
-		int len = strlen(fsdev->path);
-		if (!strncmp(path, fsdev->path, len) &&
-				(path[len] == '/' || path[len] == 0))
-			return fsdev;
+		if (path->dentry == fsdev->vfsmount.mountpoint) {
+			mntget(&fsdev->vfsmount);
+			return &fsdev->vfsmount;
+		}
 	}
 
-	return fs_dev_root;
+	return NULL;
 }
 
 /*
@@ -348,6 +167,8 @@ static void put_file(FILE *f)
 	free(f->path);
 	f->path = NULL;
 	f->in_use = 0;
+	iput(f->f_inode);
+	dput(f->dentry);
 }
 
 static int check_fd(int fd)
@@ -360,388 +181,284 @@ static int check_fd(int fd)
 	return 0;
 }
 
-#ifdef CONFIG_FS_AUTOMOUNT
-
-#define AUTOMOUNT_IS_FILE (1 << 0)
+int create(struct dentry *dir, struct dentry *dentry)
+{
+	struct inode *inode;
 
-struct automount {
-	char *path;
-	char *cmd;
-	struct list_head list;
-	unsigned int flags;
-};
+	if (d_is_negative(dir))
+		return -ENOENT;
 
-static LIST_HEAD(automount_list);
+	inode = d_inode(dir);
 
-void automount_remove(const char *_path)
-{
-	char *path = normalise_path(_path);
-	struct automount *am;
+	if (!inode->i_op->create)
+		return -EROFS;
 
-	list_for_each_entry(am, &automount_list, list) {
-		if (!strcmp(path, am->path))
-			goto found;
-	}
+	return inode->i_op->create(inode, dentry, S_IFREG | S_IRWXU | S_IRWXG | S_IRWXO);
+}
 
-	return;
-found:
-	list_del(&am->list);
-	free(am->path);
-	free(am->cmd);
-	free(am);
+int creat(const char *pathname, mode_t mode)
+{
+	return open(pathname, O_CREAT | O_WRONLY | O_TRUNC);
 }
-EXPORT_SYMBOL(automount_remove);
+EXPORT_SYMBOL(creat);
 
-int automount_add(const char *path, const char *cmd)
+int ftruncate(int fd, loff_t length)
 {
-	struct automount *am = xzalloc(sizeof(*am));
-	struct stat s;
+	struct fs_driver_d *fsdrv;
+	FILE *f;
 	int ret;
 
-	am->path = normalise_path(path);
-	am->cmd = xstrdup(cmd);
+	if (check_fd(fd))
+		return -errno;
 
-	automount_remove(am->path);
+	f = &files[fd];
 
-	ret = stat(path, &s);
-	if (!ret) {
-		/*
-		 * If it exists it must be a directory
-		 */
-		if (!S_ISDIR(s.st_mode))
-			return -ENOTDIR;
-	} else {
-		am->flags |= AUTOMOUNT_IS_FILE;
-	}
+	fsdrv = f->fsdev->driver;
 
-	list_add_tail(&am->list, &automount_list);
+	ret = fsdrv->truncate(&f->fsdev->dev, f, length);
+	if (ret)
+		return ret;
+
+	f->size = length;
 
 	return 0;
 }
-EXPORT_SYMBOL(automount_add);
 
-void cdev_create_default_automount(struct cdev *cdev)
+int ioctl(int fd, int request, void *buf)
 {
-	char *path, *cmd;
-
-	path = basprintf("/mnt/%s", cdev->name);
-	cmd = basprintf("mount %s", cdev->name);
+	struct fs_driver_d *fsdrv;
+	FILE *f;
+	int ret;
 
-	make_directory(path);
-	automount_add(path, cmd);
+	if (check_fd(fd))
+		return -errno;
 
-	free(cmd);
-	free(path);
-}
+	f = &files[fd];
 
-void automount_print(void)
-{
-	struct automount *am;
+	fsdrv = f->fsdev->driver;
 
-	list_for_each_entry(am, &automount_list, list)
-		printf("%-20s %s\n", am->path, am->cmd);
+	if (fsdrv->ioctl)
+		ret = fsdrv->ioctl(&f->fsdev->dev, f, request, buf);
+	else
+		ret = -ENOSYS;
+	if (ret)
+		errno = -ret;
+	return ret;
 }
-EXPORT_SYMBOL(automount_print);
 
-static void automount_mount(const char *path, int instat)
+static ssize_t __read(FILE *f, void *buf, size_t count)
 {
-	struct automount *am;
+	struct fs_driver_d *fsdrv;
 	int ret;
-	static int in_automount;
-
-	if (in_automount)
-		return;
-
-	in_automount++;
 
-	if (fs_dev_root != get_fsdevice_by_path(path))
+	if ((f->flags & O_ACCMODE) == O_WRONLY) {
+		ret = -EBADF;
 		goto out;
+	}
 
-	list_for_each_entry(am, &automount_list, list) {
-		int len_path = strlen(path);
-		int len_am_path = strlen(am->path);
-
-		/*
-		 * stat is a bit special. We do not want to trigger
-		 * automount when someone calls stat() on the automount
-		 * directory itself.
-		 */
-		if (instat && !(am->flags & AUTOMOUNT_IS_FILE) &&
-				len_path == len_am_path) {
-			continue;
-		}
+	fsdrv = f->fsdev->driver;
 
-		if (len_path < len_am_path)
-			continue;
+	if (f->size != FILE_SIZE_STREAM && f->pos + count > f->size)
+		count = f->size - f->pos;
 
-		if (strncmp(path, am->path, len_am_path))
-			continue;
+	if (!count)
+		return 0;
 
-		if (*(path + len_am_path) != 0 && *(path + len_am_path) != '/')
-			continue;
+	ret = fsdrv->read(&f->fsdev->dev, f, buf, count);
+out:
+	if (ret < 0)
+		errno = -ret;
+	return ret;
+}
 
-		setenv("automount_path", am->path);
-		export("automount_path");
-		ret = run_command(am->cmd);
-		setenv("automount_path", NULL);
+ssize_t pread(int fd, void *buf, size_t count, loff_t offset)
+{
+	loff_t pos;
+	FILE *f;
+	int ret;
 
-		if (ret)
-			printf("running automount command '%s' failed\n",
-					am->cmd);
+	if (check_fd(fd))
+		return -errno;
 
-		break;
-	}
-out:
-	in_automount--;
-}
+	f = &files[fd];
 
-BAREBOX_MAGICVAR(automount_path, "mountpath passed to automount scripts");
+	pos = f->pos;
+	f->pos = offset;
+	ret = __read(f, buf, count);
+	f->pos = pos;
 
-#else
-static void automount_mount(const char *path, int instat)
-{
+	return ret;
 }
-#endif /* CONFIG_FS_AUTOMOUNT */
+EXPORT_SYMBOL(pread);
 
-static struct fs_device_d *get_fs_device_and_root_path(char **path)
+ssize_t read(int fd, void *buf, size_t count)
 {
-	struct fs_device_d *fsdev;
+	FILE *f;
+	int ret;
 
-	automount_mount(*path, 0);
+	if (check_fd(fd))
+		return -errno;
 
-	fsdev = get_fsdevice_by_path(*path);
-	if (!fsdev)
-		return NULL;
-	if (fsdev != fs_dev_root)
-		*path += strlen(fsdev->path);
+	f = &files[fd];
 
-	return fsdev;
+	ret = __read(f, buf, count);
+
+	if (ret > 0)
+		f->pos += ret;
+	return ret;
 }
+EXPORT_SYMBOL(read);
 
-static int dir_is_empty(const char *pathname)
+static ssize_t __write(FILE *f, const void *buf, size_t count)
 {
-	DIR *dir;
-	struct dirent *d;
-	int ret = 1;
+	struct fs_driver_d *fsdrv;
+	int ret;
 
-	dir = opendir(pathname);
-	if (!dir) {
-		errno = ENOENT;
-		return -ENOENT;
+	if (!(f->flags & O_ACCMODE)) {
+		ret = -EBADF;
+		goto out;
 	}
 
-	while ((d = readdir(dir))) {
-		if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
-				continue;
-		ret = 0;
-		break;
+	fsdrv = f->fsdev->driver;
+	if (f->size != FILE_SIZE_STREAM && f->pos + count > f->size) {
+		ret = fsdrv->truncate(&f->fsdev->dev, f, f->pos + count);
+		if (ret) {
+			if (ret != -ENOSPC)
+				goto out;
+			count = f->size - f->pos;
+			if (!count)
+				goto out;
+		} else {
+			f->size = f->pos + count;
+			f->f_inode->i_size = f->size;
+		}
 	}
-
-	closedir(dir);
+	ret = fsdrv->write(&f->fsdev->dev, f, buf, count);
+out:
+	if (ret < 0)
+		errno = -ret;
 	return ret;
 }
 
-static int parent_check_directory(const char *path)
+ssize_t pwrite(int fd, const void *buf, size_t count, loff_t offset)
 {
-	struct stat s;
+	loff_t pos;
+	FILE *f;
 	int ret;
-	char *dir = dirname(xstrdup(path));
 
-	ret = lstat(dir, &s);
-
-	free(dir);
-
-	if (ret)
-		return -ENOENT;
+	if (check_fd(fd))
+		return -errno;
 
-	if (!S_ISDIR(s.st_mode))
-		return -ENOTDIR;
+	f = &files[fd];
 
-	return 0;
-}
+	pos = f->pos;
+	f->pos = offset;
+	ret = __write(f, buf, count);
+	f->pos = pos;
 
-const char *getcwd(void)
-{
-	return cwd;
+	return ret;
 }
-EXPORT_SYMBOL(getcwd);
+EXPORT_SYMBOL(pwrite);
 
-int chdir(const char *pathname)
+ssize_t write(int fd, const void *buf, size_t count)
 {
-	char *p = normalise_path(pathname);
+	FILE *f;
 	int ret;
-	struct stat s;
-
-	ret = stat(p, &s);
-	if (ret)
-		goto out;
-
-	if (!S_ISDIR(s.st_mode)) {
-		ret = -ENOTDIR;
-		goto out;
-	}
-
-	automount_mount(p, 0);
 
-	strcpy(cwd, p);
+	if (check_fd(fd))
+		return -errno;
 
-out:
-	free(p);
+	f = &files[fd];
 
-	if (ret)
-		errno = -ret;
+	ret = __write(f, buf, count);
 
+	if (ret > 0)
+		f->pos += ret;
 	return ret;
 }
-EXPORT_SYMBOL(chdir);
+EXPORT_SYMBOL(write);
 
-int unlink(const char *pathname)
+int flush(int fd)
 {
-	struct fs_device_d *fsdev;
 	struct fs_driver_d *fsdrv;
-	char *p = canonicalize_dir(pathname);
-	char *freep = p;
+	FILE *f;
 	int ret;
-	struct stat s;
-
-	ret = lstat(p, &s);
-	if (ret)
-		goto out;
 
-	if (S_ISDIR(s.st_mode)) {
-		ret = -EISDIR;
-		goto out;
-	}
+	if (check_fd(fd))
+		return -errno;
 
-	fsdev = get_fs_device_and_root_path(&p);
-	if (!fsdev) {
-		ret = -ENOENT;
-		goto out;
-	}
-	fsdrv = fsdev->driver;
+	f = &files[fd];
 
-	if (!fsdrv->unlink) {
-		ret = -ENOSYS;
-		goto out;
-	}
+	fsdrv = f->fsdev->driver;
+	if (fsdrv->flush)
+		ret = fsdrv->flush(&f->fsdev->dev, f);
+	else
+		ret = 0;
 
-	ret = fsdrv->unlink(&fsdev->dev, p);
-	if (ret)
-		errno = -ret;
-out:
-	free(freep);
 	if (ret)
 		errno = -ret;
+
 	return ret;
 }
-EXPORT_SYMBOL(unlink);
 
-int open(const char *pathname, int flags, ...)
+loff_t lseek(int fildes, loff_t offset, int whence)
 {
-	struct fs_device_d *fsdev;
 	struct fs_driver_d *fsdrv;
 	FILE *f;
-	int exist_err = 0;
-	struct stat s;
-	char *path;
-	char *freep;
+	loff_t pos;
 	int ret;
 
-	path = canonicalize_path(pathname);
-	if (IS_ERR(path)) {
-		ret = PTR_ERR(path);
-		goto out2;
-	}
-
-	exist_err = stat(path, &s);
-
-	freep = path;
-
-	if (!exist_err && S_ISDIR(s.st_mode)) {
-		ret = -EISDIR;
-		goto out1;
-	}
-
-	if (exist_err && !(flags & O_CREAT)) {
-		ret = exist_err;
-		goto out1;
-	}
-
-	if (exist_err) {
-		ret = parent_check_directory(path);
-		if (ret)
-			goto out1;
-	}
-
-	f = get_file();
-	if (!f) {
-		ret = -EMFILE;
-		goto out1;
-	}
+	if (check_fd(fildes))
+		return -1;
 
-	fsdev = get_fs_device_and_root_path(&path);
-	if (!fsdev) {
-		ret = -ENOENT;
+	f = &files[fildes];
+	fsdrv = f->fsdev->driver;
+	if (!fsdrv->lseek) {
+		ret = -ENOSYS;
 		goto out;
 	}
 
-	fsdrv = fsdev->driver;
-
-	f->fsdev = fsdev;
-	f->flags = flags;
-
-	if ((flags & O_ACCMODE) && !fsdrv->write) {
-		ret = -EROFS;
-		goto out;
-	}
+	ret = -EINVAL;
 
-	if (exist_err) {
-		if (NULL != fsdrv->create)
-			ret = fsdrv->create(&fsdev->dev, path,
-					S_IFREG | S_IRWXU | S_IRWXG | S_IRWXO);
-		else
-			ret = -EROFS;
-		if (ret)
+	switch (whence) {
+	case SEEK_SET:
+		if (f->size != FILE_SIZE_STREAM && offset > f->size)
 			goto out;
-	}
-
-	f->path = xstrdup(path);
-
-	ret = fsdrv->open(&fsdev->dev, f, path);
-	if (ret)
-		goto out;
-
-	if (flags & O_TRUNC) {
-		ret = fsdrv->truncate(&fsdev->dev, f, 0);
-		f->size = 0;
-		if (ret)
+		if (offset < 0)
+			goto out;
+		pos = offset;
+		break;
+	case SEEK_CUR:
+		if (f->size != FILE_SIZE_STREAM && offset + f->pos > f->size)
+			goto out;
+		pos = f->pos + offset;
+		break;
+	case SEEK_END:
+		if (offset > 0)
 			goto out;
+		pos = f->size + offset;
+		break;
+	default:
+		goto out;
 	}
 
-	if (flags & O_APPEND)
-		f->pos = f->size;
+	pos = fsdrv->lseek(&f->fsdev->dev, f, pos);
+	if (pos < 0) {
+		errno = -pos;
+		return -1;
+	}
 
-	free(freep);
-	return f->no;
+	return pos;
 
 out:
-	put_file(f);
-out1:
-	free(freep);
-out2:
 	if (ret)
 		errno = -ret;
-	return ret;
-}
-EXPORT_SYMBOL(open);
 
-int creat(const char *pathname, mode_t mode)
-{
-	return open(pathname, O_CREAT | O_WRONLY | O_TRUNC);
+	return -1;
 }
-EXPORT_SYMBOL(creat);
+EXPORT_SYMBOL(lseek);
 
-int ftruncate(int fd, loff_t length)
+int erase(int fd, loff_t count, loff_t offset)
 {
 	struct fs_driver_d *fsdrv;
 	FILE *f;
@@ -749,21 +466,28 @@ int ftruncate(int fd, loff_t length)
 
 	if (check_fd(fd))
 		return -errno;
-
 	f = &files[fd];
+	if (offset >= f->size)
+		return 0;
+	if (count == ERASE_SIZE_ALL || count > f->size - offset)
+		count = f->size - offset;
+	if (count < 0)
+		return -EINVAL;
 
 	fsdrv = f->fsdev->driver;
+	if (fsdrv->erase)
+		ret = fsdrv->erase(&f->fsdev->dev, f, count, offset);
+	else
+		ret = -ENOSYS;
 
-	ret = fsdrv->truncate(&f->fsdev->dev, f, length);
 	if (ret)
-		return ret;
-
-	f->size = length;
+		errno = -ret;
 
-	return 0;
+	return ret;
 }
+EXPORT_SYMBOL(erase);
 
-int ioctl(int fd, int request, void *buf)
+int protect(int fd, size_t count, loff_t offset, int prot)
 {
 	struct fs_driver_d *fsdrv;
 	FILE *f;
@@ -771,387 +495,1981 @@ int ioctl(int fd, int request, void *buf)
 
 	if (check_fd(fd))
 		return -errno;
-
 	f = &files[fd];
+	if (offset >= f->size)
+		return 0;
+	if (count > f->size - offset)
+		count = f->size - offset;
 
 	fsdrv = f->fsdev->driver;
-
-	if (fsdrv->ioctl)
-		ret = fsdrv->ioctl(&f->fsdev->dev, f, request, buf);
+	if (fsdrv->protect)
+		ret = fsdrv->protect(&f->fsdev->dev, f, count, offset, prot);
 	else
 		ret = -ENOSYS;
+
 	if (ret)
 		errno = -ret;
+
 	return ret;
 }
+EXPORT_SYMBOL(protect);
 
-static ssize_t __read(FILE *f, void *buf, size_t count)
+int protect_file(const char *file, int prot)
 {
-	struct fs_driver_d *fsdrv;
-	int ret;
-
-	if ((f->flags & O_ACCMODE) == O_WRONLY) {
-		ret = -EBADF;
-		goto out;
-	}
+	int fd, ret;
 
-	fsdrv = f->fsdev->driver;
+	fd = open(file, O_WRONLY);
+	if (fd < 0)
+		return fd;
 
-	if (f->size != FILE_SIZE_STREAM && f->pos + count > f->size)
-		count = f->size - f->pos;
+	ret = protect(fd, ~0, 0, prot);
 
-	if (!count)
-		return 0;
+	close(fd);
 
-	ret = fsdrv->read(&f->fsdev->dev, f, buf, count);
-out:
-	if (ret < 0)
-		errno = -ret;
 	return ret;
 }
 
-ssize_t pread(int fd, void *buf, size_t count, loff_t offset)
+void *memmap(int fd, int flags)
 {
-	loff_t pos;
+	struct fs_driver_d *fsdrv;
 	FILE *f;
+	void *retp = (void *)-1;
 	int ret;
 
 	if (check_fd(fd))
-		return -errno;
+		return retp;
 
 	f = &files[fd];
 
-	pos = f->pos;
-	f->pos = offset;
-	ret = __read(f, buf, count);
-	f->pos = pos;
+	fsdrv = f->fsdev->driver;
 
-	return ret;
+	if (fsdrv->memmap)
+		ret = fsdrv->memmap(&f->fsdev->dev, f, &retp, flags);
+	else
+		ret = -EINVAL;
+
+	if (ret)
+		errno = -ret;
+
+	return retp;
 }
-EXPORT_SYMBOL(pread);
+EXPORT_SYMBOL(memmap);
 
-ssize_t read(int fd, void *buf, size_t count)
+int close(int fd)
 {
+	struct fs_driver_d *fsdrv;
 	FILE *f;
-	int ret;
+	int ret = 0;
 
 	if (check_fd(fd))
 		return -errno;
 
 	f = &files[fd];
 
-	ret = __read(f, buf, count);
+	fsdrv = f->fsdev->driver;
+
+	if (fsdrv->close)
+		ret = fsdrv->close(&f->fsdev->dev, f);
+
+	put_file(f);
+
+	if (ret)
+		errno = -ret;
 
-	if (ret > 0)
-		f->pos += ret;
 	return ret;
 }
-EXPORT_SYMBOL(read);
+EXPORT_SYMBOL(close);
 
-static ssize_t __write(FILE *f, const void *buf, size_t count)
+static int fs_match(struct device_d *dev, struct driver_d *drv)
 {
-	struct fs_driver_d *fsdrv;
+	return strcmp(dev->name, drv->name) ? -1 : 0;
+}
+
+static int fs_probe(struct device_d *dev)
+{
+	struct fs_device_d *fsdev = dev_to_fs_device(dev);
+	struct driver_d *drv = dev->driver;
+	struct fs_driver_d *fsdrv = container_of(drv, struct fs_driver_d, drv);
 	int ret;
 
-	if (!(f->flags & O_ACCMODE)) {
-		ret = -EBADF;
-		goto out;
+	ret = dev->driver->probe(dev);
+	if (ret)
+		return ret;
+
+	fsdev->driver = fsdrv;
+
+	list_add_tail(&fsdev->list, &fs_device_list);
+
+	return 0;
+}
+
+void dentry_kill(struct dentry *dentry)
+{
+	if (dentry->d_inode)
+		iput(dentry->d_inode);
+
+	if (!IS_ROOT(dentry))
+		dput(dentry->d_parent);
+
+	list_del(&dentry->d_child);
+	free(dentry->name);
+	free(dentry);
+}
+
+int dentry_delete_subtree(struct super_block *sb, struct dentry *parent)
+{
+	struct dentry *dentry, *tmp;
+
+	if (!parent)
+		return 0;
+
+	list_for_each_entry_safe(dentry, tmp, &parent->d_subdirs, d_child)
+		dentry_delete_subtree(sb, dentry);
+
+	dentry_kill(parent);
+
+	return 0;
+}
+
+static void destroy_inode(struct inode *inode)
+{
+	if (inode->i_sb->s_op->destroy_inode)
+		inode->i_sb->s_op->destroy_inode(inode);
+	else
+		free(inode);
+}
+
+static void fs_remove(struct device_d *dev)
+{
+	struct fs_device_d *fsdev = dev_to_fs_device(dev);
+	struct super_block *sb = &fsdev->sb;
+	struct inode *inode, *tmp;
+
+	if (fsdev->dev.driver) {
+		dev->driver->remove(dev);
+		list_del(&fsdev->list);
 	}
 
-	fsdrv = f->fsdev->driver;
-	if (f->size != FILE_SIZE_STREAM && f->pos + count > f->size) {
-		ret = fsdrv->truncate(&f->fsdev->dev, f, f->pos + count);
-		if (ret) {
-			if (ret != -ENOSPC)
-				goto out;
-			count = f->size - f->pos;
-			if (!count)
-				goto out;
-		} else {
-			f->size = f->pos + count;
+	free(fsdev->path);
+	free(fsdev->options);
+
+	if (fsdev->cdev)
+		cdev_close(fsdev->cdev);
+
+	if (fsdev->loop)
+		cdev_remove_loop(fsdev->cdev);
+
+	dput(sb->s_root);
+	dentry_delete_subtree(sb, sb->s_root);
+
+	list_for_each_entry_safe(inode, tmp, &sb->s_inodes, i_sb_list)
+		destroy_inode(inode);
+
+	if (fsdev->vfsmount.mountpoint)
+		fsdev->vfsmount.mountpoint->d_flags &= ~DCACHE_MOUNTED;
+
+	mntput(fsdev->vfsmount.parent);
+
+	free(fsdev->backingstore);
+	free(fsdev);
+}
+
+struct bus_type fs_bus = {
+	.name = "fs",
+	.match = fs_match,
+	.probe = fs_probe,
+	.remove = fs_remove,
+};
+
+static int fs_bus_init(void)
+{
+	return bus_register(&fs_bus);
+}
+pure_initcall(fs_bus_init);
+
+int register_fs_driver(struct fs_driver_d *fsdrv)
+{
+	fsdrv->drv.bus = &fs_bus;
+	register_driver(&fsdrv->drv);
+
+	return 0;
+}
+EXPORT_SYMBOL(register_fs_driver);
+
+static const char *detect_fs(const char *filename, const char *fsoptions)
+{
+	enum filetype type;
+	struct driver_d *drv;
+	struct fs_driver_d *fdrv;
+	bool loop = false;
+	unsigned long long offset = 0;
+
+	parseopt_b(fsoptions, "loop", &loop);
+	parseopt_llu_suffix(fsoptions, "offset", &offset);
+	if (loop)
+		type = file_name_detect_type_offset(filename, offset);
+	else
+		type = cdev_detect_type(filename);
+
+	if (type == filetype_unknown)
+		return NULL;
+
+	bus_for_each_driver(&fs_bus, drv) {
+		fdrv = drv_to_fs_driver(drv);
+
+		if (type == fdrv->type)
+			return drv->name;
+	}
+
+	return NULL;
+}
+
+int fsdev_open_cdev(struct fs_device_d *fsdev)
+{
+	unsigned long long offset = 0;
+
+	parseopt_b(fsdev->options, "loop", &fsdev->loop);
+	parseopt_llu_suffix(fsdev->options, "offset", &offset);
+	if (fsdev->loop)
+		fsdev->cdev = cdev_create_loop(fsdev->backingstore, O_RDWR,
+					       offset);
+	else
+		fsdev->cdev = cdev_open(fsdev->backingstore, O_RDWR);
+	if (!fsdev->cdev)
+		return -EINVAL;
+
+	fsdev->dev.parent = fsdev->cdev->dev;
+	fsdev->parent_device = fsdev->cdev->dev;
+
+	return 0;
+}
+
+static void init_super(struct super_block *sb)
+{
+	INIT_LIST_HEAD(&sb->s_inodes);
+}
+
+static int fsdev_umount(struct fs_device_d *fsdev)
+{
+	if (fsdev->vfsmount.ref)
+		return -EBUSY;
+
+	return unregister_device(&fsdev->dev);
+}
+
+/**
+ * umount_by_cdev Use a cdev struct to umount all mounted filesystems
+ * @param cdev cdev to the according device
+ * @return 0 on success or if cdev was not mounted, -errno otherwise
+ */
+int umount_by_cdev(struct cdev *cdev)
+{
+	struct fs_device_d *fs;
+	struct fs_device_d *fs_tmp;
+	int first_error = 0;
+
+	for_each_fs_device_safe(fs_tmp, fs) {
+		int ret;
+
+		if (fs->cdev == cdev) {
+			ret = fsdev_umount(fs);
+			if (ret) {
+				pr_err("Failed umounting %s, %d, continuing anyway\n",
+				       fs->path, ret);
+				if (!first_error)
+					first_error = ret;
+			}
 		}
 	}
-	ret = fsdrv->write(&f->fsdev->dev, f, buf, count);
-out:
-	if (ret < 0)
-		errno = -ret;
-	return ret;
+
+	return first_error;
 }
+EXPORT_SYMBOL(umount_by_cdev);
 
-ssize_t pwrite(int fd, const void *buf, size_t count, loff_t offset)
+struct readdir_entry {
+	struct dirent d;
+	struct list_head list;
+};
+
+struct readdir_callback {
+	struct dir_context ctx;
+	DIR *dir;
+};
+
+static int fillonedir(struct dir_context *ctx, const char *name, int namlen,
+		      loff_t offset, u64 ino, unsigned int d_type)
 {
-	loff_t pos;
-	FILE *f;
-	int ret;
+	struct readdir_callback *rd = container_of(ctx, struct readdir_callback, ctx);
+	struct readdir_entry *entry;
 
-	if (check_fd(fd))
-		return -errno;
+	entry = xzalloc(sizeof(*entry));
+	if (!entry)
+		return -ENOMEM;
 
-	f = &files[fd];
+	memcpy(entry->d.d_name, name, namlen);
+	list_add_tail(&entry->list, &rd->dir->entries);
 
-	pos = f->pos;
-	f->pos = offset;
-	ret = __write(f, buf, count);
-	f->pos = pos;
+	return 0;
+}
 
-	return ret;
+struct dirent *readdir(DIR *dir)
+{
+	struct readdir_entry *entry;
+
+	if (!dir)
+		return NULL;
+
+	if (list_empty(&dir->entries))
+		return NULL;
+
+	entry = list_first_entry(&dir->entries, struct readdir_entry, list);
+
+	list_del(&entry->list);
+	strcpy(dir->d.d_name, entry->d.d_name);
+	free(entry);
+
+	return &dir->d;
 }
-EXPORT_SYMBOL(pwrite);
+EXPORT_SYMBOL(readdir);
 
-ssize_t write(int fd, const void *buf, size_t count)
+int fstat(int fd, struct stat *s)
 {
 	FILE *f;
-	int ret;
+	struct fs_device_d *fsdev;
 
 	if (check_fd(fd))
 		return -errno;
 
 	f = &files[fd];
 
-	ret = __write(f, buf, count);
+	fsdev = f->fsdev;
+
+	return -ENOENT;
+//	return fsdev->driver->stat(&fsdev->dev, f->path, s);
+}
+EXPORT_SYMBOL(fstat);
+
+/*
+ * cdev_get_mount_path - return the path a cdev is mounted on
+ *
+ * If a cdev is mounted return the path it's mounted on, NULL
+ * otherwise.
+ */
+const char *cdev_get_mount_path(struct cdev *cdev)
+{
+	struct fs_device_d *fsdev;
+
+	for_each_fs_device(fsdev) {
+		if (fsdev->cdev && fsdev->cdev == cdev)
+			return fsdev->path;
+	}
+
+	return NULL;
+}
+
+/*
+ * cdev_mount_default - mount a cdev to the default path
+ *
+ * If a cdev is already mounted return the path it's mounted on, otherwise
+ * mount it to /mnt/<cdevname> and return the path. Returns an error pointer
+ * on failure.
+ */
+const char *cdev_mount_default(struct cdev *cdev, const char *fsoptions)
+{
+	const char *path;
+	char *newpath, *devpath;
+	int ret;
+
+	/*
+	 * If this cdev is already mounted somewhere use this path
+	 * instead of mounting it again to avoid corruption on the
+	 * filesystem. Note this ignores eventual fsoptions though.
+	 */
+	path = cdev_get_mount_path(cdev);
+	if (path)
+		return path;
+
+	newpath = basprintf("/mnt/%s", cdev->name);
+	make_directory(newpath);
+
+	devpath = basprintf("/dev/%s", cdev->name);
+
+	ret = mount(devpath, NULL, newpath, fsoptions);
+
+	free(devpath);
+
+	if (ret) {
+		free(newpath);
+		return ERR_PTR(ret);
+	}
+
+	return cdev_get_mount_path(cdev);
+}
+
+/*
+ * mount_all - iterate over block devices and mount all devices we are able to
+ */
+void mount_all(void)
+{
+	struct device_d *dev;
+	struct block_device *bdev;
+
+	if (!IS_ENABLED(CONFIG_BLOCK))
+		return;
+
+	for_each_device(dev)
+		device_detect(dev);
+
+	for_each_block_device(bdev) {
+		struct cdev *cdev = &bdev->cdev;
+
+		list_for_each_entry(cdev, &bdev->dev->cdevs, devices_list)
+			cdev_mount_default(cdev, NULL);
+	}
+}
+
+void fsdev_set_linux_rootarg(struct fs_device_d *fsdev, const char *str)
+{
+	fsdev->linux_rootarg = xstrdup(str);
+
+	dev_add_param_fixed(&fsdev->dev, "linux.bootargs", fsdev->linux_rootarg);
+}
+
+/**
+ * path_get_linux_rootarg() - Given a path return a suitable root= option for
+ *                            Linux
+ * @path: The path
+ *
+ * Return: A string containing the root= option or an ERR_PTR. the returned
+ *         string must be freed by the caller.
+ */
+char *path_get_linux_rootarg(const char *path)
+{
+	struct fs_device_d *fsdev;
+	const char *str;
+
+	fsdev = get_fsdevice_by_path(path);
+	if (!fsdev)
+		return ERR_PTR(-EINVAL);
+
+	str = dev_get_param(&fsdev->dev, "linux.bootargs");
+	if (!str)
+		return ERR_PTR(-ENOSYS);
+
+	return xstrdup(str);
+}
+
+/**
+ * __is_tftp_fs() - return true when path is mounted on TFTP
+ * @path: The path
+ *
+ * Do not use directly, use is_tftp_fs instead.
+ *
+ * Return: true when @path is on TFTP, false otherwise
+ */
+bool __is_tftp_fs(const char *path)
+{
+	struct fs_device_d *fsdev;
+
+	fsdev = get_fsdevice_by_path(path);
+	if (!fsdev)
+		return false;
+
+	if (strcmp(fsdev->driver->drv.name, "tftp"))
+		return false;
+
+	return true;
+}
+
+/* inode.c */
+unsigned int get_next_ino(void)
+{
+	static unsigned int ino;
+
+	return ++ino;
+}
+
+void drop_nlink(struct inode *inode)
+{
+	WARN_ON(inode->i_nlink == 0);
+	inode->__i_nlink--;
+}
+
+void inc_nlink(struct inode *inode)
+{
+	inode->__i_nlink++;
+}
+
+static struct inode *alloc_inode(struct super_block *sb)
+{
+	static const struct inode_operations empty_iops;
+	static const struct file_operations no_open_fops;
+	struct inode *inode;
+
+	if (sb->s_op->alloc_inode)
+		inode = sb->s_op->alloc_inode(sb);
+	else
+		inode = xzalloc(sizeof(*inode));
+
+	inode->i_op = &empty_iops;
+	inode->i_fop = &no_open_fops;
+	inode->__i_nlink = 1;
+	inode->i_count = 1;
+
+	return inode;
+}
+
+struct inode *new_inode(struct super_block *sb)
+{
+	struct inode *inode;
+
+	inode = alloc_inode(sb);
+	if (!inode)
+		return NULL;
+
+	inode->i_sb = sb;
+
+	list_add(&inode->i_sb_list, &sb->s_inodes);
+
+	return inode;
+}
+
+void iput(struct inode *inode)
+{
+	if (!inode->i_count)
+		return;
+
+	inode->i_count--;
+}
+
+struct inode *iget(struct inode *inode)
+{
+	inode->i_count++;
+
+	return inode;
+}
+
+/* dcache.c */
+
+/*
+ * refcounting is implemented but right now we do not do anything with
+ * the refcounting information. Dentries are never freed unless the
+ * filesystem they are on is unmounted. In this case we do not care
+ * about the refcounts so we may free up a dentry that is actually used
+ * (file is opened). This leaves room for improvements.
+ */
+void dput(struct dentry *dentry)
+{
+	if (!dentry)
+		return;
+
+	if (!dentry->d_count)
+		return;
+
+	dentry->d_count--;
+}
+
+struct dentry *dget(struct dentry *dentry)
+{
+	dentry->d_count++;
+
+	return dentry;
+}
+
+const struct qstr slash_name = QSTR_INIT("/", 1);
+
+void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op)
+{
+	dentry->d_op = op;
+}
+
+/**
+ * __d_alloc	-	allocate a dcache entry
+ * @sb: filesystem it will belong to
+ * @name: qstr of the name
+ *
+ * Allocates a dentry. It returns %NULL if there is insufficient memory
+ * available. On a success the dentry is returned. The name passed in is
+ * copied and the copy passed in may be reused after this call.
+ */
+struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name)
+{
+	struct dentry *dentry;
+
+	dentry = xzalloc(sizeof(*dentry));
+	if (!dentry)
+		return NULL;
+
+	if (!name)
+		name = &slash_name;
+
+	dentry->name = malloc(name->len + 1);
+	if (!dentry->name)
+		return NULL;
+
+	memcpy(dentry->name, name->name, name->len);
+	dentry->name[name->len] = 0;
+
+	dentry->d_name.len = name->len;
+	dentry->d_name.name = dentry->name;
+
+	dentry->d_count = 1;
+	dentry->d_parent = dentry;
+	dentry->d_sb = sb;
+	INIT_LIST_HEAD(&dentry->d_subdirs);
+	INIT_LIST_HEAD(&dentry->d_child);
+	d_set_d_op(dentry, dentry->d_sb->s_d_op);
+
+	return dentry;
+}
+
+/**
+ * d_alloc	-	allocate a dcache entry
+ * @parent: parent of entry to allocate
+ * @name: qstr of the name
+ *
+ * Allocates a dentry. It returns %NULL if there is insufficient memory
+ * available. On a success the dentry is returned. The name passed in is
+ * copied and the copy passed in may be reused after this call.
+ */
+struct dentry *d_alloc(struct dentry *parent, const struct qstr *name)
+{
+	struct dentry *dentry = __d_alloc(parent->d_sb, name);
+	if (!dentry)
+		return NULL;
+
+	dget(parent);
+
+	dentry->d_parent = parent;
+	list_add(&dentry->d_child, &parent->d_subdirs);
+
+	return dentry;
+}
+
+struct dentry *d_alloc_anon(struct super_block *sb)
+{
+	return __d_alloc(sb, NULL);
+}
+
+static unsigned d_flags_for_inode(struct inode *inode)
+{
+        if (!inode)
+                return DCACHE_MISS_TYPE;
+
+	if (S_ISDIR(inode->i_mode))
+		return DCACHE_DIRECTORY_TYPE;
+
+	if (inode->i_op->get_link)
+		return DCACHE_SYMLINK_TYPE;
+
+	return DCACHE_REGULAR_TYPE;
+}
+
+void d_instantiate(struct dentry *dentry, struct inode *inode)
+{
+	dentry->d_inode = inode;
+	dentry->d_flags &= ~DCACHE_ENTRY_TYPE;
+	dentry->d_flags |= d_flags_for_inode(inode);
+}
+
+struct dentry *d_make_root(struct inode *inode)
+{
+	struct dentry *res;
+
+	if (!inode)
+		return NULL;
+
+	res = d_alloc_anon(inode->i_sb);
+	if (!res)
+		return NULL;
+
+	d_instantiate(res, inode);
+
+	return res;
+}
+
+void d_add(struct dentry *dentry, struct inode *inode)
+{
+	dentry->d_inode = inode;
+	dentry->d_flags &= ~DCACHE_ENTRY_TYPE;
+	dentry->d_flags |= d_flags_for_inode(inode);
+}
+
+static bool d_same_name(const struct dentry *dentry,
+			const struct dentry *parent,
+			const struct qstr *name)
+{
+	if (dentry->d_name.len != name->len)
+		return false;
+
+	return strncmp(dentry->d_name.name, name->name, name->len) == 0;
+}
+
+struct dentry *d_lookup(const struct dentry *parent, const struct qstr *name)
+{
+	struct dentry *dentry;
+
+	list_for_each_entry(dentry, &parent->d_subdirs, d_child) {
+		if (!d_same_name(dentry, parent, name))
+			continue;
+
+		dget(dentry);
+
+		return dentry;
+	}
+
+	return NULL;
+}
+
+void d_invalidate(struct dentry *dentry)
+{
+}
+
+static inline void __d_clear_type_and_inode(struct dentry *dentry)
+{
+	dentry->d_flags &= ~(DCACHE_ENTRY_TYPE | DCACHE_FALLTHRU);
+
+	dentry->d_inode = NULL;
+}
+
+/*
+ * Release the dentry's inode, using the filesystem
+ * d_iput() operation if defined.
+ */
+static void dentry_unlink_inode(struct dentry * dentry)
+{
+	struct inode *inode = dentry->d_inode;
+
+	__d_clear_type_and_inode(dentry);
+	iput(inode);
+}
+
+void d_delete(struct dentry * dentry)
+{
+	dentry_unlink_inode(dentry);
+}
+
+/*
+ * These are the Linux name resolve functions from fs/namei.c
+ *
+ * The implementation is more or less directly ported from the
+ * Linux Kernel (as of Linux-4.16) minus the RCU and locking code.
+ */
+
+enum {WALK_FOLLOW = 1, WALK_MORE = 2};
+
+/*
+ * Define EMBEDDED_LEVELS to MAXSYMLINKS so we do not have to
+ * dynamically allocate a path stack.
+ */
+#define EMBEDDED_LEVELS MAXSYMLINKS
+
+struct nameidata {
+	struct path	path;
+	struct qstr	last;
+	struct inode	*inode; /* path.dentry.d_inode */
+	unsigned int	flags;
+	unsigned	seq, m_seq;
+	int		last_type;
+	unsigned	depth;
+	int		total_link_count;
+	struct saved {
+		struct path link;
+		const char *name;
+		unsigned seq;
+	} *stack, internal[EMBEDDED_LEVELS];
+	struct filename	*name;
+	struct nameidata *saved;
+	struct inode	*link_inode;
+	unsigned	root_seq;
+	int		dfd;
+};
+
+struct filename {
+	char *name;
+	int refcnt;
+};
+
+static void set_nameidata(struct nameidata *p, int dfd, struct filename *name)
+{
+	p->stack = p->internal;
+	p->dfd = dfd;
+	p->name = name;
+	p->total_link_count = 0;
+}
+
+void path_get(const struct path *path)
+{
+	mntget(path->mnt);
+	dget(path->dentry);
+}
+
+void path_put(const struct path *path)
+{
+	dput(path->dentry);
+	mntput(path->mnt);
+}
+
+static inline void get_root(struct path *root)
+{
+	root->dentry = d_root;
+	root->mnt = mnt_root;
+
+	path_get(root);
+}
+
+static inline void get_pwd(struct path *pwd)
+{
+	if (!cwd_dentry) {
+		cwd_dentry = d_root;
+		cwd_mnt = mnt_root;
+	}
+
+	pwd->dentry = cwd_dentry;
+	pwd->mnt = cwd_mnt;
+
+	path_get(pwd);
+}
+
+static inline void put_link(struct nameidata *nd)
+{
+	struct saved *last = nd->stack + --nd->depth;
+	path_put(&last->link);
+}
+
+static int automount_mount(struct dentry *dentry);
+
+static void path_put_conditional(struct path *path, struct nameidata *nd)
+{
+	dput(path->dentry);
+	if (path->mnt != nd->path.mnt)
+		mntput(path->mnt);
+}
+
+static int follow_automount(struct path *path, struct nameidata *nd,
+			    bool *need_mntput)
+{
+	/* We don't want to mount if someone's just doing a stat -
+	 * unless they're stat'ing a directory and appended a '/' to
+	 * the name.
+	 *
+	 * We do, however, want to mount if someone wants to open or
+	 * create a file of any type under the mountpoint, wants to
+	 * traverse through the mountpoint or wants to open the
+	 * mounted directory.  Also, autofs may mark negative dentries
+	 * as being automount points.  These will need the attentions
+	 * of the daemon to instantiate them before they can be used.
+	 */
+	if (!(nd->flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY |
+			LOOKUP_OPEN | LOOKUP_CREATE | LOOKUP_AUTOMOUNT)) &&
+			path->dentry->d_inode)
+		return -EISDIR;
+
+	return automount_mount(path->dentry);
+}
+
+/*
+ * Handle a dentry that is managed in some way.
+ * - Flagged for transit management (autofs)
+ * - Flagged as mountpoint
+ * - Flagged as automount point
+ *
+ * This may only be called in refwalk mode.
+ *
+ * Serialization is taken care of in namespace.c
+ */
+static int follow_managed(struct path *path, struct nameidata *nd)
+{
+	struct vfsmount *mnt = path->mnt;
+	unsigned managed = path->dentry->d_flags;
+	bool need_mntput = false;
+	int ret = 0;
+
+	while (managed = path->dentry->d_flags,
+		managed &= DCACHE_MANAGED_DENTRY,
+		managed != 0) {
+
+		if (managed & DCACHE_MOUNTED) {
+			struct vfsmount *mounted = lookup_mnt(path);
+
+			if (mounted) {
+				dput(path->dentry);
+				if (need_mntput)
+					mntput(path->mnt);
+				path->mnt = mounted;
+				path->dentry = dget(mounted->mnt_root);
+				need_mntput = true;
+				continue;
+			}
+		}
+
+		/* Handle an automount point */
+		if (managed & DCACHE_NEED_AUTOMOUNT) {
+			ret = follow_automount(path, nd, &need_mntput);
+			if (ret < 0)
+				break;
+			continue;
+		}
+
+		/* We didn't change the current path point */
+		break;
+	}
+
+	if (need_mntput && path->mnt == mnt)
+		mntput(path->mnt);
+	if (ret == -EISDIR || !ret)
+		ret = 1;
+	if (need_mntput)
+		nd->flags |= LOOKUP_JUMPED;
+	if (ret < 0)
+		path_put_conditional(path, nd);
+	return ret;
+}
+
+static struct dentry *__lookup_hash(const struct qstr *name,
+		struct dentry *base, unsigned int flags)
+{
+	struct dentry *dentry;
+	struct dentry *old;
+	struct inode *dir = base->d_inode;
+
+	dentry = d_lookup(base, name);
+	if (dentry)
+		return dentry;
+
+	dentry = d_alloc(base, name);
+	if (unlikely(!dentry))
+		return ERR_PTR(-ENOMEM);
+
+	old = dir->i_op->lookup(dir, dentry, flags);
+	if (IS_ERR(old)) {
+		dput(dentry);
+		return old;
+	}
+
+	if (unlikely(old)) {
+		dput(dentry);
+		dentry = old;
+	}
+
+	return dentry;
+}
+
+static int lookup_fast(struct nameidata *nd, struct path *path)
+{
+	struct dentry *dentry, *parent = nd->path.dentry;
+
+	dentry = __lookup_hash(&nd->last, parent, 0);
+	if (IS_ERR(dentry))
+		return PTR_ERR(dentry);
+
+	if (d_is_negative(dentry)) {
+		dput(dentry);
+		return -ENOENT;
+	}
+
+	path->dentry = dentry;
+	path->mnt = nd->path.mnt;
+
+	return follow_managed(path, nd);
+}
+
+/*
+ * follow_up - Find the mountpoint of path's vfsmount
+ *
+ * Given a path, find the mountpoint of its source file system.
+ * Replace @path with the path of the mountpoint in the parent mount.
+ * Up is towards /.
+ *
+ * Return 1 if we went up a level and 0 if we were already at the
+ * root.
+ */
+int follow_up(struct path *path)
+{
+	struct vfsmount *parent, *mnt = path->mnt;
+	struct dentry *mountpoint;
+
+	parent = mnt->parent;
+	if (parent == mnt)
+		return 0;
+
+	mntget(parent);
+	mountpoint = dget(mnt->mountpoint);
+	dput(path->dentry);
+	path->dentry = mountpoint;
+	mntput(path->mnt);
+	path->mnt = mnt->parent;
+
+	return 1;
+}
+
+static void follow_mount(struct path *path)
+{
+	while (d_mountpoint(path->dentry)) {
+		struct vfsmount *mounted = lookup_mnt(path);
+		if (!mounted)
+			break;
+		dput(path->dentry);
+		path->mnt = mounted;
+		path->dentry = dget(mounted->mnt_root);
+	}
+}
+
+static int path_parent_directory(struct path *path)
+{
+	struct dentry *old = path->dentry;
+
+	path->dentry = dget(path->dentry->d_parent);
+	dput(old);
+
+	return 0;
+}
+
+static int follow_dotdot(struct nameidata *nd)
+{
+	while (1) {
+		if (nd->path.dentry != nd->path.mnt->mnt_root) {
+			int ret = path_parent_directory(&nd->path);
+			if (ret)
+				return ret;
+			break;
+		}
+
+		if (!follow_up(&nd->path))
+			break;
+	}
 
-	if (ret > 0)
-		f->pos += ret;
-	return ret;
+	follow_mount(&nd->path);
+
+	nd->inode = nd->path.dentry->d_inode;
+
+	return 0;
 }
-EXPORT_SYMBOL(write);
 
-int flush(int fd)
+static inline int handle_dots(struct nameidata *nd, int type)
+{
+	if (type == LAST_DOTDOT) {
+		return follow_dotdot(nd);
+	}
+	return 0;
+}
+
+static inline void path_to_nameidata(const struct path *path,
+					struct nameidata *nd)
+{
+	dput(nd->path.dentry);
+	if (nd->path.mnt != path->mnt)
+		mntput(nd->path.mnt);
+	nd->path.mnt = path->mnt;
+	nd->path.dentry = path->dentry;
+}
+
+static const char *get_link(struct nameidata *nd)
+{
+	struct saved *last = nd->stack + nd->depth - 1;
+	struct dentry *dentry = last->link.dentry;
+	struct inode *inode = nd->link_inode;
+	const char *res;
+
+	nd->last_type = LAST_BIND;
+	res = inode->i_link;
+	if (!res) {
+		res = inode->i_op->get_link(dentry, inode);
+		if (IS_ERR_OR_NULL(res))
+			return res;
+	}
+	if (*res == '/') {
+		while (unlikely(*++res == '/'))
+			;
+	}
+	if (!*res)
+		res = NULL;
+	return res;
+}
+
+static int pick_link(struct nameidata *nd, struct path *link,
+		     struct inode *inode)
+{
+	struct saved *last;
+
+	if (unlikely(nd->total_link_count++ >= MAXSYMLINKS)) {
+		path_to_nameidata(link, nd);
+		return -ELOOP;
+	}
+
+	if (link->mnt == nd->path.mnt)
+		mntget(link->mnt);
+
+	last = nd->stack + nd->depth++;
+	last->link = *link;
+	nd->link_inode = inode;
+
+	return 1;
+}
+
+/*
+ * Do we need to follow links? We _really_ want to be able
+ * to do this check without having to look at inode->i_op,
+ * so we keep a cache of "no, this doesn't need follow_link"
+ * for the common case.
+ */
+static inline int step_into(struct nameidata *nd, struct path *path,
+			    int flags, struct inode *inode)
+{
+	if (!(flags & WALK_MORE) && nd->depth)
+		put_link(nd);
+
+	if (likely(!d_is_symlink(path->dentry)) ||
+	   !(flags & WALK_FOLLOW || nd->flags & LOOKUP_FOLLOW)) {
+		/* not a symlink or should not follow */
+		path_to_nameidata(path, nd);
+		nd->inode = inode;
+		return 0;
+	}
+
+	return pick_link(nd, path, inode);
+}
+
+static int walk_component(struct nameidata *nd, int flags)
+{
+	struct path path;
+	int err;
+
+	/*
+	 * "." and ".." are special - ".." especially so because it has
+	 * to be able to know about the current root directory and
+	 * parent relationships.
+	 */
+	if (nd->last_type != LAST_NORM) {
+		err = handle_dots(nd, nd->last_type);
+		if (!(flags & WALK_MORE) && nd->depth)
+			put_link(nd);
+		return err;
+	}
+
+	err = lookup_fast(nd, &path);
+	if (err < 0)
+		return err;
+
+	if (err == 0) {
+		path.mnt = nd->path.mnt;
+		err = follow_managed(&path, nd);
+		if (err < 0)
+			return err;
+
+		if (d_is_negative(path.dentry)) {
+			path_to_nameidata(&path, nd);
+			return -ENOENT;
+		}
+	}
+
+	return step_into(nd, &path, flags, d_inode(path.dentry));
+}
+
+static int component_len(const char *name, char separator)
+{
+	int len = 0;
+
+	while (name[len] && name[len] != separator)
+		len++;
+
+	return len;
+}
+
+struct filename *getname(const char *filename)
+{
+	struct filename *result;
+
+	result = malloc(sizeof(*result));
+	if (!result)
+		return NULL;
+
+	result->name = strdup(filename);
+	if (!result->name) {
+		free(result);
+		return NULL;
+	}
+
+	result->refcnt = 1;
+
+	return result;
+}
+
+void putname(struct filename *name)
+{
+	BUG_ON(name->refcnt <= 0);
+
+	if (--name->refcnt > 0)
+		return;
+
+	free(name->name);
+	free(name);
+}
+
+static struct fs_device_d *get_fsdevice_by_dentry(struct dentry *dentry)
+{
+	struct super_block *sb;
+
+	sb = dentry->d_sb;
+
+	return container_of(sb, struct fs_device_d, sb);
+}
+
+static bool dentry_is_tftp(struct dentry *dentry)
+{
+	struct fs_device_d *fsdev;
+
+	fsdev = get_fsdevice_by_dentry(dentry);
+	if (!fsdev)
+		return false;
+
+	if (strcmp(fsdev->driver->drv.name, "tftp"))
+		return false;
+
+	return true;
+}
+
+/*
+ * Name resolution.
+ * This is the basic name resolution function, turning a pathname into
+ * the final dentry. We expect 'base' to be positive and a directory.
+ *
+ * Returns 0 and nd will have valid dentry and mnt on success.
+ * Returns error and drops reference to input namei data on failure.
+ */
+static int link_path_walk(const char *name, struct nameidata *nd)
+{
+	int err;
+	char separator = '/';
+
+	while (*name=='/')
+		name++;
+	if (!*name)
+		return 0;
+
+	/* At this point we know we have a real path component. */
+	for(;;) {
+		int len;
+		int type;
+
+		len = component_len(name, separator);
+
+		type = LAST_NORM;
+		if (name[0] == '.') switch (len) {
+			case 2:
+				if (name[1] == '.') {
+					type = LAST_DOTDOT;
+					nd->flags |= LOOKUP_JUMPED;
+				}
+				break;
+			case 1:
+				type = LAST_DOT;
+		}
+		if (likely(type == LAST_NORM))
+			nd->flags &= ~LOOKUP_JUMPED;
+
+		nd->last.len = len;
+		nd->last.name = name;
+		nd->last_type = type;
+
+		name += len;
+		if (!*name)
+			goto OK;
+
+		/*
+		 * If it wasn't NUL, we know it was '/'. Skip that
+		 * slash, and continue until no more slashes.
+		 */
+		do {
+			name++;
+		} while (unlikely(*name == separator));
+
+		if (unlikely(!*name)) {
+OK:
+			/* pathname body, done */
+			if (!nd->depth)
+				return 0;
+			name = nd->stack[nd->depth - 1].name;
+			/* trailing symlink, done */
+			if (!name)
+				return 0;
+			/* last component of nested symlink */
+			err = walk_component(nd, WALK_FOLLOW);
+		} else {
+			/* not the last component */
+			err = walk_component(nd, WALK_FOLLOW | WALK_MORE);
+		}
+
+		if (err < 0)
+			return err;
+
+		/*
+		 * barebox specific hack for TFTP. TFTP does not support
+		 * looking up directories, only the files in directories.
+		 * Since the filename is not known at this point we replace
+		 * the path separator with an invalid char so that TFTP will
+		 * get the full remaining path including slashes.
+		 */
+		if (dentry_is_tftp(nd->path.dentry))
+			separator = 0x1;
+
+		if (err) {
+			const char *s = get_link(nd);
+
+			if (IS_ERR(s))
+				return PTR_ERR(s);
+			err = 0;
+			if (unlikely(!s)) {
+				/* jumped */
+				put_link(nd);
+			} else {
+				nd->stack[nd->depth - 1].name = name;
+				name = s;
+				continue;
+			}
+		}
+		if (unlikely(!d_can_lookup(nd->path.dentry)))
+			return -ENOTDIR;
+	}
+}
+
+static const char *path_init(struct nameidata *nd, unsigned flags)
+{
+	const char *s = nd->name->name;
+
+	nd->last_type = LAST_ROOT; /* if there are only slashes... */
+	nd->flags = flags | LOOKUP_JUMPED | LOOKUP_PARENT;
+	nd->depth = 0;
+
+	nd->path.mnt = NULL;
+	nd->path.dentry = NULL;
+
+	if (*s == '/') {
+		get_root(&nd->path);
+		return s;
+	} else if (nd->dfd == AT_FDCWD) {
+		get_pwd(&nd->path);
+		nd->inode = nd->path.dentry->d_inode;
+		return s;
+	}
+
+	return s;
+}
+
+static const char *trailing_symlink(struct nameidata *nd)
+{
+	const char *s;
+
+	nd->flags |= LOOKUP_PARENT;
+	nd->stack[0].name = NULL;
+	s = get_link(nd);
+
+	return s ? s : "";
+}
+
+static inline int lookup_last(struct nameidata *nd)
+{
+	if (nd->last_type == LAST_NORM && nd->last.name[nd->last.len])
+		nd->flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
+
+	nd->flags &= ~LOOKUP_PARENT;
+	return walk_component(nd, 0);
+}
+
+static void terminate_walk(struct nameidata *nd)
+{
+	int i;
+
+	path_put(&nd->path);
+	for (i = 0; i < nd->depth; i++)
+		path_put(&nd->stack[i].link);
+
+	nd->depth = 0;
+}
+
+/* Returns 0 and nd will be valid on success; Retuns error, otherwise. */
+static int path_parentat(struct nameidata *nd, unsigned flags,
+				struct path *parent)
+{
+	const char *s = path_init(nd, flags);
+	int err;
+
+	if (IS_ERR(s))
+		return PTR_ERR(s);
+
+	err = link_path_walk(s, nd);
+	if (!err) {
+		*parent = nd->path;
+		nd->path.mnt = NULL;
+		nd->path.dentry = NULL;
+	}
+	terminate_walk(nd);
+	return err;
+}
+
+static struct filename *filename_parentat(int dfd, struct filename *name,
+				unsigned int flags, struct path *parent,
+				struct qstr *last, int *type)
+{
+	int retval;
+	struct nameidata nd;
+
+	if (IS_ERR(name))
+		return name;
+
+	set_nameidata(&nd, dfd, name);
+
+	retval = path_parentat(&nd, flags, parent);
+	if (likely(!retval)) {
+		*last = nd.last;
+		*type = nd.last_type;
+	} else {
+		putname(name);
+		name = ERR_PTR(retval);
+	}
+
+	return name;
+}
+
+static struct dentry *filename_create(int dfd, struct filename *name,
+				struct path *path, unsigned int lookup_flags)
+{
+	struct dentry *dentry = ERR_PTR(-EEXIST);
+	struct qstr last;
+	int type;
+	int error;
+	bool is_dir = (lookup_flags & LOOKUP_DIRECTORY);
+
+	/*
+	 * Note that only LOOKUP_REVAL and LOOKUP_DIRECTORY matter here. Any
+	 * other flags passed in are ignored!
+	 */
+	lookup_flags &= LOOKUP_REVAL;
+
+	name = filename_parentat(dfd, name, 0, path, &last, &type);
+	if (IS_ERR(name))
+		return ERR_CAST(name);
+
+	/*
+	 * Yucky last component or no last component at all?
+	 * (foo/., foo/.., /////)
+	 */
+	if (unlikely(type != LAST_NORM))
+		goto out;
+
+	/*
+	 * Do the final lookup.
+	 */
+	lookup_flags |= LOOKUP_CREATE | LOOKUP_EXCL;
+	dentry = __lookup_hash(&last, path->dentry, lookup_flags);
+	if (IS_ERR(dentry))
+		goto unlock;
+
+	error = -EEXIST;
+	if (d_is_positive(dentry))
+		goto fail;
+
+	/*
+	 * Special case - lookup gave negative, but... we had foo/bar/
+	 * From the vfs_mknod() POV we just have a negative dentry -
+	 * all is fine. Let's be bastards - you had / on the end, you've
+	 * been asking for (non-existent) directory. -ENOENT for you.
+	 */
+	if (unlikely(!is_dir && last.name[last.len])) {
+		error = -ENOENT;
+		goto fail;
+	}
+	putname(name);
+	return dentry;
+fail:
+	dput(dentry);
+	dentry = ERR_PTR(error);
+unlock:
+out:
+	path_put(path);
+	putname(name);
+	return dentry;
+}
+
+static int filename_lookup(int dfd, struct filename *name, unsigned flags,
+			   struct path *path)
+{
+	int err;
+	struct nameidata nd;
+	const char *s;
+
+	set_nameidata(&nd, dfd, name);
+
+	s = path_init(&nd, flags);
+
+	while (!(err = link_path_walk(s, &nd)) && ((err = lookup_last(&nd)) > 0)) {
+		s = trailing_symlink(&nd);
+		if (IS_ERR(s)) {
+			err = PTR_ERR(s);
+			break;
+		}
+	}
+
+	if (!err && nd.flags & LOOKUP_DIRECTORY)
+		if (!d_can_lookup(nd.path.dentry))
+			err = -ENOTDIR;
+	if (!err) {
+		*path = nd.path;
+		nd.path.mnt = NULL;
+		nd.path.dentry = NULL;
+	}
+
+	terminate_walk(&nd);
+	putname(name);
+
+	return err;
+}
+
+static struct fs_device_d *get_fsdevice_by_path(const char *pathname)
+{
+	struct fs_device_d *fsdev;
+	struct path path;
+	int ret;
+
+	ret = filename_lookup(AT_FDCWD, getname(pathname), 0, &path);
+	if (ret)
+		return NULL;
+
+	fsdev = get_fsdevice_by_dentry(path.dentry);
+
+	path_put(&path);
+
+	return fsdev;
+}
+
+int vfs_rmdir(struct inode *dir, struct dentry *dentry)
+{
+	int error;
+
+	if (!dir->i_op->rmdir)
+		return -EPERM;
+
+	dget(dentry);
+
+	error = dir->i_op->rmdir(dir, dentry);
+	if (error)
+		goto out;
+
+	dentry->d_inode->i_flags |= S_DEAD;
+
+out:
+	dput(dentry);
+
+	if (!error)
+		d_delete(dentry);
+
+	return error;
+}
+
+int vfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
+{
+	int error;
+
+	if (!dir->i_op->mkdir)
+		return -EPERM;
+
+	mode &= (S_IRWXUGO|S_ISVTX);
+
+	error = dir->i_op->mkdir(dir, dentry, mode);
+
+	return error;
+}
+
+/* libfs.c */
+
+/* ---------------------------------------------------------------- */
+int mkdir (const char *pathname, mode_t mode)
+{
+	struct dentry *dentry;
+	struct path path;
+	int error;
+	unsigned int lookup_flags = LOOKUP_DIRECTORY;
+
+	dentry = filename_create(AT_FDCWD, getname(pathname), &path, lookup_flags);
+	if (IS_ERR(dentry)) {
+		error = PTR_ERR(dentry);
+		goto out;
+	}
+
+	error = vfs_mkdir(path.dentry->d_inode, dentry, mode);
+
+	dput(dentry);
+	path_put(&path);
+out:
+	if (error)
+		errno = -error;
+
+	return error;
+}
+EXPORT_SYMBOL(mkdir);
+
+int rmdir (const char *pathname)
+{
+	int error = 0;
+	struct filename *name;
+	struct dentry *dentry;
+	struct path path;
+	struct qstr last;
+	int type;
+
+	name = filename_parentat(AT_FDCWD, getname(pathname), 0,
+				&path, &last, &type);
+	if (IS_ERR(name))
+		return PTR_ERR(name);
+
+	switch (type) {
+	case LAST_DOTDOT:
+		error = -ENOTEMPTY;
+		goto out;
+	case LAST_DOT:
+		error = -EINVAL;
+		goto out;
+	case LAST_ROOT:
+		error = -EBUSY;
+		goto out;
+	}
+
+	dentry = __lookup_hash(&last, path.dentry, 0);
+	if (d_is_negative(dentry)) {
+		error = -ENOENT;
+		goto out;
+	}
+	if (d_mountpoint(dentry)) {
+		error = -EBUSY;
+		goto out;
+	}
+
+	if (!d_is_dir(dentry)) {
+		error = -ENOTDIR;
+		goto out;
+	}
+
+	error = vfs_rmdir(path.dentry->d_inode, dentry);
+
+	dput(dentry);
+out:
+	path_put(&path);
+	putname(name);
+
+	if (error)
+		errno = -error;
+
+	return error;
+}
+EXPORT_SYMBOL(rmdir);
+
+int open(const char *pathname, int flags, ...)
 {
+	struct fs_device_d *fsdev;
 	struct fs_driver_d *fsdrv;
+	struct super_block *sb;
 	FILE *f;
-	int ret;
+	int error = 0;
+	struct inode *inode = NULL;
+	struct dentry *dentry = NULL;
+	struct nameidata nd;
+	const char *s;
 
-	if (check_fd(fd))
-		return -errno;
+	set_nameidata(&nd, AT_FDCWD, getname(pathname));
+	s = path_init(&nd, LOOKUP_FOLLOW);
 
-	f = &files[fd];
+	while (1) {
+		error = link_path_walk(s, &nd);
 
-	fsdrv = f->fsdev->driver;
-	if (fsdrv->flush)
-		ret = fsdrv->flush(&f->fsdev->dev, f);
-	else
-		ret = 0;
+		if (!d_is_dir(nd.path.dentry)) {
+			error = -ENOTDIR;
+			break;
+		}
 
-	if (ret)
-		errno = -ret;
+		dentry = __lookup_hash(&nd.last, nd.path.dentry, 0);
+		if (IS_ERR(dentry)) {
+			error = PTR_ERR(dentry);
+			break;
+		}
 
-	return ret;
-}
+		if (!d_is_symlink(dentry))
+			break;
 
-loff_t lseek(int fildes, loff_t offset, int whence)
-{
-	struct fs_driver_d *fsdrv;
-	FILE *f;
-	loff_t pos;
-	int ret;
+		dput(dentry);
 
-	if (check_fd(fildes))
-		return -1;
+		error = lookup_last(&nd);
+		if (error <= 0)
+			break;
 
-	f = &files[fildes];
-	fsdrv = f->fsdev->driver;
-	if (!fsdrv->lseek) {
-		ret = -ENOSYS;
-		goto out;
+		s = trailing_symlink(&nd);
+		if (IS_ERR(s)) {
+			error = PTR_ERR(s);
+			break;
+		}
 	}
 
-	ret = -EINVAL;
+	terminate_walk(&nd);
+	putname(nd.name);
 
-	switch (whence) {
-	case SEEK_SET:
-		if (f->size != FILE_SIZE_STREAM && offset > f->size)
-			goto out;
-		if (offset < 0)
-			goto out;
-		pos = offset;
-		break;
-	case SEEK_CUR:
-		if (f->size != FILE_SIZE_STREAM && offset + f->pos > f->size)
-			goto out;
-		pos = f->pos + offset;
-		break;
-	case SEEK_END:
-		if (offset > 0)
+	if (error)
+		return error;
+
+	if (d_is_negative(dentry)) {
+		if (flags & O_CREAT) {
+			error = create(nd.path.dentry, dentry);
+			if (error)
+				goto out1;
+		} else {
+			dput(dentry);
+			error = -ENOENT;
+			goto out1;
+		}
+	} else {
+		if (d_is_dir(dentry) && !dentry_is_tftp(dentry)) {
+			error = -EISDIR;
+			goto out1;
+		}
+	}
+
+	inode = d_inode(dentry);
+
+	f = get_file();
+	if (!f) {
+		error = -EMFILE;
+		goto out1;
+	}
+
+	f->path = xstrdup(pathname);
+	f->dentry = dentry;
+	f->f_inode = iget(inode);
+	f->flags = flags;
+	f->size = inode->i_size;
+
+	sb = inode->i_sb;
+	fsdev = container_of(sb, struct fs_device_d, sb);
+	fsdrv = fsdev->driver;
+
+	f->fsdev = fsdev;
+
+	if (fsdrv->open) {
+		error = fsdrv->open(&fsdev->dev, f, NULL);
+		if (error)
 			goto out;
-		pos = f->size + offset;
-		break;
-	default:
-		goto out;
 	}
 
-	pos = fsdrv->lseek(&f->fsdev->dev, f, pos);
-	if (pos < 0) {
-		errno = -pos;
-		return -1;
+	if (flags & O_TRUNC) {
+		error = fsdrv->truncate(&fsdev->dev, f, 0);
+		f->size = 0;
+		inode->i_size = 0;
+		if (error)
+			goto out;
 	}
 
-	return pos;
+	if (flags & O_APPEND)
+		f->pos = f->size;
+
+	return f->no;
 
 out:
-	if (ret)
-		errno = -ret;
+	put_file(f);
+out1:
 
-	return -1;
+	if (error)
+		errno = -error;
+	return error;
 }
-EXPORT_SYMBOL(lseek);
+EXPORT_SYMBOL(open);
 
-int erase(int fd, loff_t count, loff_t offset)
+int unlink(const char *pathname)
 {
-	struct fs_driver_d *fsdrv;
-	FILE *f;
 	int ret;
+	struct dentry *dentry;
+	struct inode *inode;
+	struct path path;
 
-	if (check_fd(fd))
-		return -errno;
-	f = &files[fd];
-	if (offset >= f->size)
-		return 0;
-	if (count == ERASE_SIZE_ALL || count > f->size - offset)
-		count = f->size - offset;
-	if (count < 0)
-		return -EINVAL;
+	ret = filename_lookup(AT_FDCWD, getname(pathname), 0, &path);
+	if (ret)
+		goto out;
 
-	fsdrv = f->fsdev->driver;
-	if (fsdrv->erase)
-		ret = fsdrv->erase(&f->fsdev->dev, f, count, offset);
-	else
-		ret = -ENOSYS;
+	dentry = path.dentry;
 
-	if (ret)
-		errno = -ret;
+	if (d_is_dir(dentry)) {
+		ret = -EISDIR;
+		goto out_put;
+	}
 
-	return ret;
-}
-EXPORT_SYMBOL(erase);
+	inode = d_inode(dentry->d_parent);
 
-int protect(int fd, size_t count, loff_t offset, int prot)
-{
-	struct fs_driver_d *fsdrv;
-	FILE *f;
-	int ret;
+	if (!inode->i_op->unlink) {
+		ret = -EPERM;
+		goto out_put;
+	}
 
-	if (check_fd(fd))
-		return -errno;
-	f = &files[fd];
-	if (offset >= f->size)
-		return 0;
-	if (count > f->size - offset)
-		count = f->size - offset;
+	ret = inode->i_op->unlink(inode, dentry);
+	if (ret)
+		goto out_put;
 
-	fsdrv = f->fsdev->driver;
-	if (fsdrv->protect)
-		ret = fsdrv->protect(&f->fsdev->dev, f, count, offset, prot);
-	else
-		ret = -ENOSYS;
+	d_delete(dentry);
 
+out_put:
+	path_put(&path);
+out:
 	if (ret)
 		errno = -ret;
-
 	return ret;
 }
-EXPORT_SYMBOL(protect);
+EXPORT_SYMBOL(unlink);
 
-int protect_file(const char *file, int prot)
+int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname)
 {
-	int fd, ret;
+	if (!dir->i_op->symlink)
+		return -EPERM;
 
-	fd = open(file, O_WRONLY);
-	if (fd < 0)
-		return fd;
+	return dir->i_op->symlink(dir, dentry, oldname);
+}
 
-	ret = protect(fd, ~0, 0, prot);
+int symlink(const char *pathname, const char *newpath)
+{
+	struct dentry *dentry;
+	struct path path;
+	int error;
+	unsigned int lookup_flags = LOOKUP_DIRECTORY;
 
-	close(fd);
+	dentry = filename_create(AT_FDCWD, getname(newpath), &path, lookup_flags);
+	if (IS_ERR(dentry)) {
+		error = PTR_ERR(dentry);
+		goto out;
+	}
 
-	return ret;
+	error = vfs_symlink(path.dentry->d_inode, dentry, pathname);
+out:
+	if (error)
+		errno = -error;
+
+	return error;
 }
+EXPORT_SYMBOL(symlink);
 
-void *memmap(int fd, int flags)
+static void release_dir(DIR *d)
+{
+	struct readdir_entry *entry, *tmp;
+
+	list_for_each_entry_safe(entry, tmp, &d->entries, list) {
+		free(entry);
+	}
+
+	free(d);
+}
+
+DIR *opendir(const char *pathname)
 {
-	struct fs_driver_d *fsdrv;
-	FILE *f;
-	void *retp = (void *)-1;
 	int ret;
+	struct dentry *dir;
+	struct inode *inode;
+	struct file file = {};
+	DIR *d;
+	struct path path = {};
+	struct readdir_callback rd = {
+		.ctx = {
+			.actor = fillonedir,
+		},
+	};
+
+	ret = filename_lookup(AT_FDCWD, getname(pathname),
+			      LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path);
+	if (ret)
+		goto out;
 
-	if (check_fd(fd))
-		return retp;
+	dir = path.dentry;
 
-	f = &files[fd];
+	if (d_is_negative(dir)) {
+		ret = -ENOENT;
+		goto out_put;
+	}
 
-	fsdrv = f->fsdev->driver;
+	inode = d_inode(dir);
 
-	if (fsdrv->memmap)
-		ret = fsdrv->memmap(&f->fsdev->dev, f, &retp, flags);
-	else
-		ret = -EINVAL;
+	if (!S_ISDIR(inode->i_mode)) {
+		ret = -ENOTDIR;
+		goto out_put;
+	}
+
+	file.f_path.dentry = dir;
+	file.f_op = dir->d_inode->i_fop;
 
+	d = xzalloc(sizeof(*d));
+
+	INIT_LIST_HEAD(&d->entries);
+	rd.dir = d;
+
+	ret = file.f_op->iterate(&file, &rd.ctx);
 	if (ret)
-		errno = -ret;
+		goto out_release;
 
-	return retp;
-}
-EXPORT_SYMBOL(memmap);
+	path_put(&path);
 
-int close(int fd)
-{
-	struct fs_driver_d *fsdrv;
-	FILE *f;
-	int ret;
+	return d;
 
-	if (check_fd(fd))
-		return -errno;
+out_release:
+	release_dir(d);
+out_put:
+	path_put(&path);
+out:
+	errno = -ret;
 
-	f = &files[fd];
+	return NULL;
+}
+EXPORT_SYMBOL(opendir);
 
-	fsdrv = f->fsdev->driver;
-	ret = fsdrv->close(&f->fsdev->dev, f);
+int closedir(DIR *dir)
+{
+	int ret;
 
-	put_file(f);
+	if (!dir) {
+		errno = EBADF;
+		return -EBADF;
+	}
 
-	if (ret)
-		errno = -ret;
+	release_dir(dir);
 
 	return ret;
 }
-EXPORT_SYMBOL(close);
+EXPORT_SYMBOL(closedir);
 
 int readlink(const char *pathname, char *buf, size_t bufsiz)
 {
-	struct fs_driver_d *fsdrv;
-	struct fs_device_d *fsdev;
-	char *p = canonicalize_dir(pathname);
-	char *freep = p;
 	int ret;
-	struct stat s;
+	struct dentry *dentry;
+	struct inode *inode;
+	const char *link;
+	struct path path = {};
 
-	ret = lstat(pathname, &s);
+	ret = filename_lookup(AT_FDCWD, getname(pathname), 0, &path);
 	if (ret)
 		goto out;
 
-	if (!S_ISLNK(s.st_mode)) {
+	dentry = path.dentry;
+
+	if (!d_is_symlink(dentry)) {
 		ret = -EINVAL;
-		goto out;
+		goto out_put;
 	}
 
-	fsdev = get_fs_device_and_root_path(&p);
-	if (!fsdev) {
-		ret = -ENODEV;
-		goto out;
+	inode = d_inode(dentry);
+
+	if (!inode->i_op->get_link) {
+		ret = -EPERM;
+		goto out_put;
 	}
-	fsdrv = fsdev->driver;
 
-	if (fsdrv->readlink)
-		ret = fsdrv->readlink(&fsdev->dev, p, buf, bufsiz);
-	else
-		ret = -ENOSYS;
+	link = inode->i_op->get_link(dentry, inode);
 
-	if (ret)
-		goto out;
+	strncpy(buf, link, bufsiz);
 
+	ret = 0;
+out_put:
+	path_put(&path);
 out:
-	free(freep);
-
 	if (ret)
 		errno = -ret;
 
@@ -1159,225 +2477,224 @@ out:
 }
 EXPORT_SYMBOL(readlink);
 
-int symlink(const char *pathname, const char *newpath)
+static int __stat(const char *filename, struct stat *s, unsigned int flags)
 {
-	struct fs_driver_d *fsdrv;
-	struct fs_device_d *fsdev;
-	char *p;
 	int ret;
-	struct stat s;
+	struct dentry *dentry;
+	struct inode *inode;
+	struct path path = {};
 
-	p = canonicalize_path(newpath);
-	if (IS_ERR(p)) {
-		ret = PTR_ERR(p);
+	ret = filename_lookup(AT_FDCWD, getname(filename), flags, &path);
+	if (ret)
 		goto out;
-	}
 
-	ret = lstat(p, &s);
-	if (!ret) {
-		ret = -EEXIST;
-		goto out;
-	}
+	dentry = path.dentry;
 
-	fsdev = get_fs_device_and_root_path(&p);
-	if (!fsdev) {
-		ret = -ENODEV;
-		goto out;
+	if (d_is_negative(dentry)) {
+		ret = -ENOENT;
+		goto out_put;
 	}
-	fsdrv = fsdev->driver;
 
-	if (fsdrv->symlink) {
-		ret = fsdrv->symlink(&fsdev->dev, pathname, p);
-	} else {
-		ret = -EPERM;
-	}
+	inode = d_inode(dentry);
 
-out:
-	free(p);
-	if (ret)
-		errno = -ret;
+	s->st_dev = 0;
+	s->st_ino = inode->i_ino;
+	s->st_mode = inode->i_mode;
+	s->st_uid = inode->i_uid;
+	s->st_gid = inode->i_gid;
+	s->st_size = inode->i_size;
 
+	ret = 0;
+out_put:
+	path_put(&path);
+out:
 	return ret;
 }
-EXPORT_SYMBOL(symlink);
 
-static int fs_match(struct device_d *dev, struct driver_d *drv)
+int stat(const char *filename, struct stat *s)
+{
+	return __stat(filename, s, LOOKUP_FOLLOW);
+}
+EXPORT_SYMBOL(stat);
+
+int lstat(const char *filename, struct stat *s)
 {
-	return strcmp(dev->name, drv->name) ? -1 : 0;
+	return __stat(filename, s, 0);
 }
+EXPORT_SYMBOL(lstat);
 
-static int fs_probe(struct device_d *dev)
+static char *__dpath(struct dentry *dentry, struct dentry *root)
 {
-	struct fs_device_d *fsdev = dev_to_fs_device(dev);
-	struct driver_d *drv = dev->driver;
-	struct fs_driver_d *fsdrv = container_of(drv, struct fs_driver_d, drv);
-	int ret;
+	char *res, *ppath;
 
-	ret = dev->driver->probe(dev);
-	if (ret)
-		return ret;
+	if (dentry == root)
+		return NULL;
+	if (dentry == d_root)
+		return NULL;
 
-	fsdev->driver = fsdrv;
+	while (IS_ROOT(dentry)) {
+		struct fs_device_d *fsdev;
 
-	list_add_tail(&fsdev->list, &fs_device_list);
+		for_each_fs_device(fsdev) {
+			if (dentry == fsdev->vfsmount.mnt_root) {
+				dentry = fsdev->vfsmount.mountpoint;
+				break;
+			}
+		}
+	}
 
-	if (!fs_dev_root)
-		fs_dev_root = fsdev;
+	ppath = __dpath(dentry->d_parent, root);
+	if (ppath)
+		res = basprintf("%s/%s", ppath, dentry->name);
+	else
+		res = basprintf("/%s", dentry->name);
+	free(ppath);
 
-	return 0;
+	return res;
 }
 
-static void fs_remove(struct device_d *dev)
+/** dpath - return path of a dentry
+ * @dentry: The dentry to return the path from
+ * @root:   The dentry up to which the path is followed
+ *
+ * Get the path of a dentry. The path is followed up to
+ * @root or the root ("/") dentry, whatever is found first.
+ *
+ * Return: Dynamically allocated string containing the path
+ */
+char *dpath(struct dentry *dentry, struct dentry *root)
 {
-	struct fs_device_d *fsdev = dev_to_fs_device(dev);
-
-	if (fsdev->dev.driver) {
-		dev->driver->remove(dev);
-		list_del(&fsdev->list);
-	}
+	char *res;
 
-	free(fsdev->path);
-	free(fsdev->options);
+	if (dentry == root && dentry == d_root)
+		return strdup("/");
 
-	if (fsdev == fs_dev_root)
-		fs_dev_root = NULL;
+	res = __dpath(dentry, root);
 
-	if (fsdev->cdev)
-		cdev_close(fsdev->cdev);
+	return res;
+}
 
-	if (fsdev->loop)
-		cdev_remove_loop(fsdev->cdev);
+/**
+ * canonicalize_path - resolve links in path
+ * @pathname: The input path
+ *
+ * This function resolves all links in @pathname and returns
+ * a path without links in it.
+ *
+ * Return: Path with links resolved. Allocated, must be freed after use.
+ */
+char *canonicalize_path(const char *pathname)
+{
+	char *res = NULL;
+	struct path path;
+	int ret;
 
-	free(fsdev->backingstore);
-	free(fsdev);
-}
+	ret = filename_lookup(AT_FDCWD, getname(pathname), LOOKUP_FOLLOW, &path);
+	if (ret)
+		goto out;
 
-struct bus_type fs_bus = {
-	.name = "fs",
-	.match = fs_match,
-	.probe = fs_probe,
-	.remove = fs_remove,
-};
+	res = dpath(path.dentry, d_root);
+out:
+	if (ret)
+		errno = -ret;
 
-static int fs_bus_init(void)
-{
-	return bus_register(&fs_bus);
+	return res;
 }
-pure_initcall(fs_bus_init);
 
-int register_fs_driver(struct fs_driver_d *fsdrv)
+const char *getcwd(void)
 {
-	fsdrv->drv.bus = &fs_bus;
-	register_driver(&fsdrv->drv);
-
-	return 0;
+	return cwd;
 }
-EXPORT_SYMBOL(register_fs_driver);
+EXPORT_SYMBOL(getcwd);
 
-static const char *detect_fs(const char *filename, const char *fsoptions)
+int chdir(const char *pathname)
 {
-	enum filetype type;
-	struct driver_d *drv;
-	struct fs_driver_d *fdrv;
-	bool loop = false;
-	unsigned long long offset = 0;
-
-	parseopt_b(fsoptions, "loop", &loop);
-	parseopt_llu_suffix(fsoptions, "offset", &offset);
-	if (loop)
-		type = file_name_detect_type_offset(filename, offset);
-	else
-		type = cdev_detect_type(filename);
-
-	if (type == filetype_unknown)
-		return NULL;
+	char *realpath;
+	struct path path;
+	int ret;
 
-	bus_for_each_driver(&fs_bus, drv) {
-		fdrv = drv_to_fs_driver(drv);
+	ret = filename_lookup(AT_FDCWD, getname(pathname), LOOKUP_FOLLOW, &path);
+	if (ret)
+		goto out;
 
-		if (type == fdrv->type)
-			return drv->name;
+	if (!d_is_dir(path.dentry)) {
+		ret = -ENOTDIR;
+		goto out;
 	}
 
-	return NULL;
-}
-
-int fsdev_open_cdev(struct fs_device_d *fsdev)
-{
-	unsigned long long offset = 0;
+	realpath = dpath(path.dentry, d_root);
+	strcpy(cwd, realpath);
+	free(realpath);
+	cwd_dentry = path.dentry;
+	cwd_mnt = path.mnt;
 
-	parseopt_b(fsdev->options, "loop", &fsdev->loop);
-	parseopt_llu_suffix(fsdev->options, "offset", &offset);
-	if (fsdev->loop)
-		fsdev->cdev = cdev_create_loop(fsdev->backingstore, O_RDWR,
-					       offset);
-	else
-		fsdev->cdev = cdev_open(fsdev->backingstore, O_RDWR);
-	if (!fsdev->cdev)
-		return -EINVAL;
+	ret = 0;
 
-	fsdev->dev.parent = fsdev->cdev->dev;
-	fsdev->parent_device = fsdev->cdev->dev;
+out:
+	if (ret)
+		errno = -ret;
 
-	return 0;
+	return ret;
 }
+EXPORT_SYMBOL(chdir);
 
 /*
  * Mount a device to a directory.
  * We do this by registering a new device on which the filesystem
  * driver will match.
  */
-int mount(const char *device, const char *fsname, const char *_path,
+int mount(const char *device, const char *fsname, const char *pathname,
 		const char *fsoptions)
 {
 	struct fs_device_d *fsdev;
 	int ret;
-	char *path = normalise_path(_path);
-
-	if (!fsoptions)
-		fsoptions = "";
+	struct path path = {};
 
-	debug("mount: %s on %s type %s, options=%s\n",
-			device, path, fsname, fsoptions);
+	if (d_root) {
+		ret = filename_lookup(AT_FDCWD, getname(pathname), LOOKUP_FOLLOW, &path);
+		if (ret)
+			goto out;
 
-	if (fs_dev_root) {
-		struct stat s;
+		if (!d_is_dir(path.dentry)) {
+			ret = -ENOTDIR;
+			goto out;
+		}
 
-		fsdev = get_fsdevice_by_path(path);
-		if (fsdev != fs_dev_root) {
-			printf("sorry, no nested mounts\n");
+		if (IS_ROOT(path.dentry) || d_mountpoint(path.dentry)) {
 			ret = -EBUSY;
-			goto err_free_path;
-		}
-		ret = lstat(path, &s);
-		if (ret)
-			goto err_free_path;
-		if (!S_ISDIR(s.st_mode)) {
-			ret = -ENOTDIR;
-			goto err_free_path;
+			goto out;
 		}
 	} else {
-		/* no mtab, so we only allow to mount on '/' */
-		if (*path != '/' || *(path + 1)) {
-			ret = -ENOTDIR;
-			goto err_free_path;
-		}
+		if (pathname[0] != '/' || pathname[1])
+			return -EINVAL;
 	}
 
+	if (!fsoptions)
+		fsoptions = "";
+
+	debug("mount: %s on %s type %s, options=%s\n",
+			device, pathname, fsname, fsoptions);
+
 	if (!fsname)
 		fsname = detect_fs(device, fsoptions);
 
-	if (!fsname)
-		return -ENOENT;
+	if (!fsname) {
+		ret = -ENOENT;
+		goto out;
+	}
 
 	fsdev = xzalloc(sizeof(struct fs_device_d));
 	fsdev->backingstore = xstrdup(device);
 	safe_strncpy(fsdev->dev.name, fsname, MAX_DRIVER_NAME);
 	fsdev->dev.id = get_free_deviceid(fsdev->dev.name);
-	fsdev->path = xstrdup(path);
 	fsdev->dev.bus = &fs_bus;
 	fsdev->options = xstrdup(fsoptions);
 
+	init_super(&fsdev->sb);
+
+	if (path.mnt)
+		mntget(path.mnt);
+
 	ret = register_device(&fsdev->dev);
 	if (ret)
 		goto err_register;
@@ -1391,6 +2708,22 @@ int mount(const char *device, const char *fsname, const char *_path,
 		goto err_no_driver;
 	}
 
+	if (d_root) {
+		fsdev->vfsmount.mountpoint = path.dentry;
+		fsdev->vfsmount.parent = path.mnt;
+		fsdev->vfsmount.mountpoint->d_flags |= DCACHE_MOUNTED;
+	} else {
+		d_root = fsdev->sb.s_root;
+		path.dentry = d_root;
+		mnt_root = &fsdev->vfsmount;
+		fsdev->vfsmount.mountpoint = d_root;
+		fsdev->vfsmount.parent = &fsdev->vfsmount;
+	}
+
+	fsdev->path = dpath(path.dentry, d_root);
+
+	fsdev->vfsmount.mnt_root = fsdev->sb.s_root;
+
 	if (!fsdev->linux_rootarg && fsdev->cdev && fsdev->cdev->partuuid[0] != 0) {
 		char *str = basprintf("root=PARTUUID=%s",
 					fsdev->cdev->partuuid);
@@ -1398,7 +2731,7 @@ int mount(const char *device, const char *fsname, const char *_path,
 		fsdev_set_linux_rootarg(fsdev, str);
 	}
 
-	free(path);
+	path_put(&path);
 
 	return 0;
 
@@ -1406,8 +2739,8 @@ err_no_driver:
 	unregister_device(&fsdev->dev);
 err_register:
 	fs_remove(&fsdev->dev);
-err_free_path:
-	free(path);
+out:
+	path_put(&path);
 
 	errno = -ret;
 
@@ -1415,69 +2748,39 @@ err_free_path:
 }
 EXPORT_SYMBOL(mount);
 
-static int fsdev_umount(struct fs_device_d *fsdev)
-{
-	return unregister_device(&fsdev->dev);
-}
-
-/**
- * umount_by_cdev Use a cdev struct to umount all mounted filesystems
- * @param cdev cdev to the according device
- * @return 0 on success or if cdev was not mounted, -errno otherwise
- */
-int umount_by_cdev(struct cdev *cdev)
+int umount(const char *pathname)
 {
-	struct fs_device_d *fs;
-	struct fs_device_d *fs_tmp;
-	int first_error = 0;
+	struct fs_device_d *fsdev = NULL, *f;
+	struct path path = {};
+	int ret;
 
-	for_each_fs_device_safe(fs_tmp, fs) {
-		int ret;
+	ret = filename_lookup(AT_FDCWD, getname(pathname), LOOKUP_FOLLOW, &path);
+	if (ret)
+		return ret;
 
-		if (fs->cdev == cdev) {
-			ret = fsdev_umount(fs);
-			if (ret) {
-				pr_err("Failed umounting %s, %d, continuing anyway\n",
-				       fs->path, ret);
-				if (!first_error)
-					first_error = ret;
-			}
-		}
+	if (path.dentry == d_root) {
+		path_put(&path);
+		return -EBUSY;
 	}
 
-	return first_error;
-}
-EXPORT_SYMBOL(umount_by_cdev);
-
-int umount(const char *pathname)
-{
-	struct fs_device_d *fsdev = NULL, *f;
-	char *p = normalise_path(pathname);
-
 	for_each_fs_device(f) {
-		if (!strcmp(p, f->path)) {
+		if (path.dentry == f->vfsmount.mnt_root) {
 			fsdev = f;
 			break;
 		}
 	}
 
+	path_put(&path);
+
 	if (!fsdev) {
-		struct cdev *cdev = cdev_open(p, O_RDWR);
+		struct cdev *cdev = cdev_open(pathname, O_RDWR);
 
 		if (cdev) {
-			free(p);
 			cdev_close(cdev);
 			return umount_by_cdev(cdev);
 		}
 	}
 
-	free(p);
-
-	if (f == fs_dev_root && !list_is_singular(&fs_device_list)) {
-		errno = EBUSY;
-		return -EBUSY;
-	}
-
 	if (!fsdev) {
 		errno = EFAULT;
 		return -EFAULT;
@@ -1487,386 +2790,249 @@ int umount(const char *pathname)
 }
 EXPORT_SYMBOL(umount);
 
-DIR *opendir(const char *pathname)
-{
-	DIR *dir = NULL;
-	struct fs_device_d *fsdev;
-	struct fs_driver_d *fsdrv;
-	char *p = canonicalize_path(pathname);
-	char *freep = p;
-	int ret;
-	struct stat s;
-
-	ret = stat(pathname, &s);
-	if (ret)
-		goto out;
-
-	if (!S_ISDIR(s.st_mode)) {
-		ret = -ENOTDIR;
-		goto out;
-	}
-
-	fsdev = get_fs_device_and_root_path(&p);
-	if (!fsdev) {
-		ret = -ENOENT;
-		goto out;
-	}
-	fsdrv = fsdev->driver;
-
-	debug("opendir: fsdrv: %p\n",fsdrv);
-
-	dir = fsdrv->opendir(&fsdev->dev, p);
-	if (dir) {
-		dir->dev = &fsdev->dev;
-		dir->fsdrv = fsdrv;
-	} else {
-		/*
-		 * FIXME: The fs drivers should return ERR_PTR here so that
-		 * we are able to forward the error
-		 */
-		ret = -EINVAL;
-	}
-
-out:
-	free(freep);
-
-	if (ret)
-		errno = -ret;
-
-	return dir;
-}
-EXPORT_SYMBOL(opendir);
-
-struct dirent *readdir(DIR *dir)
-{
-	struct dirent *ent;
-
-	if (!dir)
-		return NULL;
+#ifdef CONFIG_FS_AUTOMOUNT
 
-	ent = dir->fsdrv->readdir(dir->dev, dir);
+#define AUTOMOUNT_IS_FILE (1 << 0)
 
-	if (!ent)
-		errno = EBADF;
+struct automount {
+	char *path;
+	struct dentry *dentry;
+	char *cmd;
+	struct list_head list;
+	unsigned int flags;
+};
 
-	return ent;
-}
-EXPORT_SYMBOL(readdir);
+static LIST_HEAD(automount_list);
 
-int closedir(DIR *dir)
+static void automount_remove_dentry(struct dentry *dentry)
 {
-	int ret;
+	struct automount *am;
 
-	if (!dir) {
-		errno = EBADF;
-		return -EBADF;
+	list_for_each_entry(am, &automount_list, list) {
+		if (dentry == am->dentry)
+			goto found;
 	}
 
-	ret = dir->fsdrv->closedir(dir->dev, dir);
-	if (ret)
-		errno = -ret;
-
-	return ret;
+	return;
+found:
+	list_del(&am->list);
+	dput(am->dentry);
+	free(am->path);
+	free(am->cmd);
+	free(am);
 }
-EXPORT_SYMBOL(closedir);
 
-int stat(const char *filename, struct stat *s)
+void automount_remove(const char *pathname)
 {
-	char *path = canonicalize_path(filename);
+	struct path path;
 	int ret;
 
-	if (IS_ERR(path))
-		return PTR_ERR(path);
-
-	ret = lstat(path, s);
+	ret = filename_lookup(AT_FDCWD, getname(pathname), LOOKUP_FOLLOW, &path);
+	if (ret)
+		return;
 
-	free(path);
+	automount_remove_dentry(path.dentry);
 
-	return ret;
+	path_put(&path);
 }
-EXPORT_SYMBOL(stat);
+EXPORT_SYMBOL(automount_remove);
 
-static int __lstat(const char *filename, struct stat *s)
+int automount_add(const char *pathname, const char *cmd)
 {
-	struct fs_driver_d *fsdrv;
-	struct fs_device_d *fsdev;
-	char *f = normalise_path(filename);
-	char *freep = f;
+	struct automount *am = xzalloc(sizeof(*am));
+	struct path path;
 	int ret;
 
-	automount_mount(f, 1);
-
-	memset(s, 0, sizeof(struct stat));
+	ret = filename_lookup(AT_FDCWD, getname(pathname), LOOKUP_FOLLOW, &path);
+	if (ret)
+		return ret;
 
-	fsdev = get_fsdevice_by_path(f);
-	if (!fsdev) {
-		ret = -ENOENT;
+	if (!d_is_dir(path.dentry)) {
+		ret = -ENOTDIR;
 		goto out;
 	}
 
-	if (fsdev != fs_dev_root && strcmp(f, fsdev->path))
-		f += strlen(fsdev->path);
-	else
-		fsdev = fs_dev_root;
+	am->path = dpath(path.dentry, d_root);
+	am->dentry = dget(path.dentry);
+	am->dentry->d_flags |= DCACHE_NEED_AUTOMOUNT;
+	am->cmd = xstrdup(cmd);
 
-	fsdrv = fsdev->driver;
+	automount_remove_dentry(am->dentry);
 
-	if (*f == 0)
-		f = "/";
+	list_add_tail(&am->list, &automount_list);
 
-	ret = fsdrv->stat(&fsdev->dev, f, s);
+	ret = 0;
 out:
-	free(freep);
-
-	if (ret)
-		errno = -ret;
+	path_put(&path);
 
 	return ret;
 }
+EXPORT_SYMBOL(automount_add);
 
-int lstat(const char *filename, struct stat *s)
+void cdev_create_default_automount(struct cdev *cdev)
 {
-	char *f = canonicalize_dir(filename);
-	int ret;
-
-	if (IS_ERR(f))
-		return PTR_ERR(f);
+	char *path, *cmd;
 
-	ret = __lstat(f, s);
+	path = basprintf("/mnt/%s", cdev->name);
+	cmd = basprintf("mount %s", cdev->name);
 
-	free(f);
+	make_directory(path);
+	automount_add(path, cmd);
 
-	return ret;
+	free(cmd);
+	free(path);
 }
-EXPORT_SYMBOL(lstat);
 
-int fstat(int fd, struct stat *s)
+void automount_print(void)
 {
-	FILE *f;
-	struct fs_device_d *fsdev;
-
-	if (check_fd(fd))
-		return -errno;
-
-	f = &files[fd];
-
-	fsdev = f->fsdev;
+	struct automount *am;
 
-	return fsdev->driver->stat(&fsdev->dev, f->path, s);
+	list_for_each_entry(am, &automount_list, list)
+		printf("%-20s %s\n", am->path, am->cmd);
 }
-EXPORT_SYMBOL(fstat);
+EXPORT_SYMBOL(automount_print);
 
-int mkdir (const char *pathname, mode_t mode)
+static int automount_mount(struct dentry *dentry)
 {
-	struct fs_driver_d *fsdrv;
-	struct fs_device_d *fsdev;
-	char *p = canonicalize_path(pathname);
-	char *freep = p;
-	int ret;
-	struct stat s;
-
-	ret = parent_check_directory(p);
-	if (ret)
-		goto out;
-
-	ret = stat(pathname, &s);
-	if (!ret) {
-		ret = -EEXIST;
-		goto out;
-	}
-
-	fsdev = get_fs_device_and_root_path(&p);
-	if (!fsdev) {
-		ret = -ENOENT;
-		goto out;
-	}
-	fsdrv = fsdev->driver;
-
-	if (fsdrv->mkdir)
-		ret = fsdrv->mkdir(&fsdev->dev, p);
-	else
-		ret = -EROFS;
-out:
-	free(freep);
+	struct automount *am;
+	int ret = -ENOENT;
+	static int in_automount;
 
-	if (ret)
-		errno = -ret;
+	if (in_automount)
+		return -EINVAL;
 
-	return ret;
-}
-EXPORT_SYMBOL(mkdir);
+	in_automount++;
 
-int rmdir (const char *pathname)
-{
-	struct fs_driver_d *fsdrv;
-	struct fs_device_d *fsdev;
-	char *p = canonicalize_path(pathname);
-	char *freep = p;
-	int ret;
-	struct stat s;
+	list_for_each_entry(am, &automount_list, list) {
+		if (am->dentry != dentry)
+			continue;
 
-	ret = lstat(pathname, &s);
-	if (ret)
-		goto out;
-	if (!S_ISDIR(s.st_mode)) {
-		ret = -ENOTDIR;
-		goto out;
-	}
+		setenv("automount_path", am->path);
+		export("automount_path");
+		ret = run_command(am->cmd);
+		setenv("automount_path", NULL);
 
-	if (!dir_is_empty(pathname)) {
-		ret = -ENOTEMPTY;
-		goto out;
-	}
+		if (ret) {
+			printf("running automount command '%s' failed\n",
+					am->cmd);
+			ret = -ENODEV;
+		}
 
-	fsdev = get_fs_device_and_root_path(&p);
-	if (!fsdev) {
-		ret = -ENODEV;
-		goto out;
+		break;
 	}
-	fsdrv = fsdev->driver;
-
-	if (fsdrv->rmdir)
-		ret = fsdrv->rmdir(&fsdev->dev, p);
-	else
-		ret = -EROFS;
-out:
-	free(freep);
 
-	if (ret)
-		errno = -ret;
+	in_automount--;
 
 	return ret;
 }
-EXPORT_SYMBOL(rmdir);
-
-/*
- * cdev_get_mount_path - return the path a cdev is mounted on
- *
- * If a cdev is mounted return the path it's mounted on, NULL
- * otherwise.
- */
-const char *cdev_get_mount_path(struct cdev *cdev)
-{
-	struct fs_device_d *fsdev;
 
-	for_each_fs_device(fsdev) {
-		if (fsdev->cdev && fsdev->cdev == cdev)
-			return fsdev->path;
-	}
+BAREBOX_MAGICVAR(automount_path, "mountpath passed to automount scripts");
 
-	return NULL;
+#else
+static int automount_mount(const char *path)
+{
+	return 0;
 }
+#endif /* CONFIG_FS_AUTOMOUNT */
+
+#ifdef DEBUG
 
 /*
- * cdev_mount_default - mount a cdev to the default path
- *
- * If a cdev is already mounted return the path it's mounted on, otherwise
- * mount it to /mnt/<cdevname> and return the path. Returns an error pointer
- * on failure.
+ * Some debug commands, helpful to debug the dcache implementation
  */
-const char *cdev_mount_default(struct cdev *cdev, const char *fsoptions)
+#include <command.h>
+
+static int do_lookup_dentry(int argc, char *argv[])
 {
-	const char *path;
-	char *newpath, *devpath;
+	struct path path;
 	int ret;
+	char *canon;
+	char mode[16];
 
-	/*
-	 * If this cdev is already mounted somewhere use this path
-	 * instead of mounting it again to avoid corruption on the
-	 * filesystem. Note this ignores eventual fsoptions though.
-	 */
-	path = cdev_get_mount_path(cdev);
-	if (path)
-		return path;
-
-	newpath = basprintf("/mnt/%s", cdev->name);
-	make_directory(newpath);
-
-	devpath = basprintf("/dev/%s", cdev->name);
-
-	ret = mount(devpath, NULL, newpath, fsoptions);
-
-	free(devpath);
+	if (argc < 2)
+		return COMMAND_ERROR_USAGE;
 
+	ret = filename_lookup(AT_FDCWD, getname(argv[1]), 0, &path);
 	if (ret) {
-		free(newpath);
-		return ERR_PTR(ret);
+		printf("Cannot lookup path \"%s\": %s\n",
+		       argv[1], strerror(-ret));
+		return 1;
 	}
 
-	return cdev_get_mount_path(cdev);
-}
+	canon = canonicalize_path(argv[1]);
+	
+	printf("path \"%s\":\n", argv[1]);
+	printf("dentry: 0x%p\n", path.dentry);
+	printf("dentry refcnt: %d\n", path.dentry->d_count);
+	if (path.dentry->d_inode) {
+		struct inode *inode = path.dentry->d_inode;
+		printf("inode: 0x%p\n", inode);
+		printf("inode refcnt: %d\n", inode->i_count);
+		printf("Type: %s\n", mkmodestr(inode->i_mode, mode));
+	}
+	printf("canonical path: \"%s\"\n", canon);
 
-/*
- * mount_all - iterate over block devices and mount all devices we are able to
- */
-void mount_all(void)
-{
-	struct device_d *dev;
-	struct block_device *bdev;
+	path_put(&path);
+	free(canon);
 
-	if (!IS_ENABLED(CONFIG_BLOCK))
-		return;
+        return 0;
+}
 
-	for_each_device(dev)
-		device_detect(dev);
+BAREBOX_CMD_START(lookup_dentry)
+        .cmd            = do_lookup_dentry,
+BAREBOX_CMD_END
 
-	for_each_block_device(bdev) {
-		struct cdev *cdev = &bdev->cdev;
+static struct dentry *debug_follow_mount(struct dentry *dentry)
+{
+	struct fs_device_d *fsdev;
+	unsigned managed = dentry->d_flags;
 
-		list_for_each_entry(cdev, &bdev->dev->cdevs, devices_list)
-			cdev_mount_default(cdev, NULL);
+	if (managed & DCACHE_MOUNTED) {
+		for_each_fs_device(fsdev) {
+			if (dentry == fsdev->vfsmount.mountpoint)
+				return fsdev->vfsmount.mnt_root;
+		}
+		return NULL;
+	} else {
+		return dentry;
 	}
 }
 
-void fsdev_set_linux_rootarg(struct fs_device_d *fsdev, const char *str)
+static void debug_dump_dentries(struct dentry *parent, int indent)
 {
-	fsdev->linux_rootarg = xstrdup(str);
+	int i;
+	struct dentry *dentry, *mp;
 
-	dev_add_param_fixed(&fsdev->dev, "linux.bootargs", fsdev->linux_rootarg);
-}
+	for (i = 0; i < indent; i++)
+		printf("\t");
+again:
+	printf("%s d: %p refcnt: %d, inode %p refcnt %d\n",
+	       parent->name, parent, parent->d_count, parent->d_inode,
+		parent->d_inode ? parent->d_inode->i_count : -1);
 
-/**
- * path_get_linux_rootarg() - Given a path return a suitable root= option for
- *                            Linux
- * @path: The path
- *
- * Return: A string containing the root= option or an ERR_PTR. the returned
- *         string must be freed by the caller.
- */
-char *path_get_linux_rootarg(const char *path)
-{
-	struct fs_device_d *fsdev;
-	const char *str;
+	mp = debug_follow_mount(parent);
+	if (mp != parent) {
+		for (i = 0; i < indent; i++)
+			printf("\t");
+		printf("MOUNT: ");
 
-	fsdev = get_fsdevice_by_path(path);
-	if (!fsdev)
-		return ERR_PTR(-EINVAL);
+		parent = mp;
 
-	str = dev_get_param(&fsdev->dev, "linux.bootargs");
-	if (!str)
-		return ERR_PTR(-ENOSYS);
+		goto again;
+	}
 
-	return xstrdup(str);
+	list_for_each_entry(dentry, &parent->d_subdirs, d_child)
+		debug_dump_dentries(dentry, indent + 1);
 }
 
-/**
- * __is_tftp_fs() - return true when path is mounted on TFTP
- * @path: The path
- *
- * Do not use directly, use is_tftp_fs instead.
- *
- * Return: true when @path is on TFTP, false otherwise
- */
-bool __is_tftp_fs(const char *path)
+static int do_debug_fs_dump(int argc, char *argv[])
 {
-	struct fs_device_d *fsdev;
-
-	fsdev = get_fsdevice_by_path(path);
-	if (!fsdev)
-		return false;
-
-	if (strcmp(fsdev->driver->drv.name, "tftp"))
-		return false;
+	debug_dump_dentries(d_root, 0);
 
-	return true;
+        return 0;
 }
+
+BAREBOX_CMD_START(debug_fs_dump)
+        .cmd            = do_debug_fs_dump,
+BAREBOX_CMD_END
+#endif
diff --git a/fs/libfs.c b/fs/libfs.c
new file mode 100644
index 0000000000..e1c038757b
--- /dev/null
+++ b/fs/libfs.c
@@ -0,0 +1,87 @@
+#include <common.h>
+#include <fs.h>
+#include <linux/fs.h>
+
+/*
+ * Lookup the data. This is trivial - if the dentry didn't already
+ * exist, we know it is negative.  Set d_op to delete negative dentries.
+ */
+struct dentry *simple_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
+{
+	return NULL;
+}
+
+/* Relationship between i_mode and the DT_xxx types */
+static inline unsigned char dt_type(struct inode *inode)
+{
+	return (inode->i_mode >> 12) & 15;
+}
+
+int dcache_readdir(struct file *file, struct dir_context *ctx)
+{
+	struct dentry *dentry = file->f_path.dentry;
+	struct dentry *d;
+
+	dir_emit_dots(file, ctx);
+
+	list_for_each_entry(d, &dentry->d_subdirs, d_child) {
+		if (d_is_negative(d))
+			continue;
+		dir_emit(ctx, d->d_name.name, d->d_name.len,
+				d_inode(d)->i_ino, dt_type(d_inode(d)));
+	}
+
+        return 0;
+}
+
+const struct file_operations simple_dir_operations = {
+	.iterate = dcache_readdir,
+};
+
+int simple_empty(struct dentry *dentry)
+{
+	struct dentry *child;
+	int ret = 0;
+
+	list_for_each_entry(child, &dentry->d_subdirs, d_child) {
+		if (d_is_positive(child))
+			goto out;
+	}
+	ret = 1;
+out:
+	return ret;
+}
+
+int simple_unlink(struct inode *dir, struct dentry *dentry)
+{
+	struct inode *inode = d_inode(dentry);
+
+	drop_nlink(inode);
+	dput(dentry);
+
+	return 0;
+}
+
+int simple_rmdir(struct inode *dir, struct dentry *dentry)
+{
+	if (IS_ROOT(dentry))
+		return -EBUSY;
+
+	if (!simple_empty(dentry))
+		return -ENOTEMPTY;
+
+	drop_nlink(d_inode(dentry));
+	simple_unlink(dir, dentry);
+	drop_nlink(dir);
+
+	return 0;
+}
+
+const char *simple_get_link(struct dentry *dentry, struct inode *inode)
+{
+	return inode->i_link;
+}
+
+const struct inode_operations simple_symlink_inode_operations = {
+	.get_link = simple_get_link,
+};
diff --git a/fs/pstore/Kconfig b/fs/pstore/Kconfig
index 0c6f136920..a0e9a302f9 100644
--- a/fs/pstore/Kconfig
+++ b/fs/pstore/Kconfig
@@ -1,4 +1,5 @@
 menuconfig FS_PSTORE
+	depends on BROKEN
 	bool
 	prompt "pstore fs support"
 	help
diff --git a/fs/squashfs/Kconfig b/fs/squashfs/Kconfig
index 19b8297af6..d58843b640 100644
--- a/fs/squashfs/Kconfig
+++ b/fs/squashfs/Kconfig
@@ -1,6 +1,7 @@
 menuconfig FS_SQUASHFS
 	bool
 	prompt "squashfs support"
+	depends on BROKEN
 	help
 	  Saying Y here includes support for SquashFS 4.0 (a Compressed
 	  Read-Only File System).  Squashfs is a highly compressed read-only
diff --git a/fs/ubifs/Kconfig b/fs/ubifs/Kconfig
index 889a2be97a..d013ea5780 100644
--- a/fs/ubifs/Kconfig
+++ b/fs/ubifs/Kconfig
@@ -1,6 +1,7 @@
 menuconfig FS_UBIFS
 	bool
 	depends on MTD_UBI
+	depends on BROKEN
 	prompt "ubifs support"
 
 if FS_UBIFS
diff --git a/include/dirent.h b/include/dirent.h
index 5ee4c2063e..1df5d90452 100644
--- a/include/dirent.h
+++ b/include/dirent.h
@@ -1,6 +1,8 @@
 #ifndef __DIRENT_H
 #define __DIRENT_H
 
+#include <linux/list.h>
+
 struct dirent {
 	char d_name[256];
 };
@@ -11,6 +13,7 @@ typedef struct dir {
 	struct node_d *node;
 	struct dirent d;
 	void *priv; /* private data for the fs driver */
+	struct list_head entries;
 } DIR;
 
 DIR *opendir(const char *pathname);
diff --git a/include/fs.h b/include/fs.h
index e6fcd044dd..dcb64405b3 100644
--- a/include/fs.h
+++ b/include/fs.h
@@ -31,14 +31,15 @@ typedef struct filep {
 	/* private fields. Mapping between FILE and filedescriptor number     */
 	int no;
 	char in_use;
+
+	struct inode *f_inode;
+	struct dentry *dentry;
 } FILE;
 
 #define FS_DRIVER_NO_DEV	1
 
 struct fs_driver_d {
 	int (*probe) (struct device_d *dev);
-	int (*mkdir)(struct device_d *dev, const char *pathname);
-	int (*rmdir)(struct device_d *dev, const char *pathname);
 
 	/* create a file. The file is guaranteed to not exist */
 	int (*create)(struct device_d *dev, const char *pathname, mode_t mode);
@@ -47,11 +48,6 @@ struct fs_driver_d {
 	/* Truncate a file to given size */
 	int (*truncate)(struct device_d *dev, FILE *f, ulong size);
 
-	int (*symlink)(struct device_d *dev, const char *pathname,
-		       const char *newpath);
-	int (*readlink)(struct device_d *dev, const char *pathname, char *name,
-			size_t size);
-
 	int (*open)(struct device_d *dev, FILE *f, const char *pathname);
 	int (*close)(struct device_d *dev, FILE *f);
 	int (*read)(struct device_d *dev, FILE *f, void *buf, size_t size);
@@ -59,11 +55,6 @@ struct fs_driver_d {
 	int (*flush)(struct device_d *dev, FILE *f);
 	loff_t (*lseek)(struct device_d *dev, FILE *f, loff_t pos);
 
-	struct dir* (*opendir)(struct device_d *dev, const char *pathname);
-	struct dirent* (*readdir)(struct device_d *dev, struct dir *dir);
-	int (*closedir)(struct device_d *dev, DIR *dir);
-	int (*stat)(struct device_d *dev, const char *file, struct stat *stat);
-
 	int (*ioctl)(struct device_d *dev, FILE *f, int request, void *buf);
 	int (*erase)(struct device_d *dev, FILE *f, loff_t count,
 			loff_t offset);
@@ -99,6 +90,10 @@ struct fs_device_d {
 	struct list_head list;
 	char *options;
 	char *linux_rootarg;
+
+	struct super_block sb;
+
+	struct vfsmount vfsmount;
 };
 
 bool __is_tftp_fs(const char *path);
@@ -135,12 +130,6 @@ int ls(const char *path, ulong flags);
 
 char *mkmodestr(unsigned long mode, char *str);
 
-/*
- * This function turns 'path' into an absolute path and removes all occurrences
- * of "..", "." and double slashes. The returned string must be freed wit free().
- */
-char *normalise_path(const char *path);
-
 char *canonicalize_path(const char *pathname);
 
 char *get_mounted_path(const char *path);
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index dfb466722c..16244129bf 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -53,6 +53,10 @@ struct dentry {
 	spinlock_t d_lock;		/* per dentry lock */
 	struct inode *d_inode;		/* Where the name belongs to - NULL is
 					 * negative */
+
+	unsigned int d_count;
+	const struct dentry_operations *d_op;
+
 	/*
 	 * The next three fields are touched by __d_lookup.  Place them here
 	 * so they all fit in a cache line.
@@ -65,8 +69,8 @@ struct dentry {
 	/*
 	 * d_child and d_rcu can share memory
 	 */
+	struct list_head d_child;       /* child of parent list */
 	struct list_head d_subdirs;	/* our children */
-	struct list_head d_alias;	/* inode alias list */
 	unsigned long d_time;		/* used by d_revalidate */
 	struct super_block *d_sb;	/* The root of the dentry tree */
 	void *d_fsdata;			/* fs-specific data */
@@ -74,7 +78,108 @@ struct dentry {
 	struct dcookie_struct *d_cookie; /* cookie, if any */
 #endif
 	int d_mounted;
-	unsigned char d_iname[DNAME_INLINE_LEN_MIN];	/* small names */
+	unsigned char *name;		/* all names */
+};
+
+struct dentry_operations {
 };
 
+struct dentry * d_make_root(struct inode *);
+void d_add(struct dentry *, struct inode *);
+struct dentry * d_alloc_anon(struct super_block *);
+void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op);
+void d_instantiate(struct dentry *dentry, struct inode *inode);
+void d_delete(struct dentry *);
+struct dentry *dget(struct dentry *);
+void dput(struct dentry *);
+
+#define DCACHE_ENTRY_TYPE		0x00700000
+#define DCACHE_MISS_TYPE		0x00000000 /* Negative dentry (maybe fallthru to nowhere) */
+#define DCACHE_WHITEOUT_TYPE		0x00100000 /* Whiteout dentry (stop pathwalk) */
+#define DCACHE_DIRECTORY_TYPE		0x00200000 /* Normal directory */
+#define DCACHE_AUTODIR_TYPE		0x00300000 /* Lookupless directory (presumed automount) */
+#define DCACHE_REGULAR_TYPE		0x00400000 /* Regular file type (or fallthru to such) */
+#define DCACHE_SPECIAL_TYPE		0x00500000 /* Other file type (or fallthru to such) */
+#define DCACHE_SYMLINK_TYPE		0x00600000 /* Symlink (or fallthru to such) */
+
+#define DCACHE_FALLTHRU			0x01000000 /* Fall through to lower layer */
+#define DCACHE_CANT_MOUNT		0x00000100
+#define DCACHE_MOUNTED                  0x00010000 /* is a mountpoint */
+#define DCACHE_NEED_AUTOMOUNT           0x00020000 /* handle automount on this dir */
+#define DCACHE_MANAGED_DENTRY \
+		(DCACHE_MOUNTED|DCACHE_NEED_AUTOMOUNT)
+
+static inline bool d_mountpoint(const struct dentry *dentry)
+{
+	return dentry->d_flags & DCACHE_MOUNTED;
+}
+
+/*
+ * Directory cache entry type accessor functions.
+ */
+static inline unsigned __d_entry_type(const struct dentry *dentry)
+{
+	return dentry->d_flags & DCACHE_ENTRY_TYPE;
+}
+
+static inline bool d_is_miss(const struct dentry *dentry)
+{
+	return __d_entry_type(dentry) == DCACHE_MISS_TYPE;
+}
+
+static inline bool d_can_lookup(const struct dentry *dentry)
+{
+	return __d_entry_type(dentry) == DCACHE_DIRECTORY_TYPE;
+}
+
+static inline bool d_is_autodir(const struct dentry *dentry)
+{
+	return __d_entry_type(dentry) == DCACHE_AUTODIR_TYPE;
+}
+
+static inline bool d_is_dir(const struct dentry *dentry)
+{
+	return d_can_lookup(dentry) || d_is_autodir(dentry);
+}
+
+static inline bool d_is_symlink(const struct dentry *dentry)
+{
+	return __d_entry_type(dentry) == DCACHE_SYMLINK_TYPE;
+}
+
+static inline bool d_is_reg(const struct dentry *dentry)
+{
+	return __d_entry_type(dentry) == DCACHE_REGULAR_TYPE;
+}
+
+static inline bool d_is_special(const struct dentry *dentry)
+{
+	return __d_entry_type(dentry) == DCACHE_SPECIAL_TYPE;
+}
+
+static inline bool d_is_file(const struct dentry *dentry)
+{
+	return d_is_reg(dentry) || d_is_special(dentry);
+}
+
+static inline bool d_is_negative(const struct dentry *dentry)
+{
+	// TODO: check d_is_whiteout(dentry) also.
+	return d_is_miss(dentry);
+}
+
+static inline bool d_is_positive(const struct dentry *dentry)
+{
+	return !d_is_negative(dentry);
+}
+
+static inline struct inode *d_inode(const struct dentry *dentry)
+{
+	return dentry->d_inode;
+}
+
+#define IS_ROOT(x) ((x) == (x)->d_parent)
+
+char *dpath(struct dentry *dentry, struct dentry *root);
+
 #endif	/* __LINUX_DCACHE_H */
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 153c464470..4550e8feeb 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -34,7 +34,18 @@
 #define DT_SOCK		12
 #define DT_WHT		14
 
+/*
+ * This is the "filldir" function type, used by readdir() to let
+ * the kernel specify what kind of dirent layout it wants to have.
+ * This allows the kernel to read directories into kernel space or
+ * to have different dirent layouts depending on the binary type.
+ */
+struct dir_context;
+typedef int (*filldir_t)(struct dir_context *, const char *, int, loff_t, u64,
+			 unsigned);
+
 struct dir_context {
+	const filldir_t actor;
 	loff_t pos;
 };
 
@@ -94,12 +105,8 @@ struct inode {
 	};
 	uid_t			i_uid;
 	gid_t			i_gid;
-	dev_t			i_rdev;
 	u64			i_version;
 	loff_t			i_size;
-#ifdef __NEED_I_SIZE_ORDERED
-	seqcount_t		i_size_seqcount;
-#endif
 	struct timespec		i_atime;
 	struct timespec		i_mtime;
 	struct timespec		i_ctime;
@@ -107,39 +114,19 @@ struct inode {
 	blkcnt_t		i_blocks;
 	unsigned short          i_bytes;
 	umode_t			i_mode;
-	spinlock_t		i_lock;	/* i_blocks, i_bytes, maybe i_size */
-	struct mutex		i_mutex;
-	struct rw_semaphore	i_alloc_sem;
 	const struct inode_operations	*i_op;
 	const struct file_operations	*i_fop;	/* former ->i_op->default_file_ops */
 	struct super_block	*i_sb;
-	struct file_lock	*i_flock;
-#ifdef CONFIG_QUOTA
-	struct dquot		*i_dquot[MAXQUOTAS];
-#endif
-	struct list_head	i_devices;
-	int			i_cindex;
 
 	__u32			i_generation;
 
-#ifdef CONFIG_DNOTIFY
-	unsigned long		i_dnotify_mask; /* Directory notify events */
-	struct dnotify_struct	*i_dnotify; /* for directory notifications */
-#endif
-
-#ifdef CONFIG_INOTIFY
-	struct list_head	inotify_watches; /* watches on this inode */
-	struct mutex		inotify_mutex;	/* protects the watches list */
-#endif
-
 	unsigned long		i_state;
-	unsigned long		dirtied_when;	/* jiffies of first dirtying */
 
 	unsigned int		i_flags;
+	unsigned int		i_count;
+
+	char			*i_link;
 
-#ifdef CONFIG_SECURITY
-	void			*i_security;
-#endif
 	void			*i_private; /* fs or device private pointer */
 };
 
@@ -199,19 +186,9 @@ struct super_block {
 	   Cannot be worse than a second */
 	u32		   s_time_gran;
 
-	/*
-	 * Filesystem subtype.  If non-empty the filesystem type field
-	 * in /proc/mounts will be "type.subtype"
-	 */
-	char *s_subtype;
-
-	/*
-	 * Saved mount options for lazy filesystems using
-	 * generic_show_options()
-	 */
-	char *s_options;
-
 	/* Number of inodes with nlink == 0 but still referenced */
+
+	const struct dentry_operations *s_d_op; /* default d_op for dentries */
 };
 
 struct file_system_type {
@@ -405,4 +382,80 @@ static inline loff_t i_size_read(const struct inode *inode)
 	return inode->i_size;
 }
 
+struct inode *new_inode(struct super_block *sb);
+unsigned int get_next_ino(void);
+void iput(struct inode *);
+struct inode *iget(struct inode *);
+void inc_nlink(struct inode *inode);
+
+struct inode_operations {
+	struct dentry * (*lookup) (struct inode *,struct dentry *, unsigned int);
+
+	const char *(*get_link) (struct dentry *dentry, struct inode *inode);
+
+	int (*create) (struct inode *,struct dentry *, umode_t);
+	int (*link) (struct dentry *,struct inode *,struct dentry *);
+	int (*unlink) (struct inode *,struct dentry *);
+	int (*symlink) (struct inode *,struct dentry *,const char *);
+	int (*mkdir) (struct inode *,struct dentry *,umode_t);
+	int (*rmdir) (struct inode *,struct dentry *);
+	int (*rename) (struct inode *, struct dentry *,
+		       struct inode *, struct dentry *, unsigned int);
+};
+
+static inline ino_t parent_ino(struct dentry *dentry)
+{
+	return dentry->d_parent->d_inode->i_ino;
+}
+
+static inline bool dir_emit(struct dir_context *ctx,
+			    const char *name, int namelen,
+			    u64 ino, unsigned type)
+{
+	return ctx->actor(ctx, name, namelen, ctx->pos, ino, type) == 0;
+}
+
+static inline bool dir_emit_dot(struct file *file, struct dir_context *ctx)
+{
+	return ctx->actor(ctx, ".", 1, ctx->pos,
+			file->f_path.dentry->d_inode->i_ino, DT_DIR) == 0;
+}
+static inline bool dir_emit_dotdot(struct file *file, struct dir_context *ctx)
+{
+	return ctx->actor(ctx, "..", 2, ctx->pos,
+			parent_ino(file->f_path.dentry), DT_DIR) == 0;
+}
+
+static inline void dir_emit_dots(struct file *file, struct dir_context *ctx)
+{
+	if (ctx->pos == 0) {
+		dir_emit_dot(file, ctx);
+		ctx->pos = 1;
+	}
+	if (ctx->pos == 1) {
+		dir_emit_dotdot(file, ctx);
+		ctx->pos = 2;
+	}
+}
+
+struct file_operations {
+	int (*iterate) (struct file *, struct dir_context *);
+	ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
+	ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
+	int (*ioctl) (struct file *, int request, void *buf);
+	int (*truncate) (struct file *, loff_t);
+};
+
+void drop_nlink(struct inode *inode);
+
+extern const struct file_operations simple_dir_operations;
+extern const struct inode_operations simple_symlink_inode_operations;
+
+int simple_empty(struct dentry *dentry);
+int simple_unlink(struct inode *dir, struct dentry *dentry);
+int simple_rmdir(struct inode *dir, struct dentry *dentry);
+struct dentry *simple_lookup(struct inode *, struct dentry *, unsigned int flags);
+int dcache_readdir(struct file *, struct dir_context *);
+const char *simple_get_link(struct dentry *dentry, struct inode *inode);
+
 #endif /* _LINUX_FS_H */
diff --git a/include/linux/mount.h b/include/linux/mount.h
index 57d5ba9523..9557365fb5 100644
--- a/include/linux/mount.h
+++ b/include/linux/mount.h
@@ -14,8 +14,11 @@
 
 struct vfsmount {
 	struct dentry *mnt_root;	/* root of the mounted tree */
+	struct dentry *mountpoint;	/* where it's mounted (barebox specific, no support */
+	struct vfsmount *parent;	/* for bind mounts and the like) */
 	struct super_block *mnt_sb;	/* pointer to superblock */
 	int mnt_flags;
+	int ref;
 };
 
 #endif /* _LINUX_MOUNT_H */
diff --git a/include/linux/namei.h b/include/linux/namei.h
new file mode 100644
index 0000000000..8ed7f8a1cd
--- /dev/null
+++ b/include/linux/namei.h
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_NAMEI_H
+#define _LINUX_NAMEI_H
+
+#include <linux/kernel.h>
+#include <linux/path.h>
+
+enum { MAX_NESTED_LINKS = 8 };
+
+#define MAXSYMLINKS 40
+
+/*
+ * Type of the last component on LOOKUP_PARENT
+ */
+enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND};
+
+/*
+ * The bitmask for a lookup event:
+ *  - follow links at the end
+ *  - require a directory
+ *  - ending slashes ok even for nonexistent files
+ *  - internal "there are more path components" flag
+ *  - dentry cache is untrusted; force a real lookup
+ *  - suppress terminal automount
+ */
+#define LOOKUP_FOLLOW		0x0001
+#define LOOKUP_DIRECTORY	0x0002
+#define LOOKUP_AUTOMOUNT	0x0004
+
+#define LOOKUP_PARENT		0x0010
+#define LOOKUP_REVAL		0x0020
+#define LOOKUP_RCU		0x0040
+#define LOOKUP_NO_REVAL		0x0080
+
+/*
+ * Intent data
+ */
+#define LOOKUP_OPEN		0x0100
+#define LOOKUP_CREATE		0x0200
+#define LOOKUP_EXCL		0x0400
+#define LOOKUP_RENAME_TARGET	0x0800
+
+#define LOOKUP_JUMPED		0x1000
+#define LOOKUP_ROOT		0x2000
+#define LOOKUP_EMPTY		0x4000
+#define LOOKUP_DOWN		0x8000
+
+#define AT_FDCWD                -100    /* Special value used to indicate
+                                           openat should use the current
+                                           working directory. */
+
+#endif /* _LINUX_NAMEI_H */
diff --git a/include/linux/stat.h b/include/linux/stat.h
index af022c5c79..87fe068396 100644
--- a/include/linux/stat.h
+++ b/include/linux/stat.h
@@ -42,6 +42,8 @@ extern "C" {
 #define S_IWOTH 00002		/* read permission for other */
 #define S_IXOTH 00001		/* execute/search permission for other */
 
+#define S_IRWXUGO	(S_IRWXU|S_IRWXG|S_IRWXO)
+
 struct stat {
 	unsigned short st_dev;
 	unsigned short __pad1;
-- 
2.16.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 13/19] fs: ramfs: Switch to dcache implementation
  2018-04-03  7:48 [PATCH 00/19] Add Linux dcache implementation Sascha Hauer
                   ` (11 preceding siblings ...)
  2018-04-03  7:48 ` [PATCH 12/19] fs: dcache implementation Sascha Hauer
@ 2018-04-03  7:48 ` Sascha Hauer
  2018-04-03  7:48 ` [PATCH 14/19] fs: devfs: " Sascha Hauer
                   ` (5 subsequent siblings)
  18 siblings, 0 replies; 23+ messages in thread
From: Sascha Hauer @ 2018-04-03  7:48 UTC (permalink / raw)
  To: Barebox List

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 fs/Kconfig |   1 -
 fs/ramfs.c | 412 +++++++++++++++----------------------------------------------
 2 files changed, 101 insertions(+), 312 deletions(-)

diff --git a/fs/Kconfig b/fs/Kconfig
index c3a78eaae5..9638e27dbd 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -20,7 +20,6 @@ source fs/ext4/Kconfig
 config FS_RAMFS
 	bool
 	default y
-	depends on BROKEN
 	prompt "ramfs support"
 
 config FS_DEVFS
diff --git a/fs/ramfs.c b/fs/ramfs.c
index a97f0a6ebf..d346a4e755 100644
--- a/fs/ramfs.c
+++ b/fs/ramfs.c
@@ -35,6 +35,7 @@ struct ramfs_chunk {
 };
 
 struct ramfs_inode {
+	struct inode inode;
 	char *name;
 	struct ramfs_inode *parent;
 	struct ramfs_inode *next;
@@ -52,84 +53,52 @@ struct ramfs_inode {
 	struct ramfs_chunk *recent_chunkp;
 };
 
+static inline struct ramfs_inode *to_ramfs_inode(struct inode *inode)
+{
+	return container_of(inode, struct ramfs_inode, inode);
+}
+
 struct ramfs_priv {
 	struct ramfs_inode root;
 };
 
 /* ---------------------------------------------------------------*/
-static struct ramfs_inode * lookup(struct ramfs_inode *node, const char *name)
-{
-	debug("lookup: %s in %p\n",name, node);
-	if(!S_ISDIR(node->mode))
-		return NULL;
 
-	node = node->child;
-	if (!node)
-		return NULL;
+static const struct super_operations ramfs_ops;
+static const struct inode_operations ramfs_dir_inode_operations;
+static const struct inode_operations ramfs_file_inode_operations;
+static const struct inode_operations ramfs_symlink_inode_operations;
+static const struct file_operations ramfs_file_operations;
 
-	while (node) {
-		debug("lookup: %s\n", node->name);
-		if (!strcmp(node->name, name)) {
-			debug("lookup: found: 0x%p\n",node);
-			return node;
-		}
-		node = node->next;
-	}
-        return NULL;
-}
-
-static struct ramfs_inode* rlookup(struct ramfs_priv *priv, const char *path)
+static struct inode *ramfs_get_inode(struct super_block *sb, const struct inode *dir,
+				     umode_t mode)
 {
-	struct ramfs_inode *node = &priv->root;
-        static char *buf;
-        char *part;
-
-	debug("rlookup %s in %p\n",path, node);
-        buf = strdup(path);
-
-        part = strtok(buf, "/");
-        if (!part)
-		goto out;
-
-        do {
-                node = lookup(node, part);
-                if (!node)
-			goto out;
-                part = strtok(NULL, "/");
-        } while(part);
-
-out:
-	free(buf);
-        return node;
-}
+	struct inode *inode = new_inode(sb);
 
-static struct ramfs_inode* rlookup_parent(struct ramfs_priv *priv, const char *pathname, char **file)
-{
-	char *path;
-	struct ramfs_inode *node;
-
-	pathname++;
-	path = strdup(pathname);
+	if (!inode)
+		return NULL;
 
-	if ((*file = strrchr((char *) pathname, '/'))) {
-		char *tmp;
-		(*file)++;
+	inode->i_ino = get_next_ino();
+	inode->i_mode = mode;
 
-		tmp = strrchr(path, '/');
-		*tmp = 0;
-		node = rlookup(priv, path);
-		if (!node) {
-			errno = -ENOENT;
-			goto out;
-		}
-	} else {
-		*file = (char *)pathname;
-		node = &priv->root;
+	switch (mode & S_IFMT) {
+	default:
+		return NULL;
+	case S_IFREG:
+		inode->i_op = &ramfs_file_inode_operations;
+		inode->i_fop = &ramfs_file_operations;
+		break;
+	case S_IFDIR:
+		inode->i_op = &ramfs_dir_inode_operations;
+		inode->i_fop = &simple_dir_operations;
+		inc_nlink(inode);
+		break;
+	case S_IFLNK:
+		inode->i_op = &ramfs_symlink_inode_operations;
+		break;
 	}
 
-out:
-	free(path);
-	return node;
+	return inode;
 }
 
 static int chunks = 0;
@@ -158,168 +127,75 @@ static void ramfs_put_chunk(struct ramfs_chunk *data)
 	chunks--;
 }
 
-static struct ramfs_inode* ramfs_get_inode(void)
-{
-	struct ramfs_inode *node = xzalloc(sizeof(struct ramfs_inode));
-	return node;
-}
-
-static void ramfs_put_inode(struct ramfs_inode *node)
-{
-	struct ramfs_chunk *data = node->data;
-
-	while (data) {
-		struct ramfs_chunk *tmp = data->next;
-		ramfs_put_chunk(data);
-		data = tmp;
-	}
-
-	free(node->symlink);
-	free(node->name);
-	free(node);
-}
-
-static struct ramfs_inode* node_insert(struct ramfs_inode *parent_node, const char *filename, ulong mode)
-{
-	struct ramfs_inode *node, *new_node = ramfs_get_inode();
-	new_node->name = strdup(filename);
-	new_node->mode = mode;
-
-	node = parent_node->child;
-
-	if (S_ISDIR(mode)) {
-		struct ramfs_inode *n = ramfs_get_inode();
-		n->name = strdup(".");
-		n->mode = S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO;
-		n->child = n;
-		n->parent = new_node;
-		new_node->child = n;
-		n = ramfs_get_inode();
-		n->name = strdup("..");
-		n->mode = S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO;
-		n->parent = new_node;
-		n->child = parent_node->child;
-		new_node->child->next = n;
-	}
-
-	while (node->next)
-		node = node->next;
-
-	node->next = new_node;
-	return new_node;
-}
-
 /* ---------------------------------------------------------------*/
 
-static int __ramfs_create(struct device_d *dev, const char *pathname,
-			  mode_t mode, const char *symlink)
+static int
+ramfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode)
 {
-	struct ramfs_priv *priv = dev->priv;
-	struct ramfs_inode *node;
-	char *file;
-	char *__symlink = NULL;
-
-	node = rlookup_parent(priv, pathname, &file);
-	if (!node)
-		return -ENOENT;
+	struct inode *inode = ramfs_get_inode(dir->i_sb, dir, mode);
 
-	if (symlink) {
-		__symlink = strdup(symlink);
-		if (!__symlink)
-			return -ENOMEM;
-	}
+	if (!inode)
+		return -ENOSPC;
 
-	node = node_insert(node, file, mode);
-	if (!node) {
-		free(__symlink);
-		return -ENOMEM;
+	if (inode) {
+		d_instantiate(dentry, inode);
+		dget(dentry);   /* Extra count - pin the dentry in core */
 	}
 
-	node->symlink = __symlink;
-
 	return 0;
 }
 
-static int ramfs_create(struct device_d *dev, const char *pathname, mode_t mode)
+static int ramfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
 {
-	return __ramfs_create(dev, pathname, mode, NULL);
-}
+	int ret;
 
-static int ramfs_unlink(struct device_d *dev, const char *pathname)
-{
-	struct ramfs_priv *priv = dev->priv;
-	struct ramfs_inode *node, *lastnode;
-	char *file;
-
-	node = rlookup_parent(priv, pathname, &file);
-
-	lastnode = node->child->next;
-	node = lastnode->next;
-
-	while (node) {
-		if (!strcmp(node->name, file)) {
-			struct ramfs_inode *tmp;
-			tmp = node;
-			lastnode->next = node->next;
-			ramfs_put_inode(tmp);
-			return 0;
-		}
-		lastnode = node;
-		node = node->next;
-	};
-	return -ENOENT;
-}
+	ret = ramfs_mknod(dir, dentry, mode | S_IFDIR);
+	if (!ret)
+		inc_nlink(dir);
 
-static int ramfs_mkdir(struct device_d *dev, const char *pathname)
-{
-	return ramfs_create(dev, pathname, S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO);
+	return ret;
 }
 
-static int ramfs_rmdir(struct device_d *dev, const char *pathname)
+static int ramfs_create(struct inode *dir, struct dentry *dentry, umode_t mode)
 {
-	struct ramfs_priv *priv = dev->priv;
-	struct ramfs_inode *node, *lastnode;
-	char *file;
-
-	node = rlookup_parent(priv, pathname, &file);
-
-	lastnode = node->child->next;
-	node = lastnode->next;
-
-	while (node) {
-		if (!strcmp(node->name, file)) {
-			struct ramfs_inode *tmp;
-			tmp = node;
-			lastnode->next = node->next;
-			ramfs_put_inode(tmp->child->next);
-			ramfs_put_inode(tmp->child);
-			ramfs_put_inode(tmp);
-			return 0;
-		}
-		lastnode = node;
-		node = node->next;
-	};
-	return -ENOENT;
+	return ramfs_mknod(dir, dentry, mode | S_IFREG);
 }
 
-static int ramfs_open(struct device_d *dev, FILE *file, const char *filename)
+static int ramfs_symlink(struct inode *dir, struct dentry *dentry,
+			 const char *symname)
 {
-	struct ramfs_priv *priv = dev->priv;
-	struct ramfs_inode *node = rlookup(priv, filename);
+	struct inode *inode;
 
-	if (!node)
-		return -ENOENT;
+	inode = ramfs_get_inode(dir->i_sb, dir, S_IFLNK | S_IRWXG);
+	if (!inode)
+		return -ENOSPC;
+
+	inode->i_link = xstrdup(symname);
+	d_instantiate(dentry, inode);
 
-	file->size = node->size;
-	file->priv = node;
 	return 0;
 }
 
-static int ramfs_close(struct device_d *dev, FILE *f)
+static const char *ramfs_get_link(struct dentry *dentry, struct inode *inode)
 {
-	return 0;
+	return inode->i_link;
 }
 
+static const struct inode_operations ramfs_symlink_inode_operations =
+{
+	.get_link = ramfs_get_link,
+};
+
+static const struct inode_operations ramfs_dir_inode_operations =
+{
+	.lookup = simple_lookup,
+	.symlink = ramfs_symlink,
+	.mkdir = ramfs_mkdir,
+	.rmdir = simple_rmdir,
+	.unlink = simple_unlink,
+	.create = ramfs_create,
+};
+
 static struct ramfs_chunk *ramfs_find_chunk(struct ramfs_inode *node, int chunk)
 {
 	struct ramfs_chunk *data;
@@ -351,7 +227,8 @@ static struct ramfs_chunk *ramfs_find_chunk(struct ramfs_inode *node, int chunk)
 
 static int ramfs_read(struct device_d *_dev, FILE *f, void *buf, size_t insize)
 {
-	struct ramfs_inode *node = f->priv;
+	struct inode *inode = f->f_inode;
+	struct ramfs_inode *node = to_ramfs_inode(inode);
 	int chunk;
 	struct ramfs_chunk *data;
 	int ofs;
@@ -359,12 +236,12 @@ static int ramfs_read(struct device_d *_dev, FILE *f, void *buf, size_t insize)
 	int pos = f->pos;
 	int size = insize;
 
-	chunk = f->pos / CHUNK_SIZE;
+	chunk = pos / CHUNK_SIZE;
 	debug("%s: reading from chunk %d\n", __FUNCTION__, chunk);
 
 	/* Position ourself in stream */
 	data = ramfs_find_chunk(node, chunk);
-	ofs = f->pos % CHUNK_SIZE;
+	ofs = pos % CHUNK_SIZE;
 
 	/* Read till end of current chunk */
 	if (ofs) {
@@ -400,7 +277,8 @@ static int ramfs_read(struct device_d *_dev, FILE *f, void *buf, size_t insize)
 
 static int ramfs_write(struct device_d *_dev, FILE *f, const void *buf, size_t insize)
 {
-	struct ramfs_inode *node = f->priv;
+	struct inode *inode = f->f_inode;
+	struct ramfs_inode *node = to_ramfs_inode(inode);
 	int chunk;
 	struct ramfs_chunk *data;
 	int ofs;
@@ -447,15 +325,10 @@ static int ramfs_write(struct device_d *_dev, FILE *f, const void *buf, size_t i
 	return insize;
 }
 
-static loff_t ramfs_lseek(struct device_d *dev, FILE *f, loff_t pos)
-{
-	f->pos = pos;
-	return f->pos;
-}
-
 static int ramfs_truncate(struct device_d *dev, FILE *f, ulong size)
 {
-	struct ramfs_inode *node = f->priv;
+	struct inode *inode = f->f_inode;
+	struct ramfs_inode *node = to_ramfs_inode(inode);
 	int oldchunks, newchunks;
 	struct ramfs_chunk *data = node->data;
 
@@ -502,108 +375,38 @@ static int ramfs_truncate(struct device_d *dev, FILE *f, ulong size)
 	return 0;
 }
 
-static DIR* ramfs_opendir(struct device_d *dev, const char *pathname)
+static struct inode *ramfs_alloc_inode(struct super_block *sb)
 {
-	DIR *dir;
-	struct ramfs_priv *priv = dev->priv;
 	struct ramfs_inode *node;
 
-	debug("opendir: %s\n", pathname);
-
-	node = rlookup(priv, pathname);
-
+	node = xzalloc(sizeof(*node));
 	if (!node)
 		return NULL;
 
-	if (!S_ISDIR(node->mode))
-		return NULL;
-
-	dir = xmalloc(sizeof(DIR));
-
-	dir->priv = node->child;
-
-	return dir;
-}
-
-static struct dirent* ramfs_readdir(struct device_d *dev, DIR *dir)
-{
-	struct ramfs_inode *node = dir->priv;
-
-	if (node) {
-		strcpy(dir->d.d_name, node->name);
-		dir->priv = node->next;
-		return &dir->d;
-	}
-	return NULL;
-}
-
-static int ramfs_closedir(struct device_d *dev, DIR *dir)
-{
-	free(dir);
-	return 0;
-}
-
-static int ramfs_stat(struct device_d *dev, const char *filename, struct stat *s)
-{
-	struct ramfs_priv *priv = dev->priv;
-	struct ramfs_inode *node = rlookup(priv, filename);
-
-	if (!node)
-		return -ENOENT;
-
-	s->st_size = node->symlink ? strlen(node->symlink) : node->size;
-	s->st_mode = node->mode;
-
-	return 0;
-}
-
-static int ramfs_symlink(struct device_d *dev, const char *pathname,
-		       const char *newpath)
-{
-	mode_t mode = S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO;
-
-	return __ramfs_create(dev, newpath, mode, pathname);
+	return &node->inode;
 }
 
-static int ramfs_readlink(struct device_d *dev, const char *pathname,
-			char *buf, size_t bufsiz)
-{
-	struct ramfs_priv *priv = dev->priv;
-	struct ramfs_inode *node = rlookup(priv, pathname);
-	int len;
-
-	if (!node || !node->symlink)
-		return -ENOENT;
-
-	len = min(bufsiz, strlen(node->symlink));
-
-	memcpy(buf, node->symlink, len);
-
-	return 0;
-}
+static const struct super_operations ramfs_ops = {
+	.alloc_inode = ramfs_alloc_inode,
+};
 
 static int ramfs_probe(struct device_d *dev)
 {
-	struct ramfs_inode *n;
+	struct inode *inode;
 	struct ramfs_priv *priv = xzalloc(sizeof(struct ramfs_priv));
+	struct fs_device_d *fsdev = dev_to_fs_device(dev);
+	struct super_block *sb = &fsdev->sb;
 
 	dev->priv = priv;
 
 	priv->root.name = "/";
 	priv->root.mode = S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO;
 	priv->root.parent = &priv->root;
-	n = ramfs_get_inode();
-	n->name = strdup(".");
-	n->mode = S_IFDIR;
-	n->parent = &priv->root;
-	n->child = n;
-	priv->root.child = n;
-	n = ramfs_get_inode();
-	n->name = strdup("..");
-	n->mode = S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO;
-	n->parent = &priv->root;
-	n->child = priv->root.child;
-	priv->root.child->next = n;
+
+	sb->s_op = &ramfs_ops;
+
+	inode = ramfs_get_inode(sb, NULL, S_IFDIR);
+	sb->s_root = d_make_root(inode);
 
 	return 0;
 }
@@ -614,22 +417,9 @@ static void ramfs_remove(struct device_d *dev)
 }
 
 static struct fs_driver_d ramfs_driver = {
-	.create    = ramfs_create,
-	.unlink    = ramfs_unlink,
-	.open      = ramfs_open,
-	.close     = ramfs_close,
-	.truncate  = ramfs_truncate,
-	.read      = ramfs_read,
-	.write     = ramfs_write,
-	.lseek     = ramfs_lseek,
-	.mkdir     = ramfs_mkdir,
-	.rmdir     = ramfs_rmdir,
-	.opendir   = ramfs_opendir,
-	.readdir   = ramfs_readdir,
-	.closedir  = ramfs_closedir,
-	.stat      = ramfs_stat,
-	.symlink   = ramfs_symlink,
-	.readlink  = ramfs_readlink,
+	.read = ramfs_read,
+	.write = ramfs_write,
+	.truncate = ramfs_truncate,
 	.flags     = FS_DRIVER_NO_DEV,
 	.drv = {
 		.probe  = ramfs_probe,
-- 
2.16.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 14/19] fs: devfs: Switch to dcache implementation
  2018-04-03  7:48 [PATCH 00/19] Add Linux dcache implementation Sascha Hauer
                   ` (12 preceding siblings ...)
  2018-04-03  7:48 ` [PATCH 13/19] fs: ramfs: Switch to " Sascha Hauer
@ 2018-04-03  7:48 ` Sascha Hauer
  2018-04-03  7:48 ` [PATCH 15/19] fs: ext4: " Sascha Hauer
                   ` (4 subsequent siblings)
  18 siblings, 0 replies; 23+ messages in thread
From: Sascha Hauer @ 2018-04-03  7:48 UTC (permalink / raw)
  To: Barebox List

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 fs/Kconfig |   1 -
 fs/devfs.c | 150 ++++++++++++++++++++++++++++++++++---------------------------
 2 files changed, 85 insertions(+), 66 deletions(-)

diff --git a/fs/Kconfig b/fs/Kconfig
index 9638e27dbd..e3460e4443 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -25,7 +25,6 @@ config FS_RAMFS
 config FS_DEVFS
 	bool
 	default y
-	depends on BROKEN
 	prompt "devfs support"
 
 config FS_TFTP
diff --git a/fs/devfs.c b/fs/devfs.c
index 2a7b1b3466..5d0bb2c674 100644
--- a/fs/devfs.c
+++ b/fs/devfs.c
@@ -33,6 +33,11 @@
 #include <linux/mtd/mtd-abi.h>
 #include <partition.h>
 
+struct devfs_inode {
+	struct inode inode;
+	struct cdev *cdev;
+};
+
 extern struct list_head cdev_list;
 
 static int devfs_read(struct device_d *_dev, FILE *f, void *buf, size_t size)
@@ -110,14 +115,11 @@ static int devfs_memmap(struct device_d *_dev, FILE *f, void **map, int flags)
 
 static int devfs_open(struct device_d *_dev, FILE *f, const char *filename)
 {
-	struct cdev *cdev;
+	struct inode *inode = f->f_inode;
+	struct devfs_inode *node = container_of(inode, struct devfs_inode, inode);
+	struct cdev *cdev = node->cdev;
 	int ret;
 
-	cdev = cdev_by_name(filename + 1);
-
-	if (!cdev)
-		return -ENOENT;
-
 	f->size = cdev->flags & DEVFS_IS_CHARACTER_DEV ?
 			FILE_SIZE_STREAM : cdev->size;
 	f->priv = cdev;
@@ -180,71 +182,112 @@ static int devfs_truncate(struct device_d *dev, FILE *f, ulong size)
 	return 0;
 }
 
-static DIR* devfs_opendir(struct device_d *dev, const char *pathname)
+static struct inode *devfs_alloc_inode(struct super_block *sb)
 {
-	DIR *dir;
-
-	dir = xzalloc(sizeof(DIR));
+	struct devfs_inode *node;
 
-	if (!list_empty(&cdev_list))
-		dir->priv = list_first_entry(&cdev_list, struct cdev, list);
+	node = xzalloc(sizeof(*node));
+	if (!node)
+		return NULL;
 
-	return dir;
+	return &node->inode;
 }
 
-static struct dirent* devfs_readdir(struct device_d *_dev, DIR *dir)
+int devfs_iterate(struct file *file, struct dir_context *ctx)
 {
-	struct cdev *cdev = dir->priv;
+	struct cdev *cdev;
 
-	if (!cdev)
-		return NULL;
+	dir_emit_dots(file, ctx);
 
-	list_for_each_entry_from(cdev, &cdev_list, list) {
-		strcpy(dir->d.d_name, cdev->name);
-		dir->priv = list_entry(cdev->list.next, struct cdev, list);
-		return &dir->d;
+	list_for_each_entry(cdev, &cdev_list, list) {
+		dir_emit(ctx, cdev->name, strlen(cdev->name),
+				1 /* FIXME */, DT_REG);
 	}
-	return NULL;
+
+        return 0;
 }
 
-static int devfs_closedir(struct device_d *dev, DIR *dir)
+static const struct inode_operations devfs_file_inode_operations;
+static const struct file_operations devfs_dir_operations;
+static const struct inode_operations devfs_dir_inode_operations;
+static const struct file_operations devfs_file_operations;
+
+static struct inode *devfs_get_inode(struct super_block *sb, const struct inode *dir,
+                                     umode_t mode)
 {
-	free(dir);
-	return 0;
+	struct inode *inode = new_inode(sb);
+
+	if (!inode)
+		return NULL;
+
+	inode->i_ino = get_next_ino();
+	inode->i_mode = mode;
+
+	switch (mode & S_IFMT) {
+	default:
+		return NULL;
+	case S_IFREG:
+		inode->i_op = &devfs_file_inode_operations;
+		inode->i_fop = &devfs_file_operations;
+		break;
+	case S_IFDIR:
+		inode->i_op = &devfs_dir_inode_operations;
+		inode->i_fop = &devfs_dir_operations;
+		inc_nlink(inode);
+		break;
+	}
+
+	return inode;
 }
 
-static int devfs_stat(struct device_d *_dev, const char *filename, struct stat *s)
+static struct dentry *devfs_lookup(struct inode *dir, struct dentry *dentry,
+				   unsigned int flags)
 {
+	struct devfs_inode *dinode;
+	struct inode *inode;
 	struct cdev *cdev;
 
-	cdev = lcdev_by_name(filename + 1);
+	cdev = cdev_by_name(dentry->name);
 	if (!cdev)
-		return -ENOENT;
+		return ERR_PTR(-ENOENT);
 
-	s->st_mode = S_IFCHR;
-	s->st_size = cdev->size;
+	inode = devfs_get_inode(dir->i_sb, dir, S_IFREG | S_IRWXUGO);
+	if (!inode)
+		return ERR_PTR(-ENOMEM);
 
-	if (cdev->link)
-		s->st_mode |= S_IFLNK;
+	dinode = container_of(inode, struct devfs_inode, inode);
 
-	cdev = cdev_readlink(cdev);
+	inode->i_size = cdev->size;
+	dinode->cdev = cdev;
 
-	if (cdev->ops->write)
-		s->st_mode |= S_IWUSR;
-	if (cdev->ops->read)
-		s->st_mode |= S_IRUSR;
+	d_add(dentry, inode);
 
-	return 0;
+	return NULL;
 }
 
+static const struct file_operations devfs_dir_operations = {
+	.iterate = devfs_iterate,
+};
+
+static const struct inode_operations devfs_dir_inode_operations =
+{
+	.lookup = devfs_lookup,
+};
+
+static const struct super_operations devfs_ops = {
+	.alloc_inode = devfs_alloc_inode,
+};
+
 static int devfs_probe(struct device_d *dev)
 {
+	struct inode *inode;
 	struct fs_device_d *fsdev = dev_to_fs_device(dev);
+	struct super_block *sb = &fsdev->sb;
 
-	if (strcmp(fsdev->path, "/dev")) {
-		dev_err(dev, "devfs can only be mounted on /dev/\n");
-		return -EINVAL;
-	}
+	sb->s_op = &devfs_ops;
+
+	inode = devfs_get_inode(sb, NULL, S_IFDIR);
+	sb->s_root = d_make_root(inode);
 
 	return 0;
 }
@@ -253,24 +296,6 @@ static void devfs_delete(struct device_d *dev)
 {
 }
 
-static int devfs_readlink(struct device_d *dev, const char *pathname,
-			  char *buf, size_t bufsz)
-{
-	struct cdev *cdev;
-
-	cdev = cdev_by_name(pathname + 1);
-	if (!cdev)
-		return -ENOENT;
-
-	while (cdev->link)
-		cdev = cdev->link;
-
-	bufsz = min(bufsz, strlen(cdev->name));
-	memcpy(buf, cdev->name, bufsz);
-
-	return 0;
-}
-
 static struct fs_driver_d devfs_driver = {
 	.read      = devfs_read,
 	.write     = devfs_write,
@@ -279,15 +304,10 @@ static struct fs_driver_d devfs_driver = {
 	.close     = devfs_close,
 	.flush     = devfs_flush,
 	.ioctl     = devfs_ioctl,
-	.opendir   = devfs_opendir,
-	.readdir   = devfs_readdir,
 	.truncate  = devfs_truncate,
-	.closedir  = devfs_closedir,
-	.stat      = devfs_stat,
 	.erase     = devfs_erase,
 	.protect   = devfs_protect,
 	.memmap    = devfs_memmap,
-	.readlink  = devfs_readlink,
 	.flags     = FS_DRIVER_NO_DEV,
 	.drv = {
 		.probe  = devfs_probe,
-- 
2.16.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 15/19] fs: ext4: Switch to dcache implementation
  2018-04-03  7:48 [PATCH 00/19] Add Linux dcache implementation Sascha Hauer
                   ` (13 preceding siblings ...)
  2018-04-03  7:48 ` [PATCH 14/19] fs: devfs: " Sascha Hauer
@ 2018-04-03  7:48 ` Sascha Hauer
  2018-04-03  7:48 ` [PATCH 16/19] fs: ubifs: " Sascha Hauer
                   ` (3 subsequent siblings)
  18 siblings, 0 replies; 23+ messages in thread
From: Sascha Hauer @ 2018-04-03  7:48 UTC (permalink / raw)
  To: Barebox List

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 fs/ext4/Kconfig       |   1 -
 fs/ext4/ext_barebox.c | 280 ++++++++++++++++++++++++++++----------------------
 fs/ext4/ext_common.h  |   3 +
 3 files changed, 161 insertions(+), 123 deletions(-)

diff --git a/fs/ext4/Kconfig b/fs/ext4/Kconfig
index ad1bf58536..f36043d9a7 100644
--- a/fs/ext4/Kconfig
+++ b/fs/ext4/Kconfig
@@ -1,4 +1,3 @@
 config FS_EXT4
 	bool
-	depends on BROKEN
 	prompt "ext4 filesystem support"
diff --git a/fs/ext4/ext_barebox.c b/fs/ext4/ext_barebox.c
index e40278a5bd..8406b1d6a4 100644
--- a/fs/ext4/ext_barebox.c
+++ b/fs/ext4/ext_barebox.c
@@ -36,6 +36,7 @@ int ext4fs_devread(struct ext_filesystem *fs, int __sector, int byte_offset,
 	ssize_t size;
 	uint64_t sector = __sector;
 
+//	printf("%s: sec: %5d, ofs: %d len: %d\n", __func__, __sector, byte_offset, byte_len);
 	size = cdev_read(fs->cdev, buf, byte_len, sector * SECTOR_SIZE + byte_offset, 0);
 	if (size < 0) {
 		dev_err(fs->dev, "read error at sector %d: %s\n", __sector,
@@ -46,34 +47,17 @@ int ext4fs_devread(struct ext_filesystem *fs, int __sector, int byte_offset,
 	return 0;
 }
 
-static int ext_open(struct device_d *dev, FILE *file, const char *filename)
+static inline struct ext2fs_node *to_ext2_node(struct inode *inode)
 {
-	struct ext_filesystem *fs = dev->priv;
-	struct ext2fs_node *inode;
-	int ret;
-
-	ret = ext4fs_open(fs->data, filename, &inode);
-	if (ret)
-		return ret;
-
-	file->size = le32_to_cpu(inode->inode.size);
-	file->priv = inode;
-
-	return 0;
-}
-
-static int ext_close(struct device_d *dev, FILE *f)
-{
-	struct ext_filesystem *fs = dev->priv;
-
-	ext4fs_free_node(f->priv, &fs->data->diropen);
-
-	return 0;
+	return container_of(inode, struct ext2fs_node, i);
 }
 
 static int ext_read(struct device_d *_dev, FILE *f, void *buf, size_t insize)
 {
-	return ext4fs_read_file(f->priv, f->pos, insize, buf);
+	struct inode *inode = f->f_inode;
+	struct ext2fs_node *node = to_ext2_node(inode);
+
+	return ext4fs_read_file(node, f->pos, insize, buf);
 }
 
 static loff_t ext_lseek(struct device_d *dev, FILE *f, loff_t pos)
@@ -83,143 +67,195 @@ static loff_t ext_lseek(struct device_d *dev, FILE *f, loff_t pos)
 	return f->pos;
 }
 
-struct ext4fs_dir {
-	struct ext2fs_node *dirnode;
-	int fpos;
-	DIR dir;
-};
-
-static DIR *ext_opendir(struct device_d *dev, const char *pathname)
+struct inode *ext_alloc_inode(struct super_block *sb)
 {
-	struct ext_filesystem *fs = dev->priv;
-	struct ext4fs_dir *ext4_dir;
-	int type, ret;
-
-	ext4_dir = xzalloc(sizeof(*ext4_dir));
-
-	ret = ext4fs_find_file(pathname, &fs->data->diropen, &ext4_dir->dirnode,
-				  &type);
-	if (ret) {
-		free(ext4_dir);
-		return NULL;
-	}
+	struct fs_device_d *fsdev = container_of(sb, struct fs_device_d, sb);
+	struct ext_filesystem *fs = fsdev->dev.priv;
+	struct ext2fs_node *node;
 
-	if (type != FILETYPE_DIRECTORY)
+	node = xzalloc(sizeof(*node));
+	if (!node)
 		return NULL;
 
-	ext4_dir->dir.priv = ext4_dir;
+	node->data = fs->data;
 
-	ret = ext4fs_read_inode(ext4_dir->dirnode->data, ext4_dir->dirnode->ino,
-			&ext4_dir->dirnode->inode);
-	if (ret) {
-		ext4fs_free_node(ext4_dir->dirnode, &fs->data->diropen);
-		free(ext4_dir);
+	return &node->i;
+}
 
-		return NULL;
-	}
+static const struct super_operations ext_ops = {
+	.alloc_inode = ext_alloc_inode,
+};
 
-	return &ext4_dir->dir;
-}
+struct inode *ext_get_inode(struct super_block *sb, int ino);
 
-static struct dirent *ext_readdir(struct device_d *dev, DIR *dir)
+static int ext4fs_get_ino(struct ext2fs_node *dir, struct qstr *name, int *inum)
 {
-	struct ext4fs_dir *ext4_dir = dir->priv;
-	struct ext2_dirent dirent;
-	struct ext2fs_node *diro = ext4_dir->dirnode;
+	unsigned int fpos = 0;
 	int ret;
-	char *filename;
 
-	if (ext4_dir->fpos >= le32_to_cpu(diro->inode.size))
-		return NULL;
+	while (fpos < le32_to_cpu(dir->inode.size)) {
+		struct ext2_dirent dirent;
 
-	ret = ext4fs_read_file(diro, ext4_dir->fpos, sizeof(struct ext2_dirent),
-			(char *) &dirent);
-	if (ret < 0)
-		return NULL;
+		ret = ext4fs_read_file(dir, fpos, sizeof(dirent), (char *)&dirent);
+		if (ret < 1)
+			return -EINVAL;
 
-	if (dirent.namelen == 0)
-		return NULL;
+		if (dirent.namelen != 0) {
+			char filename[dirent.namelen];
+			int ino;
 
-	filename = xzalloc(dirent.namelen + 1);
+			ret = ext4fs_read_file(dir, fpos + sizeof(dirent),
+						  dirent.namelen, filename);
+			if (ret < 1)
+				return -EINVAL;
 
-	ret = ext4fs_read_file(diro, ext4_dir->fpos + sizeof(struct ext2_dirent),
-			dirent.namelen, filename);
-	if (ret < 0) {
-		free(filename);
-		return NULL;
+			ino = le32_to_cpu(dirent.inode);
+
+			if (name->len == dirent.namelen &&
+			    !strncmp(name->name, filename, name->len)) {
+				*inum = ino;
+				return 0;
+			}
+		}
+		fpos += le16_to_cpu(dirent.direntlen);
 	}
 
-	filename[dirent.namelen] = '\0';
+	*inum = 0;
 
-	ext4_dir->fpos += le16_to_cpu(dirent.direntlen);
+	return 0;
+}
 
-	strcpy(dir->d.d_name, filename);
+static struct dentry *ext_lookup(struct inode *dir, struct dentry *dentry,
+				 unsigned int flags)
+{
+	struct ext2fs_node *e2dir = to_ext2_node(dir);
+	int ret, ino;
+	struct inode *inode;
 
-	free(filename);
+	ret = ext4fs_get_ino(e2dir, &dentry->d_name, &ino);
+	if (ret)
+		return ERR_PTR(ret);
 
-	return &dir->d;
+	if (ino) {
+		inode = ext_get_inode(dir->i_sb, ino);
+
+		d_add(dentry, inode);
+	}
+
+	return NULL;
 }
 
-static int ext_closedir(struct device_d *dev, DIR *dir)
+static const struct inode_operations ext_inode_operations = {
+	.lookup = ext_lookup,
+};
+
+static int ext_iterate(struct file *file, struct dir_context *ctx)
 {
-	struct ext_filesystem *fs = dev->priv;
-	struct ext4fs_dir *ext4_dir = dir->priv;
+	struct dentry *dentry = file->f_path.dentry;
+	struct inode *dir = d_inode(dentry);
+	unsigned int fpos = 0;
+	int status, ret;
+	struct ext2fs_node *diro = to_ext2_node(dir);
+	void *buf;
 
-	ext4fs_free_node(ext4_dir->dirnode, &fs->data->diropen);
+	buf = malloc(dir->i_size);
+	if (!buf)
+		return -ENOMEM;
 
-	free(ext4_dir);
+	status = ext4fs_read_file(diro, 0, dir->i_size, buf);
+	if (status < 1) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	while (fpos < dir->i_size) {
+		const struct ext2_dirent *dirent = buf + fpos;
+		const char *filename = buf + fpos + sizeof(*dirent);
+
+		if (dirent->namelen != 0)
+			dir_emit(ctx, filename, dirent->namelen,
+				 le32_to_cpu(dirent->inode), DT_UNKNOWN);
+
+		fpos += le16_to_cpu(dirent->direntlen);
+	}
+	ret = 0;
+out:
+	free(buf);
+
+	return ret;
 
-	return 0;
 }
 
-static int ext_stat(struct device_d *dev, const char *filename, struct stat *s)
+const struct file_operations ext_dir_operations = {
+	.iterate = ext_iterate,
+};
+
+static const char *ext_get_link(struct dentry *dentry, struct inode *inode)
 {
-	struct ext_filesystem *fs = dev->priv;
-	struct ext2fs_node *node;
-	int status, ret;
+	struct ext2fs_node *node = to_ext2_node(inode);
+	int ret;
 
-	status = ext4fs_find_file(filename, &fs->data->diropen, &node, NULL);
-	if (status)
-		return -ENOENT;
+	if (inode->i_size < sizeof(node->inode.b.symlink))
+		return inode->i_link;
 
-	ret = ext4fs_read_inode(node->data, node->ino, &node->inode);
-	if (ret)
-		return ret;
+	BUG_ON(inode->i_link);
 
-	s->st_size = le32_to_cpu(node->inode.size);
-	s->st_mode = le16_to_cpu(node->inode.mode);
+	inode->i_link = zalloc(inode->i_size + 1);
 
-	ext4fs_free_node(node, &fs->data->diropen);
+	ret = ext4fs_read_file(node, 0, inode->i_size, inode->i_link);
+	if (ret == 0) {
+		free(inode->i_link);
+		inode->i_link = NULL;
+	}
 
-	return 0;
+	return inode->i_link;
 }
 
-static int ext_readlink(struct device_d *dev, const char *pathname,
-		char *buf, size_t bufsiz)
+static const struct inode_operations ext_symlink_inode_operations =
 {
-	struct ext_filesystem *fs = dev->priv;
-	struct ext2fs_node *node;
-	char *symlink;
-	int ret, len, type;
+	.get_link = ext_get_link,
+};
 
-	ret = ext4fs_find_file(pathname, &fs->data->diropen, &node, &type);
-	if (ret)
-		return ret;
+struct inode *ext_get_inode(struct super_block *sb, int ino)
+{
+	struct inode *inode;
+	struct ext2fs_node *node;
+	struct fs_device_d *fsdev = container_of(sb, struct fs_device_d, sb);
+	struct ext_filesystem *fs = fsdev->dev.priv;
+	int ret;
 
-	if (type != FILETYPE_SYMLINK)
-		return -EINVAL;
+	inode = new_inode(sb);
 
-	symlink = ext4fs_read_symlink(node);
-	if (!symlink)
-		return -ENOENT;
+	node = container_of(inode, struct ext2fs_node, i);
 
-	len = min(bufsiz, strlen(symlink));
+	ret = ext4fs_read_inode(fs->data, ino, &node->inode);
 
-	memcpy(buf, symlink, len);
+	inode->i_ino = ino;
+	inode->i_mode = le16_to_cpu(node->inode.mode);
+	inode->i_size = le32_to_cpu(node->inode.size);
 
-	free(symlink);
+	switch (inode->i_mode & S_IFMT) {
+	default:
+		return NULL;
+	case S_IFREG:
+		inode->i_op = &ext_inode_operations;
+		break;
+	case S_IFDIR:
+		inode->i_op = &ext_inode_operations;
+		inode->i_fop = &ext_dir_operations;
+		inc_nlink(inode);
+		break;
+	case S_IFLNK:
+		inode->i_op = &ext_symlink_inode_operations;
+		if (inode->i_size < sizeof(node->inode.b.symlink)) {
+			inode->i_link = zalloc(inode->i_size + 1);
+			strncpy(inode->i_link, node->inode.b.symlink,
+				inode->i_size);
+		}
+		break;
+	}
 
-	return 0;
+	return inode;
 }
 
 static int ext_probe(struct device_d *dev)
@@ -227,6 +263,8 @@ static int ext_probe(struct device_d *dev)
 	struct fs_device_d *fsdev = dev_to_fs_device(dev);
 	int ret;
 	struct ext_filesystem *fs;
+	struct super_block *sb = &fsdev->sb;
+	struct inode *inode;
 
 	fs = xzalloc(sizeof(*fs));
 
@@ -243,6 +281,11 @@ static int ext_probe(struct device_d *dev)
 	if (ret)
 		goto err_mount;
 
+	sb->s_op = &ext_ops;
+
+	inode = ext_get_inode(sb, 2);
+	sb->s_root = d_make_root(inode);
+
 	return 0;
 
 err_mount:
@@ -261,15 +304,8 @@ static void ext_remove(struct device_d *dev)
 }
 
 static struct fs_driver_d ext_driver = {
-	.open      = ext_open,
-	.close     = ext_close,
 	.read      = ext_read,
 	.lseek     = ext_lseek,
-	.opendir   = ext_opendir,
-	.readdir   = ext_readdir,
-	.closedir  = ext_closedir,
-	.stat      = ext_stat,
-	.readlink  = ext_readlink,
 	.type      = filetype_ext,
 	.flags     = 0,
 	.drv = {
diff --git a/fs/ext4/ext_common.h b/fs/ext4/ext_common.h
index e82b56b86a..c084cf9a32 100644
--- a/fs/ext4/ext_common.h
+++ b/fs/ext4/ext_common.h
@@ -30,6 +30,8 @@
 #ifndef __EXT_COMMON__
 #define __EXT_COMMON__
 
+#include <linux/fs.h>
+
 #define SECTOR_SIZE		0x200
 #define SECTOR_BITS		9
 
@@ -208,6 +210,7 @@ struct ext2_dirent {
 };
 
 struct ext2fs_node {
+	struct inode i;
 	struct ext2_data *data;
 	struct ext2_inode inode;
 	int ino;
-- 
2.16.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 16/19] fs: ubifs: Switch to dcache implementation
  2018-04-03  7:48 [PATCH 00/19] Add Linux dcache implementation Sascha Hauer
                   ` (14 preceding siblings ...)
  2018-04-03  7:48 ` [PATCH 15/19] fs: ext4: " Sascha Hauer
@ 2018-04-03  7:48 ` Sascha Hauer
  2018-04-03  7:48 ` [PATCH 17/19] fs: nfs: " Sascha Hauer
                   ` (2 subsequent siblings)
  18 siblings, 0 replies; 23+ messages in thread
From: Sascha Hauer @ 2018-04-03  7:48 UTC (permalink / raw)
  To: Barebox List

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 fs/ubifs/Kconfig  |   1 -
 fs/ubifs/Makefile |   2 +-
 fs/ubifs/dir.c    | 410 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 fs/ubifs/super.c  | 153 ++------------------
 fs/ubifs/ubifs.c  | 341 +--------------------------------------------
 fs/ubifs/ubifs.h  |   7 +-
 6 files changed, 432 insertions(+), 482 deletions(-)
 create mode 100644 fs/ubifs/dir.c

diff --git a/fs/ubifs/Kconfig b/fs/ubifs/Kconfig
index d013ea5780..889a2be97a 100644
--- a/fs/ubifs/Kconfig
+++ b/fs/ubifs/Kconfig
@@ -1,7 +1,6 @@
 menuconfig FS_UBIFS
 	bool
 	depends on MTD_UBI
-	depends on BROKEN
 	prompt "ubifs support"
 
 if FS_UBIFS
diff --git a/fs/ubifs/Makefile b/fs/ubifs/Makefile
index e39ae3b0fd..44ef1b561c 100644
--- a/fs/ubifs/Makefile
+++ b/fs/ubifs/Makefile
@@ -1,4 +1,4 @@
 obj-y += ubifs.o io.o super.o sb.o master.o lpt.o
-obj-y += lpt_commit.o scan.o lprops.o
+obj-y += lpt_commit.o scan.o lprops.o dir.o
 obj-y += tnc.o tnc_misc.o debug.o crc16.o budget.o
 obj-y += log.o orphan.o recovery.o replay.o gc.o
diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
new file mode 100644
index 0000000000..e90bdb8348
--- /dev/null
+++ b/fs/ubifs/dir.c
@@ -0,0 +1,410 @@
+/* * This file is part of UBIFS.
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation.
+ * Copyright (C) 2006, 2007 University of Szeged, Hungary
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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
+ *
+ * Authors: Artem Bityutskiy (Битюцкий Артём)
+ *          Adrian Hunter
+ *          Zoltan Sogor
+ */
+
+/*
+ * This file implements directory operations.
+ *
+ * All FS operations in this file allocate budget before writing anything to the
+ * media. If they fail to allocate it, the error is returned. The only
+ * exceptions are 'ubifs_unlink()' and 'ubifs_rmdir()' which keep working even
+ * if they unable to allocate the budget, because deletion %-ENOSPC failure is
+ * not what users are usually ready to get. UBIFS budgeting subsystem has some
+ * space reserved for these purposes.
+ *
+ * All operations in this file write all inodes which they change straight
+ * away, instead of marking them dirty. For example, 'ubifs_link()' changes
+ * @i_size of the parent inode and writes the parent inode together with the
+ * target inode. This was done to simplify file-system recovery which would
+ * otherwise be very difficult to do. The only exception is rename which marks
+ * the re-named inode dirty (because its @i_ctime is updated) but does not
+ * write it, but just marks it as dirty.
+ */
+
+#include "ubifs.h"
+
+/**
+ * inherit_flags - inherit flags of the parent inode.
+ * @dir: parent inode
+ * @mode: new inode mode flags
+ *
+ * This is a helper function for 'ubifs_new_inode()' which inherits flag of the
+ * parent directory inode @dir. UBIFS inodes inherit the following flags:
+ * o %UBIFS_COMPR_FL, which is useful to switch compression on/of on
+ *   sub-directory basis;
+ * o %UBIFS_SYNC_FL - useful for the same reasons;
+ * o %UBIFS_DIRSYNC_FL - similar, but relevant only to directories.
+ *
+ * This function returns the inherited flags.
+ */
+static int inherit_flags(const struct inode *dir, umode_t mode)
+{
+	int flags;
+	const struct ubifs_inode *ui = ubifs_inode(dir);
+
+	if (!S_ISDIR(dir->i_mode))
+		/*
+		 * The parent is not a directory, which means that an extended
+		 * attribute inode is being created. No flags.
+		 */
+		return 0;
+
+	flags = ui->flags & (UBIFS_COMPR_FL | UBIFS_SYNC_FL | UBIFS_DIRSYNC_FL);
+	if (!S_ISDIR(mode))
+		/* The "DIRSYNC" flag only applies to directories */
+		flags &= ~UBIFS_DIRSYNC_FL;
+	return flags;
+}
+
+/**
+ * ubifs_new_inode - allocate new UBIFS inode object.
+ * @c: UBIFS file-system description object
+ * @dir: parent directory inode
+ * @mode: inode mode flags
+ *
+ * This function finds an unused inode number, allocates new inode and
+ * initializes it. Returns new inode in case of success and an error code in
+ * case of failure.
+ */
+struct inode *ubifs_new_inode(struct ubifs_info *c, const struct inode *dir,
+			      umode_t mode)
+{
+	struct inode *inode;
+	struct ubifs_inode *ui;
+
+	inode = new_inode(c->vfs_sb);
+	ui = ubifs_inode(inode);
+	if (!inode)
+		return ERR_PTR(-ENOMEM);
+
+	/*
+	 * Set 'S_NOCMTIME' to prevent VFS form updating [mc]time of inodes and
+	 * marking them dirty in file write path (see 'file_update_time()').
+	 * UBIFS has to fully control "clean <-> dirty" transitions of inodes
+	 * to make budgeting work.
+	 */
+	inode->i_flags |= S_NOCMTIME;
+
+	switch (mode & S_IFMT) {
+	case S_IFREG:
+		inode->i_op = &ubifs_file_inode_operations;
+		inode->i_fop = &ubifs_file_operations;
+		break;
+	case S_IFDIR:
+		inode->i_op  = &ubifs_dir_inode_operations;
+		inode->i_fop = &ubifs_dir_operations;
+		inode->i_size = ui->ui_size = UBIFS_INO_NODE_SZ;
+		break;
+	case S_IFLNK:
+		inode->i_op = &ubifs_symlink_inode_operations;
+		break;
+	case S_IFSOCK:
+	case S_IFIFO:
+	case S_IFBLK:
+	case S_IFCHR:
+		inode->i_op  = &ubifs_file_inode_operations;
+		break;
+	default:
+		BUG();
+	}
+
+	ui->flags = inherit_flags(dir, mode);
+	ubifs_set_inode_flags(inode);
+	if (S_ISREG(mode))
+		ui->compr_type = c->default_compr;
+	else
+		ui->compr_type = UBIFS_COMPR_NONE;
+	ui->synced_i_size = 0;
+
+	spin_lock(&c->cnt_lock);
+	/* Inode number overflow is currently not supported */
+	if (c->highest_inum >= INUM_WARN_WATERMARK) {
+		if (c->highest_inum >= INUM_WATERMARK) {
+			spin_unlock(&c->cnt_lock);
+			ubifs_err(c, "out of inode numbers");
+			iput(inode);
+			return ERR_PTR(-EINVAL);
+		}
+		ubifs_warn(c, "running out of inode numbers (current %lu, max %u)",
+			   (unsigned long)c->highest_inum, INUM_WATERMARK);
+	}
+
+	inode->i_ino = ++c->highest_inum;
+	/*
+	 * The creation sequence number remains with this inode for its
+	 * lifetime. All nodes for this inode have a greater sequence number,
+	 * and so it is possible to distinguish obsolete nodes belonging to a
+	 * previous incarnation of the same inode number - for example, for the
+	 * purpose of rebuilding the index.
+	 */
+	ui->creat_sqnum = ++c->max_sqnum;
+	spin_unlock(&c->cnt_lock);
+	return inode;
+}
+
+static int dbg_check_name(const struct ubifs_info *c,
+			  const struct ubifs_dent_node *dent,
+			  const struct qstr *nm)
+{
+	if (!dbg_is_chk_gen(c))
+		return 0;
+	if (le16_to_cpu(dent->nlen) != nm->len)
+		return -EINVAL;
+	if (memcmp(dent->name, nm->name, nm->len))
+		return -EINVAL;
+	return 0;
+}
+
+static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry,
+				   unsigned int flags)
+{
+	int err;
+	union ubifs_key key;
+	struct inode *inode = NULL;
+	struct ubifs_dent_node *dent;
+	struct ubifs_info *c = dir->i_sb->s_fs_info;
+
+	dbg_gen("'%pd' in dir ino %lu", dentry, dir->i_ino);
+
+	if (dentry->d_name.len > UBIFS_MAX_NLEN)
+		return ERR_PTR(-ENAMETOOLONG);
+
+	dent = kmalloc(UBIFS_MAX_DENT_NODE_SZ, GFP_NOFS);
+	if (!dent)
+		return ERR_PTR(-ENOMEM);
+
+	dent_key_init(c, &key, dir->i_ino, &dentry->d_name);
+
+	err = ubifs_tnc_lookup_nm(c, &key, dent, &dentry->d_name);
+	if (err) {
+		if (err == -ENOENT) {
+			dbg_gen("not found");
+			goto done;
+		}
+		goto out;
+	}
+
+	if (dbg_check_name(c, dent, &dentry->d_name)) {
+		err = -EINVAL;
+		goto out;
+	}
+
+	inode = ubifs_iget(dir->i_sb, le64_to_cpu(dent->inum));
+	if (IS_ERR(inode)) {
+		/*
+		 * This should not happen. Probably the file-system needs
+		 * checking.
+		 */
+		err = PTR_ERR(inode);
+		ubifs_err(c, "dead directory entry '%pd', error %d",
+			dentry, err);
+		ubifs_ro_mode(c, err);
+		goto out;
+	}
+
+done:
+	kfree(dent);
+	/*
+	 * Note, d_splice_alias() would be required instead if we supported
+	 * NFS.
+	 */
+	d_add(dentry, inode);
+	return NULL;
+
+out:
+	kfree(dent);
+	return ERR_PTR(err);
+}
+
+/**
+ * vfs_dent_type - get VFS directory entry type.
+ * @type: UBIFS directory entry type
+ *
+ * This function converts UBIFS directory entry type into VFS directory entry
+ * type.
+ */
+static unsigned int vfs_dent_type(uint8_t type)
+{
+	switch (type) {
+	case UBIFS_ITYPE_REG:
+		return DT_REG;
+	case UBIFS_ITYPE_DIR:
+		return DT_DIR;
+	case UBIFS_ITYPE_LNK:
+		return DT_LNK;
+	case UBIFS_ITYPE_BLK:
+		return DT_BLK;
+	case UBIFS_ITYPE_CHR:
+		return DT_CHR;
+	case UBIFS_ITYPE_FIFO:
+		return DT_FIFO;
+	case UBIFS_ITYPE_SOCK:
+		return DT_SOCK;
+	default:
+		BUG();
+	}
+	return 0;
+}
+
+/*
+ * The classical Unix view for directory is that it is a linear array of
+ * (name, inode number) entries. Linux/VFS assumes this model as well.
+ * Particularly, 'readdir()' call wants us to return a directory entry offset
+ * which later may be used to continue 'readdir()'ing the directory or to
+ * 'seek()' to that specific direntry. Obviously UBIFS does not really fit this
+ * model because directory entries are identified by keys, which may collide.
+ *
+ * UBIFS uses directory entry hash value for directory offsets, so
+ * 'seekdir()'/'telldir()' may not always work because of possible key
+ * collisions. But UBIFS guarantees that consecutive 'readdir()' calls work
+ * properly by means of saving full directory entry name in the private field
+ * of the file description object.
+ *
+ * This means that UBIFS cannot support NFS which requires full
+ * 'seekdir()'/'telldir()' support.
+ */
+static int ubifs_readdir(struct file *file, struct dir_context *ctx)
+{
+	int err = 0;
+	struct qstr nm;
+	union ubifs_key key;
+	struct ubifs_dent_node *dent;
+	struct dentry *dentry = file->f_path.dentry;
+	struct inode *dir = d_inode(dentry);
+	struct ubifs_info *c = dir->i_sb->s_fs_info;
+
+	dbg_gen("dir ino %lu, f_pos %#llx", dir->i_ino, ctx->pos);
+
+	if (ctx->pos > UBIFS_S_KEY_HASH_MASK || ctx->pos == 2)
+		/*
+		 * The directory was seek'ed to a senseless position or there
+		 * are no more entries.
+		 */
+		return 0;
+
+	if (file->f_version == 0) {
+		/*
+		 * The file was seek'ed, which means that @file->private_data
+		 * is now invalid. This may also be just the first
+		 * 'ubifs_readdir()' invocation, in which case
+		 * @file->private_data is NULL, and the below code is
+		 * basically a no-op.
+		 */
+		kfree(file->private_data);
+		file->private_data = NULL;
+	}
+
+	/*
+	 * 'generic_file_llseek()' unconditionally sets @file->f_version to
+	 * zero, and we use this for detecting whether the file was seek'ed.
+	 */
+	file->f_version = 1;
+
+	/* File positions 0 and 1 correspond to "." and ".." */
+	if (ctx->pos < 2) {
+		ubifs_assert(!file->private_data);
+		dir_emit_dots(file, ctx);
+
+		/* Find the first entry in TNC and save it */
+		lowest_dent_key(c, &key, dir->i_ino);
+		nm.name = NULL;
+		dent = ubifs_tnc_next_ent(c, &key, &nm);
+		if (IS_ERR(dent)) {
+			err = PTR_ERR(dent);
+			goto out;
+		}
+
+		ctx->pos = key_hash_flash(c, &dent->key);
+		file->private_data = dent;
+	}
+
+	dent = file->private_data;
+	if (!dent) {
+		/*
+		 * The directory was seek'ed to and is now readdir'ed.
+		 * Find the entry corresponding to @ctx->pos or the closest one.
+		 */
+		dent_key_init_hash(c, &key, dir->i_ino, ctx->pos);
+		nm.name = NULL;
+		dent = ubifs_tnc_next_ent(c, &key, &nm);
+		if (IS_ERR(dent)) {
+			err = PTR_ERR(dent);
+			goto out;
+		}
+		ctx->pos = key_hash_flash(c, &dent->key);
+		file->private_data = dent;
+	}
+
+	while (1) {
+		dbg_gen("feed '%s', ino %llu, new f_pos %#x",
+			dent->name, (unsigned long long)le64_to_cpu(dent->inum),
+			key_hash_flash(c, &dent->key));
+		ubifs_assert(le64_to_cpu(dent->ch.sqnum) >
+			     ubifs_inode(dir)->creat_sqnum);
+
+		nm.len = le16_to_cpu(dent->nlen);
+		dir_emit(ctx, dent->name, nm.len,
+			       le64_to_cpu(dent->inum),
+			       vfs_dent_type(dent->type));
+
+		/* Switch to the next entry */
+		key_read(c, &dent->key, &key);
+		nm.name = dent->name;
+		dent = ubifs_tnc_next_ent(c, &key, &nm);
+		if (IS_ERR(dent)) {
+			err = PTR_ERR(dent);
+			goto out;
+		}
+
+		kfree(file->private_data);
+		ctx->pos = key_hash_flash(c, &dent->key);
+		file->private_data = dent;
+		cond_resched();
+	}
+
+out:
+	kfree(file->private_data);
+	file->private_data = NULL;
+
+	if (err != -ENOENT)
+		ubifs_err(c, "cannot find next direntry, error %d", err);
+	else
+		/*
+		 * -ENOENT is a non-fatal error in this context, the TNC uses
+		 * it to indicate that the cursor moved past the current directory
+		 * and readdir() has to stop.
+		 */
+		err = 0;
+
+
+	/* 2 is a special value indicating that there are no more direntries */
+	ctx->pos = 2;
+	return err;
+}
+
+const struct inode_operations ubifs_dir_inode_operations = {
+	.lookup      = ubifs_lookup,
+};
+
+const struct file_operations ubifs_dir_operations = {
+	.iterate        = ubifs_readdir,
+};
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
index b4eb76202b..abf8ef63c9 100644
--- a/fs/ubifs/super.c
+++ b/fs/ubifs/super.c
@@ -30,6 +30,7 @@
 
 #include <common.h>
 #include <init.h>
+#include <fs.h>
 #include <malloc.h>
 #include <linux/bug.h>
 #include <linux/log2.h>
@@ -49,8 +50,6 @@ struct vfsmount;
 struct super_block *ubifs_sb;
 LIST_HEAD(super_blocks);
 
-static struct inode *inodes_locked_down[INODE_LOCKED_MAX];
-
 int set_anon_super(struct super_block *s, void *data)
 {
 	return 0;
@@ -84,39 +83,6 @@ int ubifs_iput(struct inode *inode)
 	return 0;
 }
 
-/*
- * Lock (save) inode in inode array for readback after recovery
- */
-void iput(struct inode *inode)
-{
-	int i;
-	struct inode *ino;
-
-	/*
-	 * Search end of list
-	 */
-	for (i = 0; i < INODE_LOCKED_MAX; i++) {
-		if (inodes_locked_down[i] == NULL)
-			break;
-	}
-
-	if (i >= INODE_LOCKED_MAX) {
-		dbg_gen("Error, can't lock (save) more inodes while recovery!!!");
-		return;
-	}
-
-	/*
-	 * Allocate and use new inode
-	 */
-	ino = (struct inode *)kzalloc(sizeof(struct ubifs_inode), 0);
-	memcpy(ino, inode, sizeof(struct ubifs_inode));
-
-	/*
-	 * Finally save inode in array
-	 */
-	inodes_locked_down[i] = ino;
-}
-
 /* from fs/inode.c */
 /**
  * clear_nlink - directly zero an inode's link count
@@ -231,6 +197,9 @@ static int validate_inode(struct ubifs_info *c, const struct inode *inode)
 	return err;
 }
 
+const struct inode_operations ubifs_file_inode_operations;
+const struct file_operations ubifs_file_operations;
+
 struct inode *ubifs_iget(struct super_block *sb, unsigned long inum)
 {
 	int err;
@@ -239,35 +208,9 @@ struct inode *ubifs_iget(struct super_block *sb, unsigned long inum)
 	struct ubifs_info *c = sb->s_fs_info;
 	struct inode *inode;
 	struct ubifs_inode *ui;
-#ifdef __BAREBOX__
-	int i;
-#endif
 
 	dbg_gen("inode %lu", inum);
 
-#ifdef __BAREBOX__
-	/*
-	 * U-Boot special handling of locked down inodes via recovery
-	 * e.g. ubifs_recover_size()
-	 */
-	for (i = 0; i < INODE_LOCKED_MAX; i++) {
-		/*
-		 * Exit on last entry (NULL), inode not found in list
-		 */
-		if (inodes_locked_down[i] == NULL)
-			break;
-
-		if (inodes_locked_down[i]->i_ino == inum) {
-			/*
-			 * We found the locked down inode in our array,
-			 * so just return this pointer instead of creating
-			 * a new one.
-			 */
-			return inodes_locked_down[i];
-		}
-	}
-#endif
-
 	inode = iget_locked(sb, inum);
 	if (!inode)
 		return ERR_PTR(-ENOMEM);
@@ -315,10 +258,8 @@ struct inode *ubifs_iget(struct super_block *sb, unsigned long inum)
 	if (err)
 		goto out_invalid;
 
-#ifndef __BAREBOX__
 	switch (inode->i_mode & S_IFMT) {
 	case S_IFREG:
-		inode->i_mapping->a_ops = &ubifs_file_address_operations;
 		inode->i_op = &ubifs_file_inode_operations;
 		inode->i_fop = &ubifs_file_operations;
 		if (ui->xattr) {
@@ -343,7 +284,7 @@ struct inode *ubifs_iget(struct super_block *sb, unsigned long inum)
 		}
 		break;
 	case S_IFLNK:
-		inode->i_op = &ubifs_symlink_inode_operations;
+		inode->i_op = &simple_symlink_inode_operations;
 		if (ui->data_len <= 0 || ui->data_len > UBIFS_MAX_INO_DATA) {
 			err = 12;
 			goto out_invalid;
@@ -357,60 +298,10 @@ struct inode *ubifs_iget(struct super_block *sb, unsigned long inum)
 		((char *)ui->data)[ui->data_len] = '\0';
 		inode->i_link = ui->data;
 		break;
-	case S_IFBLK:
-	case S_IFCHR:
-	{
-		dev_t rdev;
-		union ubifs_dev_desc *dev;
-
-		ui->data = kmalloc(sizeof(union ubifs_dev_desc), GFP_NOFS);
-		if (!ui->data) {
-			err = -ENOMEM;
-			goto out_ino;
-		}
-
-		dev = (union ubifs_dev_desc *)ino->data;
-		if (ui->data_len == sizeof(dev->new))
-			rdev = new_decode_dev(le32_to_cpu(dev->new));
-		else if (ui->data_len == sizeof(dev->huge))
-			rdev = huge_decode_dev(le64_to_cpu(dev->huge));
-		else {
-			err = 13;
-			goto out_invalid;
-		}
-		memcpy(ui->data, ino->data, ui->data_len);
-		inode->i_op = &ubifs_file_inode_operations;
-		init_special_inode(inode, inode->i_mode, rdev);
-		break;
-	}
-	case S_IFSOCK:
-	case S_IFIFO:
-		inode->i_op = &ubifs_file_inode_operations;
-		init_special_inode(inode, inode->i_mode, 0);
-		if (ui->data_len != 0) {
-			err = 14;
-			goto out_invalid;
-		}
-		break;
 	default:
 		err = 15;
 		goto out_invalid;
 	}
-#else
-	if ((inode->i_mode & S_IFMT) == S_IFLNK) {
-		if (ui->data_len <= 0 || ui->data_len > UBIFS_MAX_INO_DATA) {
-			err = 12;
-			goto out_invalid;
-		}
-		ui->data = kmalloc(ui->data_len + 1, GFP_NOFS);
-		if (!ui->data) {
-			err = -ENOMEM;
-			goto out_ino;
-		}
-		memcpy(ui->data, ino->data, ui->data_len);
-		((char *)ui->data)[ui->data_len] = '\0';
-	}
-#endif
 
 	kfree(ino);
 #ifndef __BAREBOX__
@@ -447,22 +338,15 @@ static struct inode *ubifs_alloc_inode(struct super_block *sb)
 	return &ui->vfs_inode;
 };
 
-#ifndef __BAREBOX__
-static void ubifs_i_callback(struct rcu_head *head)
-{
-	struct inode *inode = container_of(head, struct inode, i_rcu);
-	struct ubifs_inode *ui = ubifs_inode(inode);
-	kmem_cache_free(ubifs_inode_slab, ui);
-}
-
 static void ubifs_destroy_inode(struct inode *inode)
 {
 	struct ubifs_inode *ui = ubifs_inode(inode);
 
 	kfree(ui->data);
-	call_rcu(&inode->i_rcu, ubifs_i_callback);
+	kfree(ui);
 }
 
+#ifndef __BAREBOX__
 /*
  * Note, Linux write-back code calls this without 'i_mutex'.
  */
@@ -1330,15 +1214,9 @@ static int mount_ubifs(struct ubifs_info *c)
 	long long x, y;
 	size_t sz;
 
-	c->ro_mount = !!(c->vfs_sb->s_flags & MS_RDONLY);
+	c->ro_mount = true;
 	/* Suppress error messages while probing if MS_SILENT is set */
 	c->probing = !!(c->vfs_sb->s_flags & MS_SILENT);
-#ifdef __BAREBOX__
-	if (!c->ro_mount) {
-		printf("UBIFS: only ro mode in Barebox allowed.\n");
-		return -EACCES;
-	}
-#endif
 
 	err = init_constants_early(c);
 	if (err)
@@ -2099,8 +1977,8 @@ static int ubifs_remount_fs(struct super_block *sb, int *flags, char *data)
 
 const struct super_operations ubifs_super_operations = {
 	.alloc_inode   = ubifs_alloc_inode,
-#ifndef __BAREBOX__
 	.destroy_inode = ubifs_destroy_inode,
+#ifndef __BAREBOX__
 	.put_super     = ubifs_put_super,
 	.write_inode   = ubifs_write_inode,
 	.evict_inode   = ubifs_evict_inode,
@@ -2298,15 +2176,11 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
 		goto out_umount;
 	}
 
-#ifndef __BAREBOX__
 	sb->s_root = d_make_root(root);
 	if (!sb->s_root) {
 		err = -ENOMEM;
 		goto out_umount;
 	}
-#else
-	sb->s_root = NULL;
-#endif
 
 	mutex_unlock(&c->umount_mutex);
 	return 0;
@@ -2680,13 +2554,14 @@ MODULE_AUTHOR("Artem Bityutskiy, Adrian Hunter");
 MODULE_DESCRIPTION("UBIFS - UBI File System");
 #endif
 
-struct super_block *ubifs_get_super(struct device_d *dev, struct ubi_volume_desc *ubi, int silent)
+int ubifs_get_super(struct device_d *dev, struct ubi_volume_desc *ubi, int silent)
 {
+	struct fs_device_d *fsdev = dev_to_fs_device(dev);
 	struct super_block *sb;
 	struct ubifs_info *c;
 	int err;
 
-	sb = alloc_super(NULL, MS_RDONLY | MS_ACTIVE | MS_NOATIME);
+	sb = &fsdev->sb;
 	c = alloc_ubifs_info(ubi);
 
 	c->dev = dev;
@@ -2712,9 +2587,9 @@ struct super_block *ubifs_get_super(struct device_d *dev, struct ubi_volume_desc
 		goto out;
 	}
 
-	return sb;
+	return 0;
 out:
 	kfree(c);
 	kfree(sb);
-	return ERR_PTR(err);
+	return err;
 }
diff --git a/fs/ubifs/ubifs.c b/fs/ubifs/ubifs.c
index a525b044b8..f9b4f4babc 100644
--- a/fs/ubifs/ubifs.c
+++ b/fs/ubifs/ubifs.c
@@ -269,161 +269,6 @@ int __init ubifs_compressors_init(void)
 	return 0;
 }
 
-/*
- * ubifsls...
- */
-
-static int ubifs_finddir(struct super_block *sb, char *dirname,
-			 unsigned long root_inum, unsigned long *inum)
-{
-	int err;
-	struct qstr nm;
-	union ubifs_key key;
-	struct ubifs_dent_node *dent;
-	struct ubifs_info *c;
-	struct file *file;
-	struct dentry *dentry;
-	struct inode *dir;
-	int ret = 0;
-
-	file = kzalloc(sizeof(struct file), 0);
-	dentry = kzalloc(sizeof(struct dentry), 0);
-	dir = kzalloc(sizeof(struct inode), 0);
-	if (!file || !dentry || !dir) {
-		printf("%s: Error, no memory for malloc!\n", __func__);
-		err = -ENOMEM;
-		goto out;
-	}
-
-	dir->i_sb = sb;
-	file->f_path.dentry = dentry;
-	file->f_path.dentry->d_parent = dentry;
-	file->f_path.dentry->d_inode = dir;
-	file->f_path.dentry->d_inode->i_ino = root_inum;
-	c = sb->s_fs_info;
-
-	dbg_gen("dir ino %lu, f_pos %#llx", dir->i_ino, file->f_pos);
-
-	/* Find the first entry in TNC and save it */
-	lowest_dent_key(c, &key, dir->i_ino);
-	nm.name = NULL;
-	dent = ubifs_tnc_next_ent(c, &key, &nm);
-	if (IS_ERR(dent)) {
-		err = PTR_ERR(dent);
-		goto out;
-	}
-
-	file->f_pos = key_hash_flash(c, &dent->key);
-	file->private_data = dent;
-
-	while (1) {
-		dbg_gen("feed '%s', ino %llu, new f_pos %#x",
-			dent->name, (unsigned long long)le64_to_cpu(dent->inum),
-			key_hash_flash(c, &dent->key));
-		ubifs_assert(le64_to_cpu(dent->ch.sqnum) > ubifs_inode(dir)->creat_sqnum);
-
-		nm.len = le16_to_cpu(dent->nlen);
-		if ((strncmp(dirname, (char *)dent->name, nm.len) == 0) &&
-		    (strlen(dirname) == nm.len)) {
-			*inum = le64_to_cpu(dent->inum);
-			ret = 1;
-			goto out_free;
-		}
-
-		/* Switch to the next entry */
-		key_read(c, &dent->key, &key);
-		nm.name = (char *)dent->name;
-		dent = ubifs_tnc_next_ent(c, &key, &nm);
-		if (IS_ERR(dent)) {
-			err = PTR_ERR(dent);
-			goto out;
-		}
-
-		kfree(file->private_data);
-		file->f_pos = key_hash_flash(c, &dent->key);
-		file->private_data = dent;
-		cond_resched();
-	}
-
-out:
-	if (err != -ENOENT)
-		dbg_gen("cannot find next direntry, error %d", err);
-
-out_free:
-	if (file->private_data)
-		kfree(file->private_data);
-	if (file)
-		free(file);
-	if (dentry)
-		free(dentry);
-	if (dir)
-		free(dir);
-
-	return ret;
-}
-
-static unsigned long ubifs_findfile(struct super_block *sb, const char *filename)
-{
-	int ret;
-	char *next;
-	char fpath[128];
-	char *name = fpath;
-	unsigned long root_inum = 1;
-	unsigned long inum;
-
-	strcpy(fpath, filename);
-
-	/* Remove all leading slashes */
-	while (*name == '/')
-		name++;
-
-	/*
-	 * Handle root-direcoty ('/')
-	 */
-	inum = root_inum;
-	if (!name || *name == '\0')
-		return inum;
-
-	for (;;) {
-		struct inode *inode;
-		struct ubifs_inode *ui;
-
-		/* Extract the actual part from the pathname.  */
-		next = strchr(name, '/');
-		if (next) {
-			/* Remove all leading slashes.  */
-			while (*next == '/')
-				*(next++) = '\0';
-		}
-
-		ret = ubifs_finddir(sb, name, root_inum, &inum);
-		if (!ret)
-			return 0;
-		inode = ubifs_iget(sb, inum);
-
-		if (IS_ERR(inode))
-			return 0;
-		ui = ubifs_inode(inode);
-
-		/*
-		 * Check if directory with this name exists
-		 */
-
-		/* Found the node!  */
-		if (!next || *next == '\0')
-			return inum;
-
-		root_inum = inum;
-		name = next;
-	}
-
-	return 0;
-}
-
-/*
- * ubifsload...
- */
-
 /* file.c */
 
 static inline void *kmap(struct page *page)
@@ -487,18 +332,8 @@ struct ubifs_file {
 
 static int ubifs_open(struct device_d *dev, FILE *file, const char *filename)
 {
-	struct ubifs_priv *priv = dev->priv;
-	struct inode *inode;
+	struct inode *inode = file->f_inode;
 	struct ubifs_file *uf;
-	unsigned long inum;
-
-	inum = ubifs_findfile(priv->sb, filename);
-	if (!inum)
-		return -ENOENT;
-
-	inode = ubifs_iget(priv->sb, inum);
-	if (IS_ERR(inode))
-		return -ENOENT;
 
 	uf = xzalloc(sizeof(*uf));
 
@@ -516,9 +351,6 @@ static int ubifs_open(struct device_d *dev, FILE *file, const char *filename)
 static int ubifs_close(struct device_d *dev, FILE *f)
 {
 	struct ubifs_file *uf = f->priv;
-	struct inode *inode = uf->inode;
-
-	ubifs_iput(inode);
 
 	free(uf->buf);
 	free(uf->dn);
@@ -596,163 +428,6 @@ static loff_t ubifs_lseek(struct device_d *dev, FILE *f, loff_t pos)
 	return pos;
 }
 
-struct ubifs_dir {
-	struct file file;
-	struct dentry dentry;
-	struct inode inode;
-	DIR dir;
-	union ubifs_key key;
-	struct ubifs_dent_node *dent;
-	struct ubifs_priv *priv;
-	struct qstr nm;
-};
-
-static DIR *ubifs_opendir(struct device_d *dev, const char *pathname)
-{
-	struct ubifs_priv *priv = dev->priv;
-	struct ubifs_dir *dir;
-	struct file *file;
-	struct dentry *dentry;
-	struct inode *inode;
-	unsigned long inum;
-	struct ubifs_info *c = priv->sb->s_fs_info;
-
-	inum = ubifs_findfile(priv->sb, pathname);
-	if (!inum)
-		return NULL;
-
-	inode = ubifs_iget(priv->sb, inum);
-	if (IS_ERR(inode))
-		return NULL;
-
-	ubifs_iput(inode);
-
-	dir = xzalloc(sizeof(*dir));
-
-	dir->priv = priv;
-
-	file = &dir->file;
-	dentry = &dir->dentry;
-	inode = &dir->inode;
-
-	inode->i_sb = priv->sb;
-	file->f_path.dentry = dentry;
-	file->f_path.dentry->d_parent = dentry;
-	file->f_path.dentry->d_inode = inode;
-	file->f_path.dentry->d_inode->i_ino = inum;
-	file->f_pos = 1;
-
-	/* Find the first entry in TNC and save it */
-	lowest_dent_key(c, &dir->key, inode->i_ino);
-
-	return &dir->dir;
-}
-
-static struct dirent *ubifs_readdir(struct device_d *dev, DIR *_dir)
-{
-	struct ubifs_dir *dir = container_of(_dir, struct ubifs_dir, dir);
-	struct ubifs_info *c = dir->priv->sb->s_fs_info;
-	struct ubifs_dent_node *dent;
-	struct qstr *nm = &dir->nm;
-	struct file *file = &dir->file;
-
-	dent = ubifs_tnc_next_ent(c, &dir->key, nm);
-	if (IS_ERR(dent))
-		return NULL;
-
-	debug("feed '%s', ino %llu, new f_pos %#x\n",
-		dent->name, (unsigned long long)le64_to_cpu(dent->inum),
-		key_hash_flash(c, &dent->key));
-
-	ubifs_assert(le64_to_cpu(dent->ch.sqnum) > ubifs_inode(&dir->inode)->creat_sqnum);
-
-	key_read(c, &dent->key, &dir->key);
-	file->f_pos = key_hash_flash(c, &dent->key);
-	file->private_data = dent;
-
-	nm->len = le16_to_cpu(dent->nlen);
-	nm->name = dent->name;
-
-	strcpy(_dir->d.d_name, dent->name);
-
-	free(dir->dent);
-	dir->dent = dent;
-
-	return &_dir->d;
-}
-
-static int ubifs_closedir(struct device_d *dev, DIR *_dir)
-{
-	struct ubifs_dir *dir = container_of(_dir, struct ubifs_dir, dir);
-
-	free(dir->dent);
-	free(dir);
-
-	return 0;
-}
-
-static int ubifs_stat(struct device_d *dev, const char *filename, struct stat *s)
-{
-	struct ubifs_priv *priv = dev->priv;
-	struct inode *inode;
-	unsigned long inum;
-
-	inum = ubifs_findfile(priv->sb, filename);
-	if (!inum)
-		return -ENOENT;
-
-	inode = ubifs_iget(priv->sb, inum);
-	if (IS_ERR(inode))
-		return -ENOENT;
-
-	s->st_size = inode->i_size;
-	s->st_mode = inode->i_mode;
-
-	ubifs_iput(inode);
-
-	return 0;
-}
-
-static char *ubifs_symlink(struct inode *inode)
-{
-	struct ubifs_inode *ui;
-	char *symlink;
-
-	ui = ubifs_inode(inode);
-	symlink = malloc(ui->data_len + 1);
-
-	memcpy(symlink, ui->data, ui->data_len);
-	symlink[ui->data_len] = '\0';
-
-	return symlink;
-}
-
-static int ubifs_readlink(struct device_d *dev, const char *pathname, char *buf,
-			size_t bufsz)
-{
-	struct ubifs_priv *priv = dev->priv;
-	struct inode *inode;
-	char *symlink;
-	int len;
-	unsigned long inum;
-
-	inum = ubifs_findfile(priv->sb, pathname);
-	if (!inum)
-		return -ENOENT;
-
-	inode = ubifs_iget(priv->sb, inum);
-	if (!inode)
-		return -ENOENT;
-
-	symlink = ubifs_symlink(inode);
-
-	len = min(bufsz, strlen(symlink));
-	memcpy(buf, symlink, len);
-	free(symlink);
-
-	return 0;
-}
-
 void ubifs_set_rootarg(struct ubifs_priv *priv, struct fs_device_d *fsdev)
 {
 	struct ubi_volume_info vi = {};
@@ -795,11 +470,11 @@ static int ubifs_probe(struct device_d *dev)
 		goto err_free;
 	}
 
-	priv->sb = ubifs_get_super(dev, priv->ubi, 0);
-	if (IS_ERR(priv->sb)) {
-		ret = PTR_ERR(priv->sb);
+	ret = ubifs_get_super(dev, priv->ubi, 0);
+	if (ret)
 		goto err;
-	}
+
+	priv->sb = &fsdev->sb;
 
 	ubifs_set_rootarg(priv, fsdev);
 
@@ -821,7 +496,6 @@ static void ubifs_remove(struct device_d *dev)
 	ubi_close_volume(priv->ubi);
 
 	free(c);
-	free(sb);
 
 	free(priv);
 }
@@ -831,11 +505,6 @@ static struct fs_driver_d ubifs_driver = {
 	.close     = ubifs_close,
 	.read      = ubifs_read,
 	.lseek     = ubifs_lseek,
-	.opendir   = ubifs_opendir,
-	.readdir   = ubifs_readdir,
-	.closedir  = ubifs_closedir,
-	.stat      = ubifs_stat,
-	.readlink  = ubifs_readlink,
 	.type = filetype_ubifs,
 	.flags     = 0,
 	.drv = {
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
index 22b24a1161..4c4c927de9 100644
--- a/fs/ubifs/ubifs.h
+++ b/fs/ubifs/ubifs.h
@@ -36,6 +36,7 @@
 #include <lzo.h>
 #include <crc.h>
 #include <linux/fs.h>
+#include <linux/stat.h>
 #include <linux/sched.h>
 #include <linux/ctype.h>
 #include <linux/time.h>
@@ -49,11 +50,9 @@
 
 #define crc32(seed, data, length)  crc32_no_comp(seed, (unsigned char const *)data, length)
 
-struct dentry;
 struct file;
 struct iattr;
 struct kstat;
-struct vfsmount;
 
 extern struct super_block *ubifs_sb;
 
@@ -72,8 +71,6 @@ struct page {
 	struct inode *inode;
 };
 
-void iput(struct inode *inode);
-
 struct kmem_cache { int sz; };
 
 struct kmem_cache *get_mem(int element_sz);
@@ -1901,7 +1898,7 @@ int ubifs_decompress(const struct ubifs_info *c, const void *buf, int len,
 
 #ifdef __BAREBOX__
 void ubifs_umount(struct ubifs_info *c);
-struct super_block *ubifs_get_super(struct device_d *dev, struct ubi_volume_desc *ubi, int silent);
+int ubifs_get_super(struct device_d *dev, struct ubi_volume_desc *ubi, int silent);
 #endif
 
 #endif /* !__UBIFS_H__ */
-- 
2.16.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 17/19] fs: nfs: Switch to dcache implementation
  2018-04-03  7:48 [PATCH 00/19] Add Linux dcache implementation Sascha Hauer
                   ` (15 preceding siblings ...)
  2018-04-03  7:48 ` [PATCH 16/19] fs: ubifs: " Sascha Hauer
@ 2018-04-03  7:48 ` Sascha Hauer
  2018-04-03  7:48 ` [PATCH 18/19] fs: tftp: " Sascha Hauer
  2018-04-03  7:48 ` [PATCH 19/19] block: Adjust cache sizes Sascha Hauer
  18 siblings, 0 replies; 23+ messages in thread
From: Sascha Hauer @ 2018-04-03  7:48 UTC (permalink / raw)
  To: Barebox List

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 fs/Kconfig |   1 -
 fs/nfs.c   | 542 ++++++++++++++++++++++++++-----------------------------------
 2 files changed, 234 insertions(+), 309 deletions(-)

diff --git a/fs/Kconfig b/fs/Kconfig
index e3460e4443..b2d4242e63 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -41,7 +41,6 @@ config FS_OMAP4_USBBOOT
 
 config FS_NFS
 	depends on NET
-	depends on BROKEN
 	bool
 	prompt "nfs support"
 
diff --git a/fs/nfs.c b/fs/nfs.c
index 75cd127eeb..eb5db344db 100644
--- a/fs/nfs.c
+++ b/fs/nfs.c
@@ -20,6 +20,7 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  */
+#define pr_fmt(fmt) "NFS: " fmt
 
 #include <common.h>
 #include <net.h>
@@ -127,6 +128,11 @@ struct rpc_reply {
 #define NFS_TIMEOUT	(2 * SECOND)
 #define NFS_MAX_RESEND	5
 
+struct nfs_fh {
+	unsigned short size;
+	unsigned char data[NFS3_FHSIZE];
+};
+
 struct nfs_priv {
 	struct net_connection *con;
 	IPaddr_t server;
@@ -136,18 +142,34 @@ struct nfs_priv {
 	uint16_t nfs_port;
 	unsigned manual_nfs_port:1;
 	uint32_t rpc_id;
-	uint32_t rootfh_len;
-	char rootfh[NFS3_FHSIZE];
+	struct nfs_fh rootfh;
 };
 
 struct file_priv {
 	struct kfifo *fifo;
 	void *buf;
-	uint32_t filefh_len;
-	char filefh[NFS3_FHSIZE];
+	struct nfs_priv *npriv;
+	struct nfs_fh fh;
+};
+
+struct nfs_inode {
+	struct inode inode;
+	struct nfs_fh fh;
 	struct nfs_priv *npriv;
 };
 
+static inline struct nfs_inode *nfsi(struct inode *inode)
+{
+	return container_of(inode, struct nfs_inode, inode);
+}
+
+static void nfs_set_fh(struct inode *inode, struct nfs_fh *fh)
+{
+	struct nfs_inode *ninode = nfsi(inode);
+
+	ninode->fh = *fh;
+}
+
 static uint64_t nfs_timer_start;
 
 static int nfs_state;
@@ -234,17 +256,14 @@ struct xdr_stream {
 #define XDR_QUADLEN(l)		(((l) + 3) >> 2)
 
 struct nfs_dir {
-	DIR dir;
-
 	/*
 	 * stream points to the next entry3 in the reply member of READDIR3res
 	 * (if any, to the end indicator otherwise).
 	 */
 	struct xdr_stream stream;
-	struct dirent ent;
-	struct file_priv *priv;
 	uint64_t cookie;
 	char cookieverf[NFS3_COOKIEVERFSIZE];
+	struct nfs_fh fh;
 };
 
 static void xdr_init(struct xdr_stream *stream, void *buf, int len)
@@ -300,11 +319,11 @@ static int decode_filename(struct xdr_stream *xdr, char *name, u32 *length)
 	return 0;
 
 out_nametoolong:
-	printf("%s: returned a too long filename: %u\n", __func__, count);
+	pr_err("%s: returned a too long filename: %u\n", __func__, count);
 	return -ENAMETOOLONG;
 
 out_overflow:
-	printf("%s: premature end of packet\n", __func__);
+	pr_err("%s: premature end of packet\n", __func__);
 	return -EIO;
 }
 
@@ -486,16 +505,16 @@ static uint32_t *nfs_add_uint64(uint32_t *p, uint64_t val)
 	return p + 2;
 }
 
-static uint32_t *nfs_add_fh3(uint32_t *p, unsigned fh_len, const char *fh)
+static uint32_t *nfs_add_fh3(uint32_t *p, struct nfs_fh *fh)
 {
-	*p++ = hton32(fh_len);
+	*p++ = hton32(fh->size);
 
 	/* zero padding */
-	if (fh_len & 3)
-		p[fh_len / 4] = 0;
+	if (fh->size & 3)
+		p[fh->size / 4] = 0;
 
-	memcpy(p, fh, fh_len);
-	p += DIV_ROUND_UP(fh_len, 4);
+	memcpy(p, fh->data, fh->size);
+	p += DIV_ROUND_UP(fh->size, 4);
 	return p;
 }
 
@@ -532,33 +551,36 @@ static const struct {
 	{ 0x00800, S_ISUID },
 };
 
-static int nfs_fattr3_to_stat(uint32_t *p, struct stat *s)
+static int nfs_fattr3_to_stat(uint32_t *p, struct inode *inode)
 {
 	uint32_t mode;
 	size_t i;
 
+	if (!inode)
+		return 0;
+
 	/* offsetof(struct fattr3, type) = 0 */
 	switch (ntoh32(net_read_uint32(p + 0))) {
 	case NF3REG:
-		s->st_mode = S_IFREG;
+		inode->i_mode = S_IFREG;
 		break;
 	case NF3DIR:
-		s->st_mode = S_IFDIR;
+		inode->i_mode = S_IFDIR;
 		break;
 	case NF3BLK:
-		s->st_mode = S_IFBLK;
+		inode->i_mode = S_IFBLK;
 		break;
 	case NF3CHR:
-		s->st_mode = S_IFCHR;
+		inode->i_mode = S_IFCHR;
 		break;
 	case NF3LNK:
-		s->st_mode = S_IFLNK;
+		inode->i_mode = S_IFLNK;
 		break;
 	case NF3SOCK:
-		s->st_mode = S_IFSOCK;
+		inode->i_mode = S_IFSOCK;
 		break;
 	case NF3FIFO:
-		s->st_mode = S_IFIFO;
+		inode->i_mode = S_IFIFO;
 		break;
 	default:
 		printf("%s: invalid mode %x\n",
@@ -570,18 +592,17 @@ static int nfs_fattr3_to_stat(uint32_t *p, struct stat *s)
 	mode = ntoh32(net_read_uint32(p + 1));
 	for (i = 0; i < ARRAY_SIZE(nfs3_mode_bits); ++i) {
 		if (mode & nfs3_mode_bits[i].nfsmode)
-			s->st_mode |= nfs3_mode_bits[i].statmode;
+			inode->i_mode |= nfs3_mode_bits[i].statmode;
 	}
 
 	/* offsetof(struct fattr3, size) = 20 */
-	s->st_size = ntoh64(net_read_uint64(p + 5));
+	inode->i_size = ntoh64(net_read_uint64(p + 5));
 
 	return 0;
 }
 
-static uint32_t *nfs_read_post_op_attr(uint32_t *p, struct stat **s)
+static uint32_t *nfs_read_post_op_attr(uint32_t *p, struct inode *inode)
 {
-	struct stat dummy;
 	/*
 	 * union post_op_attr switch (bool attributes_follow) {
 	 * case TRUE:
@@ -592,11 +613,8 @@ static uint32_t *nfs_read_post_op_attr(uint32_t *p, struct stat **s)
 	 */
 
 	if (ntoh32(net_read_uint32(p++))) {
-		nfs_fattr3_to_stat(p, s ? *s : &dummy);
+		nfs_fattr3_to_stat(p, inode);
 		p += 21;
-	} else if (s) {
-		/* no attributes available */
-		*s = NULL;
 	}
 
 	return p;
@@ -635,14 +653,14 @@ static int nfs_mount_req(struct nfs_priv *npriv)
 
 	p = nfs_packet + sizeof(struct rpc_reply) + 4;
 
-	npriv->rootfh_len = ntoh32(net_read_uint32(p++));
-	if (npriv->rootfh_len > NFS3_FHSIZE) {
+	npriv->rootfh.size = ntoh32(net_read_uint32(p++));
+	if (npriv->rootfh.size > NFS3_FHSIZE) {
 		printf("%s: file handle too big: %lu\n", __func__,
-				(unsigned long)npriv->rootfh_len);
+				(unsigned long)npriv->rootfh.size);
 		return -EIO;
 	}
-	memcpy(npriv->rootfh, p, npriv->rootfh_len);
-	p += DIV_ROUND_UP(npriv->rootfh_len, 4);
+	memcpy(npriv->rootfh.data, p, npriv->rootfh.size);
+	p += DIV_ROUND_UP(npriv->rootfh.size, 4);
 
 	return 0;
 }
@@ -674,9 +692,10 @@ static void nfs_umount_req(struct nfs_priv *npriv)
  *
  * *s is set to NULL if LOOKUP3resok doesn't contain obj_attributes.
  */
-static int nfs_lookup_req(struct file_priv *priv,
-		uint32_t filename_len, const char *filename, struct stat **s)
+static int nfs_lookup_req(struct nfs_priv *npriv, struct nfs_fh *fh,
+			  const char *filename, struct inode *inode)
 {
+	struct nfs_inode *ninode = nfsi(inode);
 	uint32_t data[1024];
 	uint32_t *p;
 	int len;
@@ -709,73 +728,29 @@ static int nfs_lookup_req(struct file_priv *priv,
 	p = rpc_add_credentials(p);
 
 	/* what.dir */
-	p = nfs_add_fh3(p, priv->filefh_len, priv->filefh);
+	p = nfs_add_fh3(p, fh);
 
 	/* what.name */
-	p = nfs_add_filename(p, filename_len, filename);
+	p = nfs_add_filename(p, strlen(filename), filename);
 
 	len = p - &(data[0]);
 
-	ret = rpc_req(priv->npriv, PROG_NFS, NFSPROC3_LOOKUP, data, len);
+	ret = rpc_req(npriv, PROG_NFS, NFSPROC3_LOOKUP, data, len);
 	if (ret)
 		return ret;
 
 	p = nfs_packet + sizeof(struct rpc_reply) + 4;
 
-	priv->filefh_len = ntoh32(net_read_uint32(p++));
-	if (priv->filefh_len > NFS3_FHSIZE) {
-		debug("%s: file handle too big: %lu\n", __func__,
-				(unsigned long)priv->filefh_len);
+	ninode->fh.size = ntoh32(net_read_uint32(p++));
+	if (ninode->fh.size > NFS3_FHSIZE) {
+		debug("%s: file handle too big: %u\n", __func__,
+		      ninode->fh.size);
 		return -EIO;
 	}
-	memcpy(priv->filefh, p, priv->filefh_len);
-	p += DIV_ROUND_UP(priv->filefh_len, 4);
-
-	if (s)
-		nfs_read_post_op_attr(p, s);
-
-	return 0;
-}
-
-static int nfs_attr_req(struct file_priv *priv, struct stat *s)
-{
-	uint32_t data[1024];
-	uint32_t *p;
-	int len;
-	int ret;
-
-	/*
-	 * struct GETATTR3args {
-	 * 	nfs_fh3 object;
-	 * }
-	 *
-	 * struct GETATTR3resok {
-	 * 	fattr3 obj_attributes;
-	 * };
-	 *
-	 * union GETATTR3res switch (nfsstat3 status) {
-	 * case NFS3_OK:
-	 * 	GETATTR3resok resok;
-	 * default:
-	 * 	void;
-	 * }
-	 */
-
-	p = &(data[0]);
-	p = rpc_add_credentials(p);
-
-	/* object */
-	p = nfs_add_fh3(p, priv->filefh_len, priv->filefh);
-
-	len = p - &(data[0]);
-
-	ret = rpc_req(priv->npriv, PROG_NFS, NFSPROC3_GETATTR, data, len);
-	if (ret)
-		return ret;
+	memcpy(ninode->fh.data, p, ninode->fh.size);
+	p += DIV_ROUND_UP(ninode->fh.size, 4);
 
-	p = nfs_packet + sizeof(struct rpc_reply) + 4;
-
-	nfs_fattr3_to_stat(p, s);
+	nfs_read_post_op_attr(p, inode);
 
 	return 0;
 }
@@ -784,7 +759,7 @@ static int nfs_attr_req(struct file_priv *priv, struct stat *s)
  * returns with dir->stream pointing to the first entry
  * of dirlist3 res.resok.reply
  */
-static void *nfs_readdirattr_req(struct file_priv *priv, struct nfs_dir *dir)
+static void *nfs_readdirattr_req(struct nfs_priv *npriv, struct nfs_dir *dir)
 {
 	uint32_t data[1024];
 	uint32_t *p;
@@ -833,7 +808,7 @@ static void *nfs_readdirattr_req(struct file_priv *priv, struct nfs_dir *dir)
 	p = &(data[0]);
 	p = rpc_add_credentials(p);
 
-	p = nfs_add_fh3(p, priv->filefh_len, priv->filefh);
+	p = nfs_add_fh3(p, &dir->fh);
 	p = nfs_add_uint64(p, dir->cookie);
 
 	memcpy(p, dir->cookieverf, NFS3_COOKIEVERFSIZE);
@@ -841,7 +816,7 @@ static void *nfs_readdirattr_req(struct file_priv *priv, struct nfs_dir *dir)
 
 	p = nfs_add_uint32(p, 1024); /* count */
 
-	ret = rpc_req(priv->npriv, PROG_NFS, NFSPROC3_READDIR, data, p - data);
+	ret = rpc_req(npriv, PROG_NFS, NFSPROC3_READDIR, data, p - data);
 	if (ret)
 		return NULL;
 
@@ -909,7 +884,7 @@ static int nfs_read_req(struct file_priv *priv, uint64_t offset,
 	p = &(data[0]);
 	p = rpc_add_credentials(p);
 
-	p = nfs_add_fh3(p, priv->filefh_len, priv->filefh);
+	p = nfs_add_fh3(p, &priv->fh);
 	p = nfs_add_uint64(p, offset);
 	p = nfs_add_uint32(p, readlen);
 
@@ -953,82 +928,11 @@ static void nfs_handler(void *ctx, char *packet, unsigned len)
 	nfs_len = len;
 }
 
-static int nfs_create(struct device_d *dev, const char *pathname, mode_t mode)
-{
-	return -ENOSYS;
-}
-
-static int nfs_unlink(struct device_d *dev, const char *pathname)
-{
-	return -ENOSYS;
-}
-
-static int nfs_mkdir(struct device_d *dev, const char *pathname)
-{
-	return -ENOSYS;
-}
-
-static int nfs_rmdir(struct device_d *dev, const char *pathname)
-{
-	return -ENOSYS;
-}
-
 static int nfs_truncate(struct device_d *dev, FILE *f, ulong size)
 {
 	return -ENOSYS;
 }
 
-static struct file_priv *nfs_do_open(struct device_d *dev,
-		const char *filename, struct stat **s)
-{
-	struct file_priv *priv;
-	struct nfs_priv *npriv = dev->priv;
-	int ret;
-	const char *tok;
-
-	debug("%s: filename = %s\n", __func__, filename);
-	priv = xzalloc(sizeof(*priv));
-
-	priv->npriv = npriv;
-
-	if (!*filename) {
-		priv->filefh_len = npriv->rootfh_len;
-		memcpy(priv->filefh, npriv->rootfh, npriv->rootfh_len);
-		return priv;
-	}
-
-	filename++;
-
-	priv->filefh_len = npriv->rootfh_len;
-	memcpy(priv->filefh, npriv->rootfh, NFS3_FHSIZE);
-
-	while (*filename) {
-		size_t flen;
-
-		tok = strchr(filename, '/');
-		if (tok)
-			flen = tok - filename;
-		else
-			flen = strlen(filename);
-
-		ret = nfs_lookup_req(priv, flen, filename, s);
-		if (ret)
-			goto out;
-
-		if (tok)
-			filename += flen + 1;
-		else
-			break;
-	}
-
-	return priv;
-
-out:
-	free(priv);
-
-	return ERR_PTR(ret);
-}
-
 static void nfs_do_close(struct file_priv *priv)
 {
 	if (priv->fifo)
@@ -1037,34 +941,8 @@ static void nfs_do_close(struct file_priv *priv)
 	free(priv);
 }
 
-static struct file_priv *nfs_do_stat(struct device_d *dev,
-		const char *filename, struct stat *s)
-{
-	struct file_priv *priv;
-	int ret;
-	struct stat **sptr = &s;
-
-	debug("%s: filename = %s\n", __func__, filename);
-	priv = nfs_do_open(dev, filename, sptr);
-	if (IS_ERR(priv))
-		return priv;
-
-	if (!*sptr) {
-		/*
-		 * The nfs server didn't provide obj_attributes in the lookup
-		 * reply, so ask for them explicitly.
-		 */
-		ret = nfs_attr_req(priv, s);
-		if (ret) {
-			nfs_do_close(priv);
-			return ERR_PTR(ret);
-		}
-	}
-
-	return priv;
-}
-
-static int nfs_readlink_req(struct file_priv *priv, char* buf, size_t size)
+static int nfs_readlink_req(struct nfs_priv *npriv, struct nfs_fh *fh,
+			    char **target)
 {
 	uint32_t data[1024];
 	uint32_t *p;
@@ -1095,11 +973,11 @@ static int nfs_readlink_req(struct file_priv *priv, char* buf, size_t size)
 	p = &(data[0]);
 	p = rpc_add_credentials(p);
 
-	p = nfs_add_fh3(p, priv->filefh_len, priv->filefh);
+	p = nfs_add_fh3(p, fh);
 
 	len = p - &(data[0]);
 
-	ret = rpc_req(priv->npriv, PROG_NFS, NFSPROC3_READLINK, data, len);
+	ret = rpc_req(npriv, PROG_NFS, NFSPROC3_READLINK, data, len);
 	if (ret)
 		return ret;
 
@@ -1110,44 +988,37 @@ static int nfs_readlink_req(struct file_priv *priv, char* buf, size_t size)
 	len = ntoh32(net_read_uint32(p)); /* new path length */
 	p++;
 
-	if (len > size)
-		return -ENOMEM;
-
-	memcpy(buf, p, len);
+	*target = xzalloc(len + 1);
+	memcpy(*target, p, len);
 
 	return 0;
 }
 
-static int nfs_readlink(struct device_d *dev, const char *filename,
-			char *realname, size_t size)
+static const char *nfs_get_link(struct dentry *dentry, struct inode *inode)
 {
-	struct file_priv *priv;
+	struct nfs_inode *ninode = nfsi(inode);
+	struct nfs_priv *npriv = ninode->npriv;
 	int ret;
 
-	priv = nfs_do_open(dev, filename, NULL);
-	if (IS_ERR(priv))
-		return PTR_ERR(priv);
-
-	ret = nfs_readlink_req(priv, realname, size);
-	if (ret) {
-		nfs_do_close(priv);
-		return ret;
-	}
+	ret = nfs_readlink_req(npriv, &ninode->fh, &inode->i_link);
+	if (ret)
+		return ERR_PTR(ret);
 
-	return 0;
+	return inode->i_link;
 }
 
 static int nfs_open(struct device_d *dev, FILE *file, const char *filename)
 {
+	struct inode *inode = file->f_inode;
+	struct nfs_inode *ninode = nfsi(inode);
+	struct nfs_priv *npriv = ninode->npriv;
 	struct file_priv *priv;
-	struct stat s;
-
-	priv = nfs_do_stat(dev, filename, &s);
-	if (IS_ERR(priv))
-		return PTR_ERR(priv);
 
+	priv = xzalloc(sizeof(*priv));
+	priv->fh = ninode->fh;
+	priv->npriv = npriv;
 	file->priv = priv;
-	file->size = s.st_size;
+	file->size = inode->i_size;
 
 	priv->fifo = kfifo_alloc(1024);
 	if (!priv->fifo) {
@@ -1199,115 +1070,170 @@ static loff_t nfs_lseek(struct device_d *dev, FILE *file, loff_t pos)
 	return file->pos;
 }
 
-static DIR *nfs_opendir(struct device_d *dev, const char *pathname)
+static int nfs_iterate(struct file *file, struct dir_context *ctx)
 {
-	struct file_priv *priv;
+	struct dentry *dentry = file->f_path.dentry;
+	struct inode *dir = d_inode(dentry);
+	struct nfs_priv *npriv = nfsi(dir)->npriv;
 	void *buf = NULL;
-	struct nfs_dir *dir;
+	struct nfs_dir *ndir;
+	struct xdr_stream *xdr;
+	int ret;
+	uint32_t *p, len;
 
-	priv = nfs_do_open(dev, pathname, NULL);
-	if (IS_ERR(priv))
-		return NULL;
+	ndir = xzalloc(sizeof(*ndir));
+	ndir->fh = nfsi(dir)->fh;
 
-	dir = xzalloc(sizeof(*dir));
-	dir->priv = priv;
+	while (1) {
+		/* cookie == 0 and cookieverf == 0 means start of dir */
+		buf = nfs_readdirattr_req(npriv, ndir);
+		if (!buf) {
+			pr_err("%s: nfs_readdirattr_req failed\n", __func__);
+			ret = -EINVAL;
+			goto out;
+		}
 
-	/* cookie == 0 and cookieverf == 0 means start of dir */
-	buf = nfs_readdirattr_req(priv, dir);
-	if (!buf) {
-		debug("%s: nfs_readdirattr_req failed\n", __func__);
-		goto err;
-	}
+		xdr = &ndir->stream;
 
-	return &dir->dir;
+		while (1) {
+			char name[256];
 
-err:
-	free(buf);
-	free(dir);
-	nfs_do_close(priv);
-	return NULL;
-}
+			p = xdr_inline_decode(xdr, 4);
+			if (!p)
+				goto err_eop;
 
-static struct dirent *nfs_readdir(struct device_d *dev, DIR *dir)
-{
-	struct nfs_dir *ndir = container_of(dir, struct nfs_dir, dir);
-	uint32_t *p;
-	int ret;
-	int len;
-	struct xdr_stream *xdr = &ndir->stream;
+			if (!net_read_uint32(p)) {
+				/* eof? */
+				p = xdr_inline_decode(xdr, 4);
+				if (!p)
+					goto err_eop;
 
-again:
-	p = xdr_inline_decode(xdr, 4);
-	if (!p) {
-		printf("%s: premature end of packet\n", __func__);
-		return NULL;
-	}
+				if (net_read_uint32(p)) {
+					ret = 0;
+					goto out;
+				}
 
-	if (!net_read_uint32(p)) {
-		/* eof? */
-		p = xdr_inline_decode(xdr, 4);
-		if (!p) {
-			printf("%s: premature end of packet\n", __func__);
-			return NULL;
-		}
-		if (net_read_uint32(p))
-			return NULL;
+				break;
+			}
 
-		if (!nfs_readdirattr_req(ndir->priv, ndir)) {
-			printf("%s: nfs_readdirattr_req failed\n", __func__);
-			return NULL;
-		}
+			/* skip over fileid */
+			p = xdr_inline_decode(xdr, 8);
+			if (!p)
+				goto err_eop;
 
-		goto again;
-	}
+			ret = decode_filename(xdr, name, &len);
+			if (ret)
+				goto out;
 
-	/* there is another entry available in the last reply */
+			dir_emit(ctx, name, len, 0, DT_UNKNOWN);
 
-	/* skip over fileid */
-	p = xdr_inline_decode(xdr, 8);
-	if (!p) {
-		printf("%s: premature end of packet\n", __func__);
-		return NULL;
+			p = xdr_inline_decode(xdr, 8);
+			if (!p)
+				goto err_eop;
+
+			ndir->cookie = ntoh64(net_read_uint64(p));
+		}
+		free(buf);
 	}
 
-	ret = decode_filename(xdr, ndir->ent.d_name, &len);
-	if (ret)
-		return NULL;
+	ret = 0;
 
-	p = xdr_inline_decode(xdr, 8);
-	if (!p) {
-		printf("%s: premature end of packet\n", __func__);
+out:
+	free(ndir->stream.buf);
+	free(ndir);
+
+	return ret;
+
+err_eop:
+	pr_err("Unexpected end of packet\n");
+
+	return -EIO;
+}
+
+static struct inode *nfs_alloc_inode(struct super_block *sb)
+{
+	struct nfs_inode *node;
+
+	node = xzalloc(sizeof(*node));
+	if (!node)
 		return NULL;
-	}
-	ndir->cookie = ntoh64(net_read_uint64(p));
 
-	return &ndir->ent;
+	return &node->inode;
 }
 
-static int nfs_closedir(struct device_d *dev, DIR *dir)
+static const struct inode_operations nfs_file_inode_operations;
+static const struct file_operations nfs_dir_operations;
+static const struct inode_operations nfs_dir_inode_operations;
+static const struct file_operations nfs_file_operations;
+static const struct inode_operations nfs_symlink_inode_operations = {
+	.get_link = nfs_get_link,
+};
+
+static int nfs_init_inode(struct nfs_priv *npriv, struct inode *inode,
+			  unsigned int mode)
 {
-	struct nfs_dir *ndir = (void *)dir;
+	struct nfs_inode *ninode = nfsi(inode);
 
-	nfs_do_close(ndir->priv);
-	free(ndir->stream.buf);
-	free(ndir);
+	ninode->npriv = npriv;
+
+	inode->i_ino = get_next_ino();
+	inode->i_mode = mode;
+
+	switch (inode->i_mode & S_IFMT) {
+	default:
+		return -EINVAL;
+	case S_IFREG:
+		inode->i_op = &nfs_file_inode_operations;
+		inode->i_fop = &nfs_file_operations;
+		break;
+	case S_IFDIR:
+		inode->i_op = &nfs_dir_inode_operations;
+		inode->i_fop = &nfs_dir_operations;
+		inc_nlink(inode);
+		break;
+	case S_IFLNK:
+		inode->i_op = &nfs_symlink_inode_operations;
+		break;
+	}
 
 	return 0;
 }
 
-static int nfs_stat(struct device_d *dev, const char *filename, struct stat *s)
+static struct dentry *nfs_lookup(struct inode *dir, struct dentry *dentry,
+				   unsigned int flags)
 {
-	struct file_priv *priv;
+	struct nfs_inode *ndir = nfsi(dir);
+	struct inode *inode = new_inode(dir->i_sb);
+	struct nfs_priv *npriv = ndir->npriv;
+	int ret;
 
-	priv = nfs_do_stat(dev, filename, s);
-	if (IS_ERR(priv)) {
-		return PTR_ERR(priv);
-	} else {
-		nfs_do_close(priv);
-		return 0;
-	}
+	if (!inode)
+		return NULL;
+
+	ret = nfs_lookup_req(npriv, &ndir->fh, dentry->name, inode);
+	if (ret)
+		return NULL;
+
+	nfs_init_inode(npriv, inode, inode->i_mode);
+
+	d_add(dentry, inode);
+
+	return NULL;
 }
 
+static const struct file_operations nfs_dir_operations = {
+	.iterate = nfs_iterate,
+};
+
+static const struct inode_operations nfs_dir_inode_operations =
+{
+	.lookup = nfs_lookup,
+};
+
+static const struct super_operations nfs_ops = {
+	.alloc_inode = nfs_alloc_inode,
+};
+
 static char *rootnfsopts;
 
 static void nfs_set_rootarg(struct nfs_priv *npriv, struct fs_device_d *fsdev)
@@ -1347,8 +1273,10 @@ static int nfs_probe(struct device_d *dev)
 {
 	struct fs_device_d *fsdev = dev_to_fs_device(dev);
 	struct nfs_priv *npriv = xzalloc(sizeof(struct nfs_priv));
+	struct super_block *sb = &fsdev->sb;
 	char *tmp = xstrdup(fsdev->backingstore);
 	char *path;
+	struct inode *inode;
 	int ret;
 
 	dev->priv = npriv;
@@ -1414,6 +1342,13 @@ static int nfs_probe(struct device_d *dev)
 
 	free(tmp);
 
+	sb->s_op = &nfs_ops;
+
+	inode = new_inode(sb);
+	nfs_set_fh(inode, &npriv->rootfh);
+	nfs_init_inode(npriv, inode, S_IFDIR);
+	sb->s_root = d_make_root(inode);
+
 	return 0;
 
 err2:
@@ -1443,17 +1378,8 @@ static struct fs_driver_d nfs_driver = {
 	.close     = nfs_close,
 	.read      = nfs_read,
 	.lseek     = nfs_lseek,
-	.opendir   = nfs_opendir,
-	.readdir   = nfs_readdir,
-	.closedir  = nfs_closedir,
-	.stat      = nfs_stat,
-	.create    = nfs_create,
-	.unlink    = nfs_unlink,
-	.mkdir     = nfs_mkdir,
-	.rmdir     = nfs_rmdir,
 	.write     = nfs_write,
 	.truncate  = nfs_truncate,
-	.readlink  = nfs_readlink,
 	.flags     = 0,
 	.drv = {
 		.probe  = nfs_probe,
-- 
2.16.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 18/19] fs: tftp: Switch to dcache implementation
  2018-04-03  7:48 [PATCH 00/19] Add Linux dcache implementation Sascha Hauer
                   ` (16 preceding siblings ...)
  2018-04-03  7:48 ` [PATCH 17/19] fs: nfs: " Sascha Hauer
@ 2018-04-03  7:48 ` Sascha Hauer
  2018-05-18 11:54   ` Philipp Zabel
  2018-04-03  7:48 ` [PATCH 19/19] block: Adjust cache sizes Sascha Hauer
  18 siblings, 1 reply; 23+ messages in thread
From: Sascha Hauer @ 2018-04-03  7:48 UTC (permalink / raw)
  To: Barebox List

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 fs/Kconfig |  1 -
 fs/tftp.c  | 96 +++++++++++++++++++++++++++++++++++---------------------------
 2 files changed, 55 insertions(+), 42 deletions(-)

diff --git a/fs/Kconfig b/fs/Kconfig
index b2d4242e63..2be883e544 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -29,7 +29,6 @@ config FS_DEVFS
 
 config FS_TFTP
 	bool
-	depends on BROKEN
 	prompt "tftp support"
 	depends on NET
 
diff --git a/fs/tftp.c b/fs/tftp.c
index 847921aa56..753444c459 100644
--- a/fs/tftp.c
+++ b/fs/tftp.c
@@ -89,26 +89,6 @@ struct tftp_priv {
 	IPaddr_t server;
 };
 
-static int tftp_create(struct device_d *dev, const char *pathname, mode_t mode)
-{
-	return 0;
-}
-
-static int tftp_unlink(struct device_d *dev, const char *pathname)
-{
-	return -ENOSYS;
-}
-
-static int tftp_mkdir(struct device_d *dev, const char *pathname)
-{
-	return -ENOSYS;
-}
-
-static int tftp_rmdir(struct device_d *dev, const char *pathname)
-{
-	return -ENOSYS;
-}
-
 static int tftp_truncate(struct device_d *dev, FILE *f, ulong size)
 {
 	return 0;
@@ -466,6 +446,9 @@ out:
 static int tftp_open(struct device_d *dev, FILE *file, const char *filename)
 {
 	struct file_priv *priv;
+	struct fs_device_d *fsdev = dev_to_fs_device(dev);
+
+	filename = dpath(file->dentry, fsdev->vfsmount.mnt_root);
 
 	priv = tftp_do_open(dev, file->flags, filename);
 	if (IS_ERR(priv))
@@ -618,40 +601,77 @@ out_free:
 	return -ENOSYS;
 }
 
-static DIR* tftp_opendir(struct device_d *dev, const char *pathname)
+static const struct inode_operations tftp_file_inode_operations;
+static const struct inode_operations tftp_dir_inode_operations;
+static const struct file_operations tftp_file_operations;
+
+static struct inode *tftp_get_inode(struct super_block *sb, const struct inode *dir,
+                                     umode_t mode)
 {
-	/* not implemented in tftp protocol */
-	return NULL;
+	struct inode *inode = new_inode(sb);
+
+	if (!inode)
+		return NULL;
+
+	inode->i_ino = get_next_ino();
+	inode->i_mode = mode;
+
+	switch (mode & S_IFMT) {
+	default:
+		return NULL;
+	case S_IFREG:
+		inode->i_op = &tftp_file_inode_operations;
+		inode->i_fop = &tftp_file_operations;
+		break;
+	case S_IFDIR:
+		inode->i_op = &tftp_dir_inode_operations;
+		inode->i_fop = &simple_dir_operations;
+		inc_nlink(inode);
+		break;
+	}
+
+	return inode;
 }
 
-static int tftp_stat(struct device_d *dev, const char *filename, struct stat *s)
+static struct dentry *tftp_lookup(struct inode *dir, struct dentry *dentry,
+			    unsigned int flags)
 {
-	struct file_priv *priv;
+	struct inode *inode;
 
-	priv = tftp_do_open(dev, O_RDONLY, filename);
-	if (IS_ERR(priv))
-		return PTR_ERR(priv);
+	printf("Lookup: \"%s\"\n", dentry->name);
 
-	s->st_mode = S_IFREG | S_IRWXU | S_IRWXG | S_IRWXO;
-	if (priv->filesize)
-		s->st_size = priv->filesize;
-	else
-		s->st_size = FILESIZE_MAX;
+	inode = tftp_get_inode(dir->i_sb, dir, S_IFREG | S_IRWXUGO);
+	if (!inode)
+		return ERR_PTR(-ENOSPC);
 
-	tftp_do_close(priv);
+	d_add(dentry, inode);
 
-	return 0;
+	return NULL;
 }
 
+static const struct inode_operations tftp_dir_inode_operations =
+{
+	.lookup = tftp_lookup,
+};
+
+static const struct super_operations tftp_ops;
+
 static int tftp_probe(struct device_d *dev)
 {
 	struct fs_device_d *fsdev = dev_to_fs_device(dev);
 	struct tftp_priv *priv = xzalloc(sizeof(struct tftp_priv));
+	struct super_block *sb = &fsdev->sb;
+	struct inode *inode;
 
 	dev->priv = priv;
 
 	priv->server = resolv(fsdev->backingstore);
 
+	sb->s_op = &tftp_ops;
+
+	inode = tftp_get_inode(sb, NULL, S_IFDIR);
+	sb->s_root = d_make_root(inode);
+
 	return 0;
 }
 
@@ -667,12 +687,6 @@ static struct fs_driver_d tftp_driver = {
 	.close     = tftp_close,
 	.read      = tftp_read,
 	.lseek     = tftp_lseek,
-	.opendir   = tftp_opendir,
-	.stat      = tftp_stat,
-	.create    = tftp_create,
-	.unlink    = tftp_unlink,
-	.mkdir     = tftp_mkdir,
-	.rmdir     = tftp_rmdir,
 	.write     = tftp_write,
 	.truncate  = tftp_truncate,
 	.flags     = 0,
-- 
2.16.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 19/19] block: Adjust cache sizes
  2018-04-03  7:48 [PATCH 00/19] Add Linux dcache implementation Sascha Hauer
                   ` (17 preceding siblings ...)
  2018-04-03  7:48 ` [PATCH 18/19] fs: tftp: " Sascha Hauer
@ 2018-04-03  7:48 ` Sascha Hauer
  18 siblings, 0 replies; 23+ messages in thread
From: Sascha Hauer @ 2018-04-03  7:48 UTC (permalink / raw)
  To: Barebox List

Use four times more cache entries and divide the memory for each entry
by four. This lowers the linear read throughput somewhat but increases
the access speed for filesystems.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 common/block.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/common/block.c b/common/block.c
index 55d8d1637e..219b943afc 100644
--- a/common/block.c
+++ b/common/block.c
@@ -36,7 +36,7 @@ struct chunk {
 	struct list_head list;
 };
 
-#define BUFSIZE (PAGE_SIZE * 16)
+#define BUFSIZE (PAGE_SIZE * 4)
 
 /*
  * Write all dirty chunks back to the device
@@ -361,7 +361,7 @@ int blockdevice_register(struct block_device *blk)
 	debug("%s: rdbufsize: %d blockbits: %d blkmask: 0x%08x\n", __func__, blk->rdbufsize, blk->blockbits,
 			blk->blkmask);
 
-	for (i = 0; i < 8; i++) {
+	for (i = 0; i < 32; i++) {
 		struct chunk *chunk = xzalloc(sizeof(*chunk));
 		chunk->data = dma_alloc(BUFSIZE);
 		chunk->num = i;
-- 
2.16.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 18/19] fs: tftp: Switch to dcache implementation
  2018-04-03  7:48 ` [PATCH 18/19] fs: tftp: " Sascha Hauer
@ 2018-05-18 11:54   ` Philipp Zabel
  2018-05-22  7:12     ` Sascha Hauer
  0 siblings, 1 reply; 23+ messages in thread
From: Philipp Zabel @ 2018-05-18 11:54 UTC (permalink / raw)
  To: Sascha Hauer, Barebox List

Hi Sascha,

On Tue, 2018-04-03 at 09:48 +0200, Sascha Hauer wrote:
[...]
> -static int tftp_stat(struct device_d *dev, const char *filename, struct stat *s)
> +static struct dentry *tftp_lookup(struct inode *dir, struct dentry *dentry,
> +			    unsigned int flags)
>  {
> -	struct file_priv *priv;
> +	struct inode *inode;
>  
> -	priv = tftp_do_open(dev, O_RDONLY, filename);
> -	if (IS_ERR(priv))
> -		return PTR_ERR(priv);
> +	printf("Lookup: \"%s\"\n", dentry->name);
>  
> -	s->st_mode = S_IFREG | S_IRWXU | S_IRWXG | S_IRWXO;
> -	if (priv->filesize)
> -		s->st_size = priv->filesize;
> -	else
> -		s->st_size = FILESIZE_MAX;

With this change, stat() on files on TFTP mounts will return 0 where it
returned FILESIZE_MAX before, if the TFTP server does not send
information about the file size. This causes read_file_2() to fail,
which uses stat() to determine file size. read_file_2() is used for
example by bootm to load the device tree.

> +	inode = tftp_get_inode(dir->i_sb, dir, S_IFREG | S_IRWXUGO);
> +	if (!inode)
> +		return ERR_PTR(-ENOSPC);
>  

Can we just store the fake filesize in the d_inode here?
 
+       if (inode->i_size == 0)
+               inode->i_size = FILESIZE_MAX;
+

> -	tftp_do_close(priv);
> +	d_add(dentry, inode);
>  
> -	return 0;
> +	return NULL;
>  }

regards
Philipp

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 18/19] fs: tftp: Switch to dcache implementation
  2018-05-18 11:54   ` Philipp Zabel
@ 2018-05-22  7:12     ` Sascha Hauer
  2018-05-22  8:21       ` Philipp Zabel
  0 siblings, 1 reply; 23+ messages in thread
From: Sascha Hauer @ 2018-05-22  7:12 UTC (permalink / raw)
  To: Philipp Zabel; +Cc: Barebox List

On Fri, May 18, 2018 at 01:54:13PM +0200, Philipp Zabel wrote:
> Hi Sascha,
> 
> On Tue, 2018-04-03 at 09:48 +0200, Sascha Hauer wrote:
> [...]
> > -static int tftp_stat(struct device_d *dev, const char *filename, struct stat *s)
> > +static struct dentry *tftp_lookup(struct inode *dir, struct dentry *dentry,
> > +			    unsigned int flags)
> >  {
> > -	struct file_priv *priv;
> > +	struct inode *inode;
> >  
> > -	priv = tftp_do_open(dev, O_RDONLY, filename);
> > -	if (IS_ERR(priv))
> > -		return PTR_ERR(priv);
> > +	printf("Lookup: \"%s\"\n", dentry->name);
> >  
> > -	s->st_mode = S_IFREG | S_IRWXU | S_IRWXG | S_IRWXO;
> > -	if (priv->filesize)
> > -		s->st_size = priv->filesize;
> > -	else
> > -		s->st_size = FILESIZE_MAX;
> 
> With this change, stat() on files on TFTP mounts will return 0 where it
> returned FILESIZE_MAX before, if the TFTP server does not send
> information about the file size. This causes read_file_2() to fail,
> which uses stat() to determine file size. read_file_2() is used for
> example by bootm to load the device tree.
> 
> > +	inode = tftp_get_inode(dir->i_sb, dir, S_IFREG | S_IRWXUGO);
> > +	if (!inode)
> > +		return ERR_PTR(-ENOSPC);
> >  
> 
> Can we just store the fake filesize in the d_inode here?
>  
> +       if (inode->i_size == 0)
> +               inode->i_size = FILESIZE_MAX;

Have you tried it? Does it work as expected?

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 18/19] fs: tftp: Switch to dcache implementation
  2018-05-22  7:12     ` Sascha Hauer
@ 2018-05-22  8:21       ` Philipp Zabel
  0 siblings, 0 replies; 23+ messages in thread
From: Philipp Zabel @ 2018-05-22  8:21 UTC (permalink / raw)
  To: Sascha Hauer; +Cc: Barebox List

On Tue, 2018-05-22 at 09:12 +0200, Sascha Hauer wrote:
> On Fri, May 18, 2018 at 01:54:13PM +0200, Philipp Zabel wrote:
> > Hi Sascha,
> > 
> > On Tue, 2018-04-03 at 09:48 +0200, Sascha Hauer wrote:
> > [...]
> > > -static int tftp_stat(struct device_d *dev, const char *filename, struct stat *s)
> > > +static struct dentry *tftp_lookup(struct inode *dir, struct dentry *dentry,
> > > +			    unsigned int flags)
> > >  {
> > > -	struct file_priv *priv;
> > > +	struct inode *inode;
> > >  
> > > -	priv = tftp_do_open(dev, O_RDONLY, filename);
> > > -	if (IS_ERR(priv))
> > > -		return PTR_ERR(priv);
> > > +	printf("Lookup: \"%s\"\n", dentry->name);
> > >  
> > > -	s->st_mode = S_IFREG | S_IRWXU | S_IRWXG | S_IRWXO;
> > > -	if (priv->filesize)
> > > -		s->st_size = priv->filesize;
> > > -	else
> > > -		s->st_size = FILESIZE_MAX;
> > 
> > With this change, stat() on files on TFTP mounts will return 0 where it
> > returned FILESIZE_MAX before, if the TFTP server does not send
> > information about the file size. This causes read_file_2() to fail,
> > which uses stat() to determine file size. read_file_2() is used for
> > example by bootm to load the device tree.
> > 
> > > +	inode = tftp_get_inode(dir->i_sb, dir, S_IFREG | S_IRWXUGO);
> > > +	if (!inode)
> > > +		return ERR_PTR(-ENOSPC);
> > >  
> > 
> > Can we just store the fake filesize in the d_inode here?
> >  
> > +       if (inode->i_size == 0)
> > +               inode->i_size = FILESIZE_MAX;
> 
> Have you tried it? Does it work as expected?

For the case I tested (bootm -o /mnt/tftp/...) it worked as expected.

I'm just not sure if storing the TFTP fake filesize in the d_inode could
have other undesirable side effects.

regards
Philipp

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 23+ messages in thread

end of thread, other threads:[~2018-05-22  8:21 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-04-03  7:48 [PATCH 00/19] Add Linux dcache implementation Sascha Hauer
2018-04-03  7:48 ` [PATCH 01/19] rename file_operations -> cdev_operations Sascha Hauer
2018-04-03  7:48 ` [PATCH 02/19] ubifs: remove dead code Sascha Hauer
2018-04-03  7:48 ` [PATCH 03/19] ubifs: Remove Linux struct definitions we already have Sascha Hauer
2018-04-03  7:48 ` [PATCH 04/19] ubifs: remove dead code Sascha Hauer
2018-04-03  7:48 ` [PATCH 05/19] fs: Add super_operations Sascha Hauer
2018-04-03  7:48 ` [PATCH 06/19] fs: Move mem_write/mem_read to devfs-core Sascha Hauer
2018-04-03  7:48 ` [PATCH 07/19] fs: Cleanup whitespace damage Sascha Hauer
2018-04-03  7:48 ` [PATCH 08/19] fs: Fix finding correct directory for mkdir/rmdir Sascha Hauer
2018-04-03  7:48 ` [PATCH 09/19] glob: do not unnecessarily opendir() a directory Sascha Hauer
2018-04-03  7:48 ` [PATCH 10/19] ls: Do not depend on normalise_path() Sascha Hauer
2018-04-03  7:48 ` [PATCH 11/19] loadenv: " Sascha Hauer
2018-04-03  7:48 ` [PATCH 12/19] fs: dcache implementation Sascha Hauer
2018-04-03  7:48 ` [PATCH 13/19] fs: ramfs: Switch to " Sascha Hauer
2018-04-03  7:48 ` [PATCH 14/19] fs: devfs: " Sascha Hauer
2018-04-03  7:48 ` [PATCH 15/19] fs: ext4: " Sascha Hauer
2018-04-03  7:48 ` [PATCH 16/19] fs: ubifs: " Sascha Hauer
2018-04-03  7:48 ` [PATCH 17/19] fs: nfs: " Sascha Hauer
2018-04-03  7:48 ` [PATCH 18/19] fs: tftp: " Sascha Hauer
2018-05-18 11:54   ` Philipp Zabel
2018-05-22  7:12     ` Sascha Hauer
2018-05-22  8:21       ` Philipp Zabel
2018-04-03  7:48 ` [PATCH 19/19] block: Adjust cache sizes Sascha Hauer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox