pramfs: symlink operations
PATCH 12/19 pramfs: symlink operations
Add symlink operations.
--- fs/pramfs/symlink.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 76 insertions(+), 0 deletions(-) create mode 100644 fs/pramfs/symlink.c
fs/pramfs/symlink.c new file +76 -0
@@ -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 +};
Signature · 1 line
1.7.3.4
Al Viro
maintainerQuoted 15 lines · Marco Stornelli
fs/pramfs/symlink.c new file +14
-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;
fs/pramfs/symlink.c line 64
Quoted 10 lines
fs/pramfs/symlink.c new file +10
-0+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...
Il 07/09/2013 16:41, Al Viro ha scritto:
Quoted 22 lines · Marco Stornelli
Quoted 21 lines
fs/pramfs/symlink.c new file +20
-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 );
Quoted 10 lines
fs/pramfs/symlink.c line 64
Quoted 4 lines
fs/pramfs/symlink.c new file +4
-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 thatvfs_follow_link()and be done with that; that way you can usegeneric_readlink()instead ofpram_readlink()*and* get lower stack footprint on traversing them.
Yep, you're right (as usual :))
Marco