2013-09-07 08:36:19

by Marco Stornelli

[permalink] [raw]
Subject: [PATCH 12/19] pramfs: symlink operations

Add symlink operations.

Signed-off-by: Marco Stornelli <[email protected]>
---
fs/pramfs/symlink.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 76 insertions(+), 0 deletions(-)
create mode 100644 fs/pramfs/symlink.c

diff --git a/fs/pramfs/symlink.c b/fs/pramfs/symlink.c
new file mode 100644
index 0000000..0d5213f
--- /dev/null
+++ b/fs/pramfs/symlink.c
@@ -0,0 +1,76 @@
+/*
+ * BRIEF DESCRIPTION
+ *
+ * Symlink operations
+ *
+ * Copyright 2009-2011 Marco Stornelli <[email protected]>
+ * Copyright 2003 Sony Corporation
+ * Copyright 2003 Matsushita Electric Industrial Co., Ltd.
+ * 2003-2004 (c) MontaVista Software, Inc. , Steve Longerbeam
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/fs.h>
+#include "pram.h"
+#include "xattr.h"
+
+int pram_block_symlink(struct inode *inode, const char *symname, int len)
+{
+ struct super_block *sb = inode->i_sb;
+ u64 block;
+ char *blockp;
+ int err;
+
+ err = pram_alloc_blocks(inode, 0, 1);
+ if (err)
+ return err;
+
+ block = pram_find_data_block(inode, 0);
+ blockp = pram_get_block(sb, block);
+
+ pram_memunlock_block(sb, blockp);
+ memcpy(blockp, symname, len);
+ blockp[len] = '\0';
+ pram_memlock_block(sb, blockp);
+ return 0;
+}
+
+static int pram_readlink(struct dentry *dentry, char __user *buffer, int buflen)
+{
+ struct inode *inode = dentry->d_inode;
+ struct super_block *sb = inode->i_sb;
+ u64 block;
+ char *blockp;
+
+ block = pram_find_data_block(inode, 0);
+ blockp = pram_get_block(sb, block);
+ return vfs_readlink(dentry, buffer, buflen, blockp);
+}
+
+static void *pram_follow_link(struct dentry *dentry, struct nameidata *nd)
+{
+ struct inode *inode = dentry->d_inode;
+ struct super_block *sb = inode->i_sb;
+ off_t block;
+ int status;
+ char *blockp;
+
+ block = pram_find_data_block(inode, 0);
+ blockp = pram_get_block(sb, block);
+ status = vfs_follow_link(nd, blockp);
+ return ERR_PTR(status);
+}
+
+const struct inode_operations pram_symlink_inode_operations = {
+ .readlink = pram_readlink,
+ .follow_link = pram_follow_link,
+ .setattr = pram_notify_change,
+#ifdef CONFIG_PRAMFS_XATTR
+ .setxattr = generic_setxattr,
+ .getxattr = generic_getxattr,
+ .listxattr = pram_listxattr,
+ .removexattr = generic_removexattr,
+#endif
+};
--
1.7.3.4


2013-09-07 14:41:27

by Al Viro

[permalink] [raw]
Subject: Re: [PATCH 12/19] pramfs: symlink operations

On Sat, Sep 07, 2013 at 10:29:15AM +0200, Marco Stornelli wrote:
> +static int pram_readlink(struct dentry *dentry, char __user *buffer, int buflen)
> +{
> + struct inode *inode = dentry->d_inode;
> + struct super_block *sb = inode->i_sb;
> + u64 block;
> + char *blockp;
> +
> + block = pram_find_data_block(inode, 0);
> + blockp = pram_get_block(sb, block);
> + return vfs_readlink(dentry, buffer, buflen, blockp);
> +}

> +static void *pram_follow_link(struct dentry *dentry, struct nameidata *nd)
> +{
> + struct inode *inode = dentry->d_inode;
> + struct super_block *sb = inode->i_sb;
> + off_t block;
> + int status;
> + char *blockp;
> +
> + block = pram_find_data_block(inode, 0);
> + blockp = pram_get_block(sb, block);
> + status = vfs_follow_link(nd, blockp);
> + return ERR_PTR(status);
> +}

Just nd_set_link(nd, blockp) instead of that vfs_follow_link() and be
done with that; that way you can use generic_readlink() instead of
pram_readlink() *and* get lower stack footprint on traversing them.

BTW, where's the error checking? pram_get_block()/pram_find_data_block()
seem to assume that fs image isn't corrupted and if it is... that code
will happily dereference any address. At least range checks of some sort
in pram_get_block() (and checking if it has failed) would be a good idea...

2013-09-07 16:16:33

by Marco Stornelli

[permalink] [raw]
Subject: Re: [PATCH 12/19] pramfs: symlink operations

Il 07/09/2013 16:41, Al Viro ha scritto:
> On Sat, Sep 07, 2013 at 10:29:15AM +0200, Marco Stornelli wrote:
>> +static int pram_readlink(struct dentry *dentry, char __user *buffer, int buflen)
>> +{
>> + struct inode *inode = dentry->d_inode;
>> + struct super_block *sb = inode->i_sb;
>> + u64 block;
>> + char *blockp;
>> +
>> + block = pram_find_data_block(inode, 0);
>> + blockp = pram_get_block(sb, block);
>> + return vfs_readlink(dentry, buffer, buflen, blockp);
>> +}
>
>> +static void *pram_follow_link(struct dentry *dentry, struct nameidata *nd)
>> +{
>> + struct inode *inode = dentry->d_inode;
>> + struct super_block *sb = inode->i_sb;
>> + off_t block;
>> + int status;
>> + char *blockp;
>> +
>> + block = pram_find_data_block(inode, 0);
>> + blockp = pram_get_block(sb, block);
>> + status = vfs_follow_link(nd, blockp);
>> + return ERR_PTR(status);
>> +}
>
> Just nd_set_link(nd, blockp) instead of that vfs_follow_link() and be
> done with that; that way you can use generic_readlink() instead of
> pram_readlink() *and* get lower stack footprint on traversing them.
>
>

Yep, you're right (as usual :))

Marco