X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=fs%2Fnfs%2Ffile.c;h=02deae074c6f54d73b0e0f9daa7ed7c09770c72d;hb=902d44426afe46356253fe93d8cef2b4d9f236f3;hp=91bd05377c003251ae1adfb33d5174049824c3e9;hpb=a91482bdcc2e0f6035702e46f1b99043a0893346;p=linux-2.6.git diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 91bd05377..02deae074 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -33,6 +33,8 @@ #define NFSDBG_FACILITY NFSDBG_FILE +static long nfs_file_fcntl(int fd, unsigned int cmd, + unsigned long arg, struct file *filp); static int nfs_file_open(struct inode *, struct file *); static int nfs_file_release(struct inode *, struct file *); static int nfs_file_mmap(struct file *, struct vm_area_struct *); @@ -41,7 +43,6 @@ static ssize_t nfs_file_read(struct kiocb *, char __user *, size_t, loff_t); static ssize_t nfs_file_write(struct kiocb *, const char __user *, size_t, loff_t); static int nfs_file_flush(struct file *); static int nfs_fsync(struct file *, struct dentry *dentry, int datasync); -static int nfs_check_flags(int flags); struct file_operations nfs_file_operations = { .llseek = remote_llseek, @@ -56,7 +57,7 @@ struct file_operations nfs_file_operations = { .fsync = nfs_fsync, .lock = nfs_lock, .sendfile = nfs_file_sendfile, - .check_flags = nfs_check_flags, + .fcntl = nfs_file_fcntl, }; struct inode_operations nfs_file_inode_operations = { @@ -70,12 +71,26 @@ struct inode_operations nfs_file_inode_operations = { # define IS_SWAPFILE(inode) (0) #endif -static int nfs_check_flags(int flags) +#define nfs_invalid_flags (O_APPEND | O_DIRECT) + +/* + * Check for special cases that NFS doesn't support, and + * pass the rest to the generic fcntl function. + */ +static long +nfs_file_fcntl(int fd, unsigned int cmd, + unsigned long arg, struct file *filp) { - if ((flags & (O_APPEND | O_DIRECT)) == (O_APPEND | O_DIRECT)) - return -EINVAL; + switch (cmd) { + case F_SETFL: + if ((filp->f_flags & nfs_invalid_flags) == nfs_invalid_flags) + return -EINVAL; + break; + default: + break; + } - return 0; + return generic_file_fcntl(fd, cmd, arg, filp); } /* @@ -86,11 +101,10 @@ nfs_file_open(struct inode *inode, struct file *filp) { struct nfs_server *server = NFS_SERVER(inode); int (*open)(struct inode *, struct file *); - int res; + int res = 0; - res = nfs_check_flags(filp->f_flags); - if (res) - return res; + if ((filp->f_flags & nfs_invalid_flags) == nfs_invalid_flags) + return -EINVAL; lock_kernel(); /* Do NFSv4 open() call */ @@ -156,7 +170,163 @@ nfs_file_read(struct kiocb *iocb, char __user * buf, size_t count, loff_t pos) } static ssize_t -nfs_file_sendfile(struct file *f +nfs_file_sendfile(struct file *filp, loff_t *ppos, size_t count, + read_actor_t actor, void *target) +{ + struct dentry *dentry = filp->f_dentry; + struct inode *inode = dentry->d_inode; + ssize_t res; + + dfprintk(VFS, "nfs: sendfile(%s/%s, %lu@%Lu)\n", + dentry->d_parent->d_name.name, dentry->d_name.name, + (unsigned long) count, (unsigned long long) *ppos); + + res = nfs_revalidate_inode(NFS_SERVER(inode), inode); + if (!res) + res = generic_file_sendfile(filp, ppos, count, actor, target); + return res; +} + +static int +nfs_file_mmap(struct file * file, struct vm_area_struct * vma) +{ + struct dentry *dentry = file->f_dentry; + struct inode *inode = dentry->d_inode; + int status; + + dfprintk(VFS, "nfs: mmap(%s/%s)\n", + dentry->d_parent->d_name.name, dentry->d_name.name); + + status = nfs_revalidate_inode(NFS_SERVER(inode), inode); + if (!status) + status = generic_file_mmap(file, vma); + return status; +} + +/* + * Flush any dirty pages for this process, and check for write errors. + * The return status from this call provides a reliable indication of + * whether any write errors occurred for this process. + */ +static int +nfs_fsync(struct file *file, struct dentry *dentry, int datasync) +{ + struct inode *inode = dentry->d_inode; + int status; + + dfprintk(VFS, "nfs: fsync(%s/%ld)\n", inode->i_sb->s_id, inode->i_ino); + + lock_kernel(); + status = nfs_wb_all(inode); + if (!status) { + status = file->f_error; + file->f_error = 0; + } + unlock_kernel(); + return status; +} + +/* + * This does the "real" work of the write. The generic routine has + * allocated the page, locked it, done all the page alignment stuff + * calculations etc. Now we should just copy the data from user + * space and write it back to the real medium.. + * + * If the writer ends up delaying the write, the writer needs to + * increment the page use counts until he is done with the page. + */ +static int nfs_prepare_write(struct file *file, struct page *page, unsigned offset, unsigned to) +{ + return nfs_flush_incompatible(file, page); +} + +static int nfs_commit_write(struct file *file, struct page *page, unsigned offset, unsigned to) +{ + long status; + + lock_kernel(); + status = nfs_updatepage(file, page, offset, to-offset); + unlock_kernel(); + return status; +} + +struct address_space_operations nfs_file_aops = { + .readpage = nfs_readpage, + .readpages = nfs_readpages, + .set_page_dirty = __set_page_dirty_nobuffers, + .writepage = nfs_writepage, + .writepages = nfs_writepages, + .prepare_write = nfs_prepare_write, + .commit_write = nfs_commit_write, +#ifdef CONFIG_NFS_DIRECTIO + .direct_IO = nfs_direct_IO, +#endif +}; + +/* + * Write to a file (through the page cache). + */ +static ssize_t +nfs_file_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t pos) +{ + struct dentry * dentry = iocb->ki_filp->f_dentry; + struct inode * inode = dentry->d_inode; + ssize_t result; + +#ifdef CONFIG_NFS_DIRECTIO + if (iocb->ki_filp->f_flags & O_DIRECT) + return nfs_file_direct_write(iocb, buf, count, pos); +#endif + + dfprintk(VFS, "nfs: write(%s/%s(%ld), %lu@%lu)\n", + dentry->d_parent->d_name.name, dentry->d_name.name, + inode->i_ino, (unsigned long) count, (unsigned long) pos); + + result = -EBUSY; + if (IS_SWAPFILE(inode)) + goto out_swapfile; + result = nfs_revalidate_inode(NFS_SERVER(inode), inode); + if (result) + goto out; + + result = count; + if (!count) + goto out; + + result = generic_file_aio_write(iocb, buf, count, pos); +out: + return result; + +out_swapfile: + printk(KERN_INFO "NFS: attempt to write to active swap file!\n"); + goto out; +} + +/* + * Lock a (portion of) a file + */ +int +nfs_lock(struct file *filp, int cmd, struct file_lock *fl) +{ + struct inode * inode = filp->f_mapping->host; + int status = 0; + int status2; + + dprintk("NFS: nfs_lock(f=%s/%ld, t=%x, fl=%x, r=%Ld:%Ld)\n", + inode->i_sb->s_id, inode->i_ino, + fl->fl_type, fl->fl_flags, + (long long)fl->fl_start, (long long)fl->fl_end); + + if (!inode) + return -EINVAL; + + /* No mandatory locks over NFS */ + if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) + return -ENOLCK; + + if (NFS_PROTO(inode)->version != 4) { + /* Fake OK code if mounted without NLM support */ + if (NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM) { if (IS_GETLK(cmd)) status = LOCK_USE_CLNT; goto out_ok;