Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S936399AbWLDMi7 (ORCPT ); Mon, 4 Dec 2006 07:38:59 -0500 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S936361AbWLDMgH (ORCPT ); Mon, 4 Dec 2006 07:36:07 -0500 Received: from filer.fsl.cs.sunysb.edu ([130.245.126.2]:11999 "EHLO filer.fsl.cs.sunysb.edu") by vger.kernel.org with ESMTP id S936350AbWLDMfw (ORCPT ); Mon, 4 Dec 2006 07:35:52 -0500 From: "Josef 'Jeff' Sipek" To: linux-kernel@vger.kernel.org Cc: torvalds@osdl.org, akpm@osdl.org, hch@infradead.org, viro@ftp.linux.org.uk, linux-fsdevel@vger.kernel.org, mhalcrow@us.ibm.com, Josef "Jeff" Sipek Subject: [PATCH 18/35] Unionfs: File operations Date: Mon, 4 Dec 2006 07:30:51 -0500 Message-Id: <1165235470144-git-send-email-jsipek@cs.sunysb.edu> X-Mailer: git-send-email 1.4.3.3 In-Reply-To: <1165235468365-git-send-email-jsipek@cs.sunysb.edu> References: <1165235468365-git-send-email-jsipek@cs.sunysb.edu> Sender: linux-kernel-owner@vger.kernel.org X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 7137 Lines: 283 From: Josef "Jeff" Sipek This patch provides the file operations for Unionfs. Signed-off-by: Josef "Jeff" Sipek Signed-off-by: David Quigley Signed-off-by: Erez Zadok --- fs/unionfs/file.c | 258 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 258 insertions(+), 0 deletions(-) diff --git a/fs/unionfs/file.c b/fs/unionfs/file.c new file mode 100644 index 0000000..3dc9f8f --- /dev/null +++ b/fs/unionfs/file.c @@ -0,0 +1,258 @@ +/* + * Copyright (c) 2003-2006 Erez Zadok + * Copyright (c) 2003-2006 Charles P. Wright + * Copyright (c) 2005-2006 Josef 'Jeff' Sipek + * Copyright (c) 2005-2006 Junjiro Okajima + * Copyright (c) 2005 Arun M. Krishnakumar + * Copyright (c) 2004-2006 David P. Quigley + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair + * Copyright (c) 2003 Puja Gupta + * Copyright (c) 2003 Harikesavan Krishnan + * Copyright (c) 2003-2006 Stony Brook University + * Copyright (c) 2003-2006 The Research Foundation of State University of New York + * + * 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. + */ + +#include "union.h" + +/* declarations for sparse */ +extern ssize_t unionfs_read(struct file *, char __user *, size_t, loff_t *); +extern ssize_t unionfs_write(struct file *, const char __user *, size_t, + loff_t *); + +/******************* + * File Operations * + *******************/ + +static loff_t unionfs_llseek(struct file *file, loff_t offset, int origin) +{ + loff_t err; + struct file *hidden_file = NULL; + + if ((err = unionfs_file_revalidate(file, 0))) + goto out; + + hidden_file = unionfs_lower_file(file); + /* always set hidden position to this one */ + hidden_file->f_pos = file->f_pos; + + memcpy(&hidden_file->f_ra, &file->f_ra, sizeof(struct file_ra_state)); + + if (hidden_file->f_op && hidden_file->f_op->llseek) + err = hidden_file->f_op->llseek(hidden_file, offset, origin); + else + err = generic_file_llseek(hidden_file, offset, origin); + + if (err < 0) + goto out; + if (err != file->f_pos) { + file->f_pos = err; + file->f_version++; + } +out: + return err; +} + +ssize_t unionfs_read(struct file * file, char __user * buf, size_t count, + loff_t * ppos) +{ + struct file *hidden_file; + loff_t pos = *ppos; + int err; + + if ((err = unionfs_file_revalidate(file, 0))) + goto out; + + err = -EINVAL; + hidden_file = unionfs_lower_file(file); + if (!hidden_file->f_op || !hidden_file->f_op->read) + goto out; + + err = hidden_file->f_op->read(hidden_file, buf, count, &pos); + *ppos = pos; + +out: + return err; +} + +ssize_t __unionfs_write(struct file * file, const char __user * buf, + size_t count, loff_t * ppos) +{ + int err = -EINVAL; + struct file *hidden_file = NULL; + struct inode *inode; + struct inode *hidden_inode; + loff_t pos = *ppos; + int bstart, bend; + + inode = file->f_dentry->d_inode; + + bstart = fbstart(file); + bend = fbend(file); + + BUG_ON(bstart == -1); + + hidden_file = unionfs_lower_file(file); + hidden_inode = hidden_file->f_dentry->d_inode; + + if (!hidden_file->f_op || !hidden_file->f_op->write) + goto out; + + /* adjust for append -- seek to the end of the file */ + if (file->f_flags & O_APPEND) + pos = inode->i_size; + + err = hidden_file->f_op->write(hidden_file, buf, count, &pos); + + /* + * copy ctime and mtime from lower layer attributes + * atime is unchanged for both layers + */ + if (err >= 0) + fsstack_copy_attr_times(inode, hidden_inode); + + *ppos = pos; + + /* update this inode's size */ + if (pos > inode->i_size) + inode->i_size = pos; +out: + return err; +} + +ssize_t unionfs_write(struct file * file, const char __user * buf, size_t count, + loff_t * ppos) +{ + int err = 0; + + if ((err = unionfs_file_revalidate(file, 1))) + goto out; + + err = __unionfs_write(file, buf, count, ppos); + +out: + return err; +} + +static int unionfs_file_readdir(struct file *file, void *dirent, + filldir_t filldir) +{ + return -ENOTDIR; +} + +static unsigned int unionfs_poll(struct file *file, poll_table * wait) +{ + unsigned int mask = DEFAULT_POLLMASK; + struct file *hidden_file = NULL; + + if (unionfs_file_revalidate(file, 0)) { + /* We should pretend an error happend. */ + mask = POLLERR | POLLIN | POLLOUT; + goto out; + } + + hidden_file = unionfs_lower_file(file); + + if (!hidden_file->f_op || !hidden_file->f_op->poll) + goto out; + + mask = hidden_file->f_op->poll(hidden_file, wait); + +out: + return mask; +} + +static int __do_mmap(struct file *file, struct vm_area_struct *vma) +{ + int err; + struct file *hidden_file; + + hidden_file = unionfs_lower_file(file); + + err = -ENODEV; + if (!hidden_file->f_op || !hidden_file->f_op->mmap) + goto out; + + vma->vm_file = hidden_file; + err = hidden_file->f_op->mmap(hidden_file, vma); + get_file(hidden_file); /* make sure it doesn't get freed on us */ + fput(file); /* no need to keep extra ref on ours */ +out: + return err; +} + +static int unionfs_mmap(struct file *file, struct vm_area_struct *vma) +{ + int err = 0; + int willwrite; + + /* This might could be deferred to mmap's writepage. */ + willwrite = ((vma->vm_flags | VM_SHARED | VM_WRITE) == vma->vm_flags); + if ((err = unionfs_file_revalidate(file, willwrite))) + goto out; + + err = __do_mmap(file, vma); + +out: + return err; +} + +static int unionfs_fsync(struct file *file, struct dentry *dentry, int datasync) +{ + int err; + struct file *hidden_file = NULL; + + if ((err = unionfs_file_revalidate(file, 1))) + goto out; + + hidden_file = unionfs_lower_file(file); + + err = -EINVAL; + if (!hidden_file->f_op || !hidden_file->f_op->fsync) + goto out; + + mutex_lock(&hidden_file->f_dentry->d_inode->i_mutex); + err = hidden_file->f_op->fsync(hidden_file, hidden_file->f_dentry, + datasync); + mutex_unlock(&hidden_file->f_dentry->d_inode->i_mutex); + +out: + return err; +} + +/* SP: disabled as none of the other in kernel fs's seem to use it */ +static int unionfs_fasync(int fd, struct file *file, int flag) +{ + int err = 0; + struct file *hidden_file = NULL; + + if ((err = unionfs_file_revalidate(file, 1))) + goto out; + + hidden_file = unionfs_lower_file(file); + + if (hidden_file->f_op && hidden_file->f_op->fasync) + err = hidden_file->f_op->fasync(fd, hidden_file, flag); + +out: + return err; +} + +struct file_operations unionfs_main_fops = { + .llseek = unionfs_llseek, + .read = unionfs_read, + .write = unionfs_write, + .readdir = unionfs_file_readdir, + .poll = unionfs_poll, + .unlocked_ioctl = unionfs_ioctl, + .mmap = unionfs_mmap, + .open = unionfs_open, + .flush = unionfs_flush, + .release = unionfs_file_release, + .fsync = unionfs_fsync, + .fasync = unionfs_fasync, +}; + -- 1.4.3.3 - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/