diff options
Diffstat (limited to 'fs/libfs.c')
| -rw-r--r-- | fs/libfs.c | 168 | 
1 files changed, 125 insertions, 43 deletions
diff --git a/fs/libfs.c b/fs/libfs.c index 3a3a9b53bf5..88e3e00e2ec 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -3,6 +3,7 @@   *	Library for filesystems writers.   */ +#include <linux/blkdev.h>  #include <linux/export.h>  #include <linux/pagemap.h>  #include <linux/slab.h> @@ -10,6 +11,7 @@  #include <linux/vfs.h>  #include <linux/quotaops.h>  #include <linux/mutex.h> +#include <linux/namei.h>  #include <linux/exportfs.h>  #include <linux/writeback.h>  #include <linux/buffer_head.h> /* sync_mapping_buffers */ @@ -31,6 +33,7 @@ int simple_getattr(struct vfsmount *mnt, struct dentry *dentry,  	stat->blocks = inode->i_mapping->nrpages << (PAGE_CACHE_SHIFT - 9);  	return 0;  } +EXPORT_SYMBOL(simple_getattr);  int simple_statfs(struct dentry *dentry, struct kstatfs *buf)  { @@ -39,15 +42,22 @@ int simple_statfs(struct dentry *dentry, struct kstatfs *buf)  	buf->f_namelen = NAME_MAX;  	return 0;  } +EXPORT_SYMBOL(simple_statfs);  /*   * Retaining negative dentries for an in-memory filesystem just wastes   * memory and lookup time: arrange for them to be deleted immediately.   */ -static int simple_delete_dentry(const struct dentry *dentry) +int always_delete_dentry(const struct dentry *dentry)  {  	return 1;  } +EXPORT_SYMBOL(always_delete_dentry); + +const struct dentry_operations simple_dentry_operations = { +	.d_delete = always_delete_dentry, +}; +EXPORT_SYMBOL(simple_dentry_operations);  /*   * Lookup the data. This is trivial - if the dentry didn't already @@ -55,10 +65,6 @@ static int simple_delete_dentry(const struct dentry *dentry)   */  struct dentry *simple_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)  { -	static const struct dentry_operations simple_dentry_operations = { -		.d_delete = simple_delete_dentry, -	}; -  	if (dentry->d_name.len > NAME_MAX)  		return ERR_PTR(-ENAMETOOLONG);  	if (!dentry->d_sb->s_d_op) @@ -66,6 +72,7 @@ struct dentry *simple_lookup(struct inode *dir, struct dentry *dentry, unsigned  	d_add(dentry, NULL);  	return NULL;  } +EXPORT_SYMBOL(simple_lookup);  int dcache_dir_open(struct inode *inode, struct file *file)  { @@ -75,12 +82,14 @@ int dcache_dir_open(struct inode *inode, struct file *file)  	return file->private_data ? 0 : -ENOMEM;  } +EXPORT_SYMBOL(dcache_dir_open);  int dcache_dir_close(struct inode *inode, struct file *file)  {  	dput(file->private_data);  	return 0;  } +EXPORT_SYMBOL(dcache_dir_close);  loff_t dcache_dir_lseek(struct file *file, loff_t offset, int whence)  { @@ -123,6 +132,7 @@ loff_t dcache_dir_lseek(struct file *file, loff_t offset, int whence)  	mutex_unlock(&dentry->d_inode->i_mutex);  	return offset;  } +EXPORT_SYMBOL(dcache_dir_lseek);  /* Relationship between i_mode and the DT_xxx types */  static inline unsigned char dt_type(struct inode *inode) @@ -172,11 +182,13 @@ int dcache_readdir(struct file *file, struct dir_context *ctx)  	spin_unlock(&dentry->d_lock);  	return 0;  } +EXPORT_SYMBOL(dcache_readdir);  ssize_t generic_read_dir(struct file *filp, char __user *buf, size_t siz, loff_t *ppos)  {  	return -EISDIR;  } +EXPORT_SYMBOL(generic_read_dir);  const struct file_operations simple_dir_operations = {  	.open		= dcache_dir_open, @@ -186,10 +198,12 @@ const struct file_operations simple_dir_operations = {  	.iterate	= dcache_readdir,  	.fsync		= noop_fsync,  }; +EXPORT_SYMBOL(simple_dir_operations);  const struct inode_operations simple_dir_inode_operations = {  	.lookup		= simple_lookup,  }; +EXPORT_SYMBOL(simple_dir_inode_operations);  static const struct super_operations simple_super_operations = {  	.statfs		= simple_statfs, @@ -244,6 +258,7 @@ Enomem:  	deactivate_locked_super(s);  	return ERR_PTR(-ENOMEM);  } +EXPORT_SYMBOL(mount_pseudo);  int simple_open(struct inode *inode, struct file *file)  { @@ -251,6 +266,7 @@ int simple_open(struct inode *inode, struct file *file)  		file->private_data = inode->i_private;  	return 0;  } +EXPORT_SYMBOL(simple_open);  int simple_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)  { @@ -263,6 +279,7 @@ int simple_link(struct dentry *old_dentry, struct inode *dir, struct dentry *den  	d_instantiate(dentry, inode);  	return 0;  } +EXPORT_SYMBOL(simple_link);  int simple_empty(struct dentry *dentry)  { @@ -283,6 +300,7 @@ out:  	spin_unlock(&dentry->d_lock);  	return ret;  } +EXPORT_SYMBOL(simple_empty);  int simple_unlink(struct inode *dir, struct dentry *dentry)  { @@ -293,6 +311,7 @@ int simple_unlink(struct inode *dir, struct dentry *dentry)  	dput(dentry);  	return 0;  } +EXPORT_SYMBOL(simple_unlink);  int simple_rmdir(struct inode *dir, struct dentry *dentry)  { @@ -304,6 +323,7 @@ int simple_rmdir(struct inode *dir, struct dentry *dentry)  	drop_nlink(dir);  	return 0;  } +EXPORT_SYMBOL(simple_rmdir);  int simple_rename(struct inode *old_dir, struct dentry *old_dentry,  		struct inode *new_dir, struct dentry *new_dentry) @@ -330,6 +350,7 @@ int simple_rename(struct inode *old_dir, struct dentry *old_dentry,  	return 0;  } +EXPORT_SYMBOL(simple_rename);  /**   * simple_setattr - setattr for simple filesystem @@ -370,6 +391,7 @@ int simple_readpage(struct file *file, struct page *page)  	unlock_page(page);  	return 0;  } +EXPORT_SYMBOL(simple_readpage);  int simple_write_begin(struct file *file, struct address_space *mapping,  			loff_t pos, unsigned len, unsigned flags, @@ -393,6 +415,7 @@ int simple_write_begin(struct file *file, struct address_space *mapping,  	}  	return 0;  } +EXPORT_SYMBOL(simple_write_begin);  /**   * simple_write_end - .write_end helper for non-block-device FSes @@ -444,6 +467,7 @@ int simple_write_end(struct file *file, struct address_space *mapping,  	return copied;  } +EXPORT_SYMBOL(simple_write_end);  /*   * the inodes created here are not hashed. If you use iunique to generate @@ -512,6 +536,7 @@ out:  	dput(root);  	return -ENOMEM;  } +EXPORT_SYMBOL(simple_fill_super);  static DEFINE_SPINLOCK(pin_fs_lock); @@ -534,6 +559,7 @@ int simple_pin_fs(struct file_system_type *type, struct vfsmount **mount, int *c  	mntput(mnt);  	return 0;  } +EXPORT_SYMBOL(simple_pin_fs);  void simple_release_fs(struct vfsmount **mount, int *count)  { @@ -545,6 +571,7 @@ void simple_release_fs(struct vfsmount **mount, int *count)  	spin_unlock(&pin_fs_lock);  	mntput(mnt);  } +EXPORT_SYMBOL(simple_release_fs);  /**   * simple_read_from_buffer - copy data from the buffer to user space @@ -579,6 +606,7 @@ ssize_t simple_read_from_buffer(void __user *to, size_t count, loff_t *ppos,  	*ppos = pos + count;  	return count;  } +EXPORT_SYMBOL(simple_read_from_buffer);  /**   * simple_write_to_buffer - copy data from user space to the buffer @@ -613,6 +641,7 @@ ssize_t simple_write_to_buffer(void *to, size_t available, loff_t *ppos,  	*ppos = pos + count;  	return count;  } +EXPORT_SYMBOL(simple_write_to_buffer);  /**   * memory_read_from_buffer - copy data from the buffer @@ -644,6 +673,7 @@ ssize_t memory_read_from_buffer(void *to, size_t count, loff_t *ppos,  	return count;  } +EXPORT_SYMBOL(memory_read_from_buffer);  /*   * Transaction based IO. @@ -665,6 +695,7 @@ void simple_transaction_set(struct file *file, size_t n)  	smp_mb();  	ar->size = n;  } +EXPORT_SYMBOL(simple_transaction_set);  char *simple_transaction_get(struct file *file, const char __user *buf, size_t size)  { @@ -696,6 +727,7 @@ char *simple_transaction_get(struct file *file, const char __user *buf, size_t s  	return ar->data;  } +EXPORT_SYMBOL(simple_transaction_get);  ssize_t simple_transaction_read(struct file *file, char __user *buf, size_t size, loff_t *pos)  { @@ -705,12 +737,14 @@ ssize_t simple_transaction_read(struct file *file, char __user *buf, size_t size  		return 0;  	return simple_read_from_buffer(buf, size, pos, ar->data, ar->size);  } +EXPORT_SYMBOL(simple_transaction_read);  int simple_transaction_release(struct inode *inode, struct file *file)  {  	free_page((unsigned long)file->private_data);  	return 0;  } +EXPORT_SYMBOL(simple_transaction_release);  /* Simple attribute files */ @@ -746,12 +780,14 @@ int simple_attr_open(struct inode *inode, struct file *file,  	return nonseekable_open(inode, file);  } +EXPORT_SYMBOL_GPL(simple_attr_open);  int simple_attr_release(struct inode *inode, struct file *file)  {  	kfree(file->private_data);  	return 0;  } +EXPORT_SYMBOL_GPL(simple_attr_release);	/* GPL-only?  This?  Really? */  /* read from the buffer that is filled with the get function */  ssize_t simple_attr_read(struct file *file, char __user *buf, @@ -787,6 +823,7 @@ out:  	mutex_unlock(&attr->mutex);  	return ret;  } +EXPORT_SYMBOL_GPL(simple_attr_read);  /* interpret the buffer as a number to call the set function with */  ssize_t simple_attr_write(struct file *file, const char __user *buf, @@ -819,6 +856,7 @@ out:  	mutex_unlock(&attr->mutex);  	return ret;  } +EXPORT_SYMBOL_GPL(simple_attr_write);  /**   * generic_fh_to_dentry - generic helper for the fh_to_dentry export operation @@ -886,16 +924,19 @@ struct dentry *generic_fh_to_parent(struct super_block *sb, struct fid *fid,  EXPORT_SYMBOL_GPL(generic_fh_to_parent);  /** - * generic_file_fsync - generic fsync implementation for simple filesystems + * __generic_file_fsync - generic fsync implementation for simple filesystems + *   * @file:	file to synchronize + * @start:	start offset in bytes + * @end:	end offset in bytes (inclusive)   * @datasync:	only synchronize essential metadata if true   *   * This is a generic implementation of the fsync method for simple   * filesystems which track all non-inode metadata in the buffers list   * hanging off the address_space structure.   */ -int generic_file_fsync(struct file *file, loff_t start, loff_t end, -		       int datasync) +int __generic_file_fsync(struct file *file, loff_t start, loff_t end, +				 int datasync)  {  	struct inode *inode = file->f_mapping->host;  	int err; @@ -915,10 +956,34 @@ int generic_file_fsync(struct file *file, loff_t start, loff_t end,  	err = sync_inode_metadata(inode, 1);  	if (ret == 0)  		ret = err; +  out:  	mutex_unlock(&inode->i_mutex);  	return ret;  } +EXPORT_SYMBOL(__generic_file_fsync); + +/** + * generic_file_fsync - generic fsync implementation for simple filesystems + *			with flush + * @file:	file to synchronize + * @start:	start offset in bytes + * @end:	end offset in bytes (inclusive) + * @datasync:	only synchronize essential metadata if true + * + */ + +int generic_file_fsync(struct file *file, loff_t start, loff_t end, +		       int datasync) +{ +	struct inode *inode = file->f_mapping->host; +	int err; + +	err = __generic_file_fsync(file, start, end, datasync); +	if (err) +		return err; +	return blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL); +}  EXPORT_SYMBOL(generic_file_fsync);  /** @@ -957,39 +1022,56 @@ int noop_fsync(struct file *file, loff_t start, loff_t end, int datasync)  {  	return 0;  } - -EXPORT_SYMBOL(dcache_dir_close); -EXPORT_SYMBOL(dcache_dir_lseek); -EXPORT_SYMBOL(dcache_dir_open); -EXPORT_SYMBOL(dcache_readdir); -EXPORT_SYMBOL(generic_read_dir); -EXPORT_SYMBOL(mount_pseudo); -EXPORT_SYMBOL(simple_write_begin); -EXPORT_SYMBOL(simple_write_end); -EXPORT_SYMBOL(simple_dir_inode_operations); -EXPORT_SYMBOL(simple_dir_operations); -EXPORT_SYMBOL(simple_empty); -EXPORT_SYMBOL(simple_fill_super); -EXPORT_SYMBOL(simple_getattr); -EXPORT_SYMBOL(simple_open); -EXPORT_SYMBOL(simple_link); -EXPORT_SYMBOL(simple_lookup); -EXPORT_SYMBOL(simple_pin_fs); -EXPORT_SYMBOL(simple_readpage); -EXPORT_SYMBOL(simple_release_fs); -EXPORT_SYMBOL(simple_rename); -EXPORT_SYMBOL(simple_rmdir); -EXPORT_SYMBOL(simple_statfs);  EXPORT_SYMBOL(noop_fsync); -EXPORT_SYMBOL(simple_unlink); -EXPORT_SYMBOL(simple_read_from_buffer); -EXPORT_SYMBOL(simple_write_to_buffer); -EXPORT_SYMBOL(memory_read_from_buffer); -EXPORT_SYMBOL(simple_transaction_set); -EXPORT_SYMBOL(simple_transaction_get); -EXPORT_SYMBOL(simple_transaction_read); -EXPORT_SYMBOL(simple_transaction_release); -EXPORT_SYMBOL_GPL(simple_attr_open); -EXPORT_SYMBOL_GPL(simple_attr_release); -EXPORT_SYMBOL_GPL(simple_attr_read); -EXPORT_SYMBOL_GPL(simple_attr_write); + +void kfree_put_link(struct dentry *dentry, struct nameidata *nd, +				void *cookie) +{ +	char *s = nd_get_link(nd); +	if (!IS_ERR(s)) +		kfree(s); +} +EXPORT_SYMBOL(kfree_put_link); + +/* + * nop .set_page_dirty method so that people can use .page_mkwrite on + * anon inodes. + */ +static int anon_set_page_dirty(struct page *page) +{ +	return 0; +}; + +/* + * A single inode exists for all anon_inode files. Contrary to pipes, + * anon_inode inodes have no associated per-instance data, so we need + * only allocate one of them. + */ +struct inode *alloc_anon_inode(struct super_block *s) +{ +	static const struct address_space_operations anon_aops = { +		.set_page_dirty = anon_set_page_dirty, +	}; +	struct inode *inode = new_inode_pseudo(s); + +	if (!inode) +		return ERR_PTR(-ENOMEM); + +	inode->i_ino = get_next_ino(); +	inode->i_mapping->a_ops = &anon_aops; + +	/* +	 * Mark the inode dirty from the very beginning, +	 * that way it will never be moved to the dirty +	 * list because mark_inode_dirty() will think +	 * that it already _is_ on the dirty list. +	 */ +	inode->i_state = I_DIRTY; +	inode->i_mode = S_IRUSR | S_IWUSR; +	inode->i_uid = current_fsuid(); +	inode->i_gid = current_fsgid(); +	inode->i_flags |= S_PRIVATE; +	inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; +	return inode; +} +EXPORT_SYMBOL(alloc_anon_inode);  | 
