diff options
Diffstat (limited to 'fs')
52 files changed, 809 insertions, 512 deletions
@@ -586,7 +586,7 @@ static void use_mm(struct mm_struct *mm) * Note that on UML this *requires* PF_BORROWED_MM to be set, otherwise * it won't work. Update it accordingly if you change it here */ - activate_mm(active_mm, mm); + switch_mm(active_mm, mm, tsk); task_unlock(tsk); mmdrop(active_mm); diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c index 9c48250fd726..e8f6c5ad3e90 100644 --- a/fs/autofs4/inode.c +++ b/fs/autofs4/inode.c @@ -313,7 +313,7 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent) struct autofs_sb_info *sbi; struct autofs_info *ino; - sbi = (struct autofs_sb_info *) kmalloc(sizeof(*sbi), GFP_KERNEL); + sbi = kmalloc(sizeof(*sbi), GFP_KERNEL); if ( !sbi ) goto fail_unlock; DPRINTK("starting up, sbi = %p",sbi); diff --git a/fs/befs/btree.c b/fs/befs/btree.c index 81b042ee24e6..af5bb93276f8 100644 --- a/fs/befs/btree.c +++ b/fs/befs/btree.c @@ -260,7 +260,7 @@ befs_btree_find(struct super_block *sb, befs_data_stream * ds, goto error; } - this_node = (befs_btree_node *) kmalloc(sizeof (befs_btree_node), + this_node = kmalloc(sizeof (befs_btree_node), GFP_NOFS); if (!this_node) { befs_error(sb, "befs_btree_find() failed to allocate %u " diff --git a/fs/befs/debug.c b/fs/befs/debug.c index e831a8f30849..b8e304a0661e 100644 --- a/fs/befs/debug.c +++ b/fs/befs/debug.c @@ -28,7 +28,7 @@ void befs_error(const struct super_block *sb, const char *fmt, ...) { va_list args; - char *err_buf = (char *) kmalloc(ERRBUFSIZE, GFP_KERNEL); + char *err_buf = kmalloc(ERRBUFSIZE, GFP_KERNEL); if (err_buf == NULL) { printk(KERN_ERR "could not allocate %d bytes\n", ERRBUFSIZE); return; @@ -46,7 +46,7 @@ void befs_warning(const struct super_block *sb, const char *fmt, ...) { va_list args; - char *err_buf = (char *) kmalloc(ERRBUFSIZE, GFP_KERNEL); + char *err_buf = kmalloc(ERRBUFSIZE, GFP_KERNEL); if (err_buf == NULL) { printk(KERN_ERR "could not allocate %d bytes\n", ERRBUFSIZE); return; @@ -70,7 +70,7 @@ befs_debug(const struct super_block *sb, const char *fmt, ...) char *err_buf = NULL; if (BEFS_SB(sb)->mount_opts.debug) { - err_buf = (char *) kmalloc(ERRBUFSIZE, GFP_KERNEL); + err_buf = kmalloc(ERRBUFSIZE, GFP_KERNEL); if (err_buf == NULL) { printk(KERN_ERR "could not allocate %d bytes\n", ERRBUFSIZE); diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c index eac175ed9f44..134c99941a63 100644 --- a/fs/bfs/inode.c +++ b/fs/bfs/inode.c @@ -1,7 +1,7 @@ /* * fs/bfs/inode.c * BFS superblock and inode operations. - * Copyright (C) 1999,2000 Tigran Aivazian <tigran@veritas.com> + * Copyright (C) 1999-2006 Tigran Aivazian <tigran@aivazian.fsnet.co.uk> * From fs/minix, Copyright (C) 1991, 1992 Linus Torvalds. * * Made endianness-clean by Andrew Stribblehill <ads@wompom.org>, 2005. @@ -18,7 +18,7 @@ #include <asm/uaccess.h> #include "bfs.h" -MODULE_AUTHOR("Tigran A. Aivazian <tigran@veritas.com>"); +MODULE_AUTHOR("Tigran Aivazian <tigran@aivazian.fsnet.co.uk>"); MODULE_DESCRIPTION("SCO UnixWare BFS filesystem for Linux"); MODULE_LICENSE("GPL"); diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c index 00687ea62738..c2e08252af35 100644 --- a/fs/binfmt_misc.c +++ b/fs/binfmt_misc.c @@ -311,7 +311,7 @@ static Node *create_entry(const char __user *buffer, size_t count) err = -ENOMEM; memsize = sizeof(Node) + count + 8; - e = (Node *) kmalloc(memsize, GFP_USER); + e = kmalloc(memsize, GFP_USER); if (!e) goto out; @@ -916,7 +916,7 @@ void bio_set_pages_dirty(struct bio *bio) } } -static void bio_release_pages(struct bio *bio) +void bio_release_pages(struct bio *bio) { struct bio_vec *bvec = bio->bi_io_vec; int i; diff --git a/fs/block_dev.c b/fs/block_dev.c index 197f93921847..1715d6b5f411 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -129,43 +129,191 @@ blkdev_get_block(struct inode *inode, sector_t iblock, return 0; } -static int -blkdev_get_blocks(struct inode *inode, sector_t iblock, - struct buffer_head *bh, int create) +static int blk_end_aio(struct bio *bio, unsigned int bytes_done, int error) { - sector_t end_block = max_block(I_BDEV(inode)); - unsigned long max_blocks = bh->b_size >> inode->i_blkbits; + struct kiocb *iocb = bio->bi_private; + atomic_t *bio_count = &iocb->ki_bio_count; - if ((iblock + max_blocks) > end_block) { - max_blocks = end_block - iblock; - if ((long)max_blocks <= 0) { - if (create) - return -EIO; /* write fully beyond EOF */ - /* - * It is a read which is fully beyond EOF. We return - * a !buffer_mapped buffer - */ - max_blocks = 0; - } + if (bio_data_dir(bio) == READ) + bio_check_pages_dirty(bio); + else { + bio_release_pages(bio); + bio_put(bio); + } + + /* iocb->ki_nbytes stores error code from LLDD */ + if (error) + iocb->ki_nbytes = -EIO; + + if (atomic_dec_and_test(bio_count)) { + if (iocb->ki_nbytes < 0) + aio_complete(iocb, iocb->ki_nbytes, 0); + else + aio_complete(iocb, iocb->ki_left, 0); } - bh->b_bdev = I_BDEV(inode); - bh->b_blocknr = iblock; - bh->b_size = max_blocks << inode->i_blkbits; - if (max_blocks) - set_buffer_mapped(bh); return 0; } +#define VEC_SIZE 16 +struct pvec { + unsigned short nr; + unsigned short idx; + struct page *page[VEC_SIZE]; +}; + +#define PAGES_SPANNED(addr, len) \ + (DIV_ROUND_UP((addr) + (len), PAGE_SIZE) - (addr) / PAGE_SIZE); + +/* + * get page pointer for user addr, we internally cache struct page array for + * (addr, count) range in pvec to avoid frequent call to get_user_pages. If + * internal page list is exhausted, a batch count of up to VEC_SIZE is used + * to get next set of page struct. + */ +static struct page *blk_get_page(unsigned long addr, size_t count, int rw, + struct pvec *pvec) +{ + int ret, nr_pages; + if (pvec->idx == pvec->nr) { + nr_pages = PAGES_SPANNED(addr, count); + nr_pages = min(nr_pages, VEC_SIZE); + down_read(¤t->mm->mmap_sem); + ret = get_user_pages(current, current->mm, addr, nr_pages, + rw == READ, 0, pvec->page, NULL); + up_read(¤t->mm->mmap_sem); + if (ret < 0) + return ERR_PTR(ret); + pvec->nr = ret; + pvec->idx = 0; + } + return pvec->page[pvec->idx++]; +} + static ssize_t blkdev_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, - loff_t offset, unsigned long nr_segs) -{ - struct file *file = iocb->ki_filp; - struct inode *inode = file->f_mapping->host; + loff_t pos, unsigned long nr_segs) +{ + struct inode *inode = iocb->ki_filp->f_mapping->host; + unsigned blkbits = blksize_bits(bdev_hardsect_size(I_BDEV(inode))); + unsigned blocksize_mask = (1 << blkbits) - 1; + unsigned long seg = 0; /* iov segment iterator */ + unsigned long nvec; /* number of bio vec needed */ + unsigned long cur_off; /* offset into current page */ + unsigned long cur_len; /* I/O len of current page, up to PAGE_SIZE */ + + unsigned long addr; /* user iovec address */ + size_t count; /* user iovec len */ + size_t nbytes = iocb->ki_nbytes = iocb->ki_left; /* total xfer size */ + loff_t size; /* size of block device */ + struct bio *bio; + atomic_t *bio_count = &iocb->ki_bio_count; + struct page *page; + struct pvec pvec; + + pvec.nr = 0; + pvec.idx = 0; + + if (pos & blocksize_mask) + return -EINVAL; + + size = i_size_read(inode); + if (pos + nbytes > size) { + nbytes = size - pos; + iocb->ki_left = nbytes; + } + + /* + * check first non-zero iov alignment, the remaining + * iov alignment is checked inside bio loop below. + */ + do { + addr = (unsigned long) iov[seg].iov_base; + count = min(iov[seg].iov_len, nbytes); + if (addr & blocksize_mask || count & blocksize_mask) + return -EINVAL; + } while (!count && ++seg < nr_segs); + atomic_set(bio_count, 1); + + while (nbytes) { + /* roughly estimate number of bio vec needed */ + nvec = (nbytes + PAGE_SIZE - 1) / PAGE_SIZE; + nvec = max(nvec, nr_segs - seg); + nvec = min(nvec, (unsigned long) BIO_MAX_PAGES); + + /* bio_alloc should not fail with GFP_KERNEL flag */ + bio = bio_alloc(GFP_KERNEL, nvec); + bio->bi_bdev = I_BDEV(inode); + bio->bi_end_io = blk_end_aio; + bio->bi_private = iocb; + bio->bi_sector = pos >> blkbits; +same_bio: + cur_off = addr & ~PAGE_MASK; + cur_len = PAGE_SIZE - cur_off; + if (count < cur_len) + cur_len = count; + + page = blk_get_page(addr, count, rw, &pvec); + if (unlikely(IS_ERR(page))) + goto backout; + + if (bio_add_page(bio, page, cur_len, cur_off)) { + pos += cur_len; + addr += cur_len; + count -= cur_len; + nbytes -= cur_len; + + if (count) + goto same_bio; + while (++seg < nr_segs) { + addr = (unsigned long) iov[seg].iov_base; + count = iov[seg].iov_len; + if (!count) + continue; + if (unlikely(addr & blocksize_mask || + count & blocksize_mask)) { + page = ERR_PTR(-EINVAL); + goto backout; + } + count = min(count, nbytes); + goto same_bio; + } + } - return blockdev_direct_IO_no_locking(rw, iocb, inode, I_BDEV(inode), - iov, offset, nr_segs, blkdev_get_blocks, NULL); + /* bio is ready, submit it */ + if (rw == READ) + bio_set_pages_dirty(bio); + atomic_inc(bio_count); + submit_bio(rw, bio); + } + +completion: + iocb->ki_left -= nbytes; + nbytes = iocb->ki_left; + iocb->ki_pos += nbytes; + + blk_run_address_space(inode->i_mapping); + if (atomic_dec_and_test(bio_count)) + aio_complete(iocb, nbytes, 0); + + return -EIOCBQUEUED; + +backout: + /* + * back out nbytes count constructed so far for this bio, + * we will throw away current bio. + */ + nbytes += bio->bi_size; + bio_release_pages(bio); + bio_put(bio); + + /* + * if no bio was submmitted, return the error code. + * otherwise, proceed with pending I/O completion. + */ + if (atomic_read(bio_count) == 1) + return PTR_ERR(page); + goto completion; } static int blkdev_writepage(struct page *page, struct writeback_control *wbc) diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 098790eb2aa1..472e33e0f3cf 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -4876,7 +4876,7 @@ int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, } else { /* Add file to outstanding requests */ /* BB change to kmem cache alloc */ - dnotify_req = (struct dir_notify_req *) kmalloc( + dnotify_req = kmalloc( sizeof(struct dir_notify_req), GFP_KERNEL); if(dnotify_req) { diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index 137d76c3f90a..c692487346ea 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c @@ -24,6 +24,7 @@ #include <linux/kobject.h> #include <linux/namei.h> #include <linux/debugfs.h> +#include <linux/fsnotify.h> #define DEBUGFS_MAGIC 0x64626720 @@ -54,7 +55,8 @@ static struct inode *debugfs_get_inode(struct super_block *sb, int mode, dev_t d inode->i_op = &simple_dir_inode_operations; inode->i_fop = &simple_dir_operations; - /* directory inodes start off with i_nlink == 2 (for "." entry) */ + /* directory inodes start off with i_nlink == 2 + * (for "." entry) */ inc_nlink(inode); break; } @@ -87,15 +89,22 @@ static int debugfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) mode = (mode & (S_IRWXUGO | S_ISVTX)) | S_IFDIR; res = debugfs_mknod(dir, dentry, mode, 0); - if (!res) + if (!res) { inc_nlink(dir); + fsnotify_mkdir(dir, dentry); + } return res; } static int debugfs_create(struct inode *dir, struct dentry *dentry, int mode) { + int res; + mode = (mode & S_IALLUGO) | S_IFREG; - return debugfs_mknod(dir, dentry, mode, 0); + res = debugfs_mknod(dir, dentry, mode, 0); + if (!res) + fsnotify_create(dir, dentry); + return res; } static inline int debugfs_positive(struct dentry *dentry) @@ -135,7 +144,7 @@ static int debugfs_create_by_name(const char *name, mode_t mode, * block. A pointer to that is in the struct vfsmount that we * have around. */ - if (!parent ) { + if (!parent) { if (debugfs_mount && debugfs_mount->mnt_sb) { parent = debugfs_mount->mnt_sb->s_root; } @@ -153,6 +162,7 @@ static int debugfs_create_by_name(const char *name, mode_t mode, error = debugfs_mkdir(parent->d_inode, *dentry, mode); else error = debugfs_create(parent->d_inode, *dentry, mode); + dput(*dentry); } else error = PTR_ERR(*dentry); mutex_unlock(&parent->d_inode->i_mutex); @@ -197,13 +207,15 @@ struct dentry *debugfs_create_file(const char *name, mode_t mode, pr_debug("debugfs: creating file '%s'\n",name); - error = simple_pin_fs(&debug_fs_type, &debugfs_mount, &debugfs_mount_count); + error = simple_pin_fs(&debug_fs_type, &debugfs_mount, + &debugfs_mount_count); if (error) goto exit; error = debugfs_create_by_name(name, mode, parent, &dentry); if (error) { dentry = NULL; + simple_release_fs(&debugfs_mount, &debugfs_mount_count); goto exit; } @@ -262,6 +274,7 @@ EXPORT_SYMBOL_GPL(debugfs_create_dir); void debugfs_remove(struct dentry *dentry) { struct dentry *parent; + int ret = 0; if (!dentry) return; @@ -273,11 +286,19 @@ void debugfs_remove(struct dentry *dentry) mutex_lock(&parent->d_inode->i_mutex); if (debugfs_positive(dentry)) { if (dentry->d_inode) { - if (S_ISDIR(dentry->d_inode->i_mode)) - simple_rmdir(parent->d_inode, dentry); - else + dget(dentry); + if (S_ISDIR(dentry->d_inode->i_mode)) { + ret = simple_rmdir(parent->d_inode, dentry); + if (ret) + printk(KERN_ERR + "DebugFS rmdir on %s failed : " + "directory not empty.\n", + dentry->d_name.name); + } else simple_unlink(parent->d_inode, dentry); - dput(dentry); + if (!ret) + d_delete(dentry); + dput(dentry); } } mutex_unlock(&parent->d_inode->i_mutex); diff --git a/fs/inode.c b/fs/inode.c index d00de182ecb9..bf21dc6d0dbd 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -1144,7 +1144,6 @@ sector_t bmap(struct inode * inode, sector_t block) res = inode->i_mapping->a_ops->bmap(inode->i_mapping, block); return res; } - EXPORT_SYMBOL(bmap); /** @@ -1163,27 +1162,43 @@ void touch_atime(struct vfsmount *mnt, struct dentry *dentry) if (IS_RDONLY(inode)) return; - - if ((inode->i_flags & S_NOATIME) || - (inode->i_sb->s_flags & MS_NOATIME) || - ((inode->i_sb->s_flags & MS_NODIRATIME) && S_ISDIR(inode->i_mode))) + if (inode->i_flags & S_NOATIME) + return; + if (inode->i_sb->s_flags & MS_NOATIME) + return; + if ((inode->i_sb->s_flags & MS_NODIRATIME) && S_ISDIR(inode->i_mode)) return; /* * We may have a NULL vfsmount when coming from NFSD */ - if (mnt && - ((mnt->mnt_flags & MNT_NOATIME) || - ((mnt->mnt_flags & MNT_NODIRATIME) && S_ISDIR(inode->i_mode)))) - return; + if (mnt) { + if (mnt->mnt_flags & MNT_NOATIME) + return; + if ((mnt->mnt_flags & MNT_NODIRATIME) && S_ISDIR(inode->i_mode)) + return; - now = current_fs_time(inode->i_sb); - if (!timespec_equal(&inode->i_atime, &now)) { - inode->i_atime = now; - mark_inode_dirty_sync(inode); + if (mnt->mnt_flags & MNT_RELATIME) { + /* + * With relative atime, only update atime if the + * previous atime is earlier than either the ctime or + * mtime. + */ + if (timespec_compare(&inode->i_mtime, + &inode->i_atime) < 0 && + timespec_compare(&inode->i_ctime, + &inode->i_atime) < 0) + return; + } } -} + now = current_fs_time(inode->i_sb); + if (timespec_equal(&inode->i_atime, &now)) + return; + + inode->i_atime = now; + mark_inode_dirty_sync(inode); +} EXPORT_SYMBOL(touch_atime); /** diff --git a/fs/jffs/inode-v23.c b/fs/jffs/inode-v23.c index 7b40c69f44eb..43baa1afa021 100644 --- a/fs/jffs/inode-v23.c +++ b/fs/jffs/inode-v23.c @@ -818,7 +818,7 @@ jffs_mkdir(struct inode *dir, struct dentry *dentry, int mode) D1({ int len = dentry->d_name.len; - char *_name = (char *) kmalloc(len + 1, GFP_KERNEL); + char *_name = kmalloc(len + 1, GFP_KERNEL); memcpy(_name, dentry->d_name.name, len); _name[len] = '\0'; printk("***jffs_mkdir(): dir = 0x%p, name = \"%s\", " @@ -964,7 +964,7 @@ jffs_remove(struct inode *dir, struct dentry *dentry, int type) D1({ int len = dentry->d_name.len; const char *name = dentry->d_name.name; - char *_name = (char *) kmalloc(len + 1, GFP_KERNEL); + char *_name = kmalloc(len + 1, GFP_KERNEL); memcpy(_name, name, len); _name[len] = '\0'; printk("***jffs_remove(): file = \"%s\", ino = %ld\n", _name, dentry->d_inode->i_ino); diff --git a/fs/jffs/intrep.c b/fs/jffs/intrep.c index d0e783f199ea..6dd18911b44c 100644 --- a/fs/jffs/intrep.c +++ b/fs/jffs/intrep.c @@ -436,7 +436,7 @@ jffs_checksum_flash(struct mtd_info *mtd, loff_t start, int size, __u32 *result) int i, length; /* Allocate read buffer */ - read_buf = (__u8 *) kmalloc (sizeof(__u8) * 4096, GFP_KERNEL); + read_buf = kmalloc(sizeof(__u8) * 4096, GFP_KERNEL); if (!read_buf) { printk(KERN_NOTICE "kmalloc failed in jffs_checksum_flash()\n"); return -ENOMEM; @@ -744,11 +744,11 @@ static int check_partly_erased_sectors(struct jffs_fmcontrol *fmc){ /* Allocate read buffers */ - read_buf1 = (__u8 *) kmalloc (sizeof(__u8) * READ_AHEAD_BYTES, GFP_KERNEL); + read_buf1 = kmalloc(sizeof(__u8) * READ_AHEAD_BYTES, GFP_KERNEL); if (!read_buf1) return -ENOMEM; - read_buf2 = (__u8 *) kmalloc (sizeof(__u8) * READ_AHEAD_BYTES, GFP_KERNEL); + read_buf2 = kmalloc(sizeof(__u8) * READ_AHEAD_BYTES, GFP_KERNEL); if (!read_buf2) { kfree(read_buf1); return -ENOMEM; @@ -876,7 +876,7 @@ jffs_scan_flash(struct jffs_control *c) } /* Allocate read buffer */ - read_buf = (__u8 *) kmalloc (sizeof(__u8) * 4096, GFP_KERNEL); + read_buf = kmalloc(sizeof(__u8) * 4096, GFP_KERNEL); if (!read_buf) { flash_safe_release(fmc->mtd); return -ENOMEM; @@ -1463,7 +1463,7 @@ jffs_insert_node(struct jffs_control *c, struct jffs_file *f, kfree(f->name); DJM(no_name--); } - if (!(f->name = (char *) kmalloc(raw_inode->nsize + 1, + if (!(f->name = kmalloc(raw_inode->nsize + 1, GFP_KERNEL))) { return -ENOMEM; } @@ -1737,7 +1737,7 @@ jffs_find_child(struct jffs_file *dir, const char *name, int len) printk("jffs_find_child(): Found \"%s\".\n", f->name); } else { - char *copy = (char *) kmalloc(len + 1, GFP_KERNEL); + char *copy = kmalloc(len + 1, GFP_KERNEL); if (copy) { memcpy(copy, name, len); copy[len] = '\0'; @@ -2627,7 +2627,7 @@ jffs_print_tree(struct jffs_file *first_file, int indent) return; } - if (!(space = (char *) kmalloc(indent + 1, GFP_KERNEL))) { + if (!(space = kmalloc(indent + 1, GFP_KERNEL))) { printk("jffs_print_tree(): Out of memory!\n"); return; } diff --git a/fs/jfs/jfs_dtree.c b/fs/jfs/jfs_dtree.c index 47bc0b5d1324..6d62f3222892 100644 --- a/fs/jfs/jfs_dtree.c +++ b/fs/jfs/jfs_dtree.c @@ -3777,12 +3777,12 @@ static int ciGetLeafPrefixKey(dtpage_t * lp, int li, dtpage_t * rp, struct component_name lkey; struct component_name rkey; - lkey.name = (wchar_t *) kmalloc((JFS_NAME_MAX + 1) * sizeof(wchar_t), + lkey.name = kmalloc((JFS_NAME_MAX + 1) * sizeof(wchar_t), GFP_KERNEL); if (lkey.name == NULL) return -ENOMEM; - rkey.name = (wchar_t *) kmalloc((JFS_NAME_MAX + 1) * sizeof(wchar_t), + rkey.name = kmalloc((JFS_NAME_MAX + 1) * sizeof(wchar_t), GFP_KERNEL); if (rkey.name == NULL) { kfree(lkey.name); diff --git a/fs/jfs/jfs_imap.c b/fs/jfs/jfs_imap.c index ee9b473b7b80..53f63b47a6d3 100644 --- a/fs/jfs/jfs_imap.c +++ b/fs/jfs/jfs_imap.c @@ -120,7 +120,7 @@ int diMount(struct inode *ipimap) * allocate/initialize the in-memory inode map control structure */ /* allocate the in-memory inode map control structure. */ - imap = (struct inomap *) kmalloc(sizeof(struct inomap), GFP_KERNEL); + imap = kmalloc(sizeof(struct inomap), GFP_KERNEL); if (imap == NULL) { jfs_err("diMount: kmalloc returned NULL!"); return -ENOMEM; diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c index 92681c9e9b20..062707745162 100644 --- a/fs/lockd/clntlock.c +++ b/fs/lockd/clntlock.c @@ -36,7 +36,7 @@ struct nlm_wait { struct nlm_host * b_host; struct file_lock * b_lock; /* local file lock */ unsigned short b_reclaim; /* got to reclaim lock */ - u32 b_status; /* grant callback status */ + __be32 b_status; /* grant callback status */ }; static LIST_HEAD(nlm_blocked); @@ -53,7 +53,7 @@ struct nlm_wait *nlmclnt_prepare_block(struct nlm_host *host, struct file_lock * block->b_host = host; block->b_lock = fl; init_waitqueue_head(&block->b_wait); - block->b_status = NLM_LCK_BLOCKED; + block->b_status = nlm_lck_blocked; list_add(&block->b_list, &nlm_blocked); } return block; @@ -89,7 +89,7 @@ int nlmclnt_block(struct nlm_wait *block, struct nlm_rqst *req, long timeout) * nlmclnt_lock for an explanation. */ ret = wait_event_interruptible_timeout(block->b_wait, - block->b_status != NLM_LCK_BLOCKED, + block->b_status != nlm_lck_blocked, timeout); if (ret < 0) return -ERESTARTSYS; @@ -131,7 +131,7 @@ __be32 nlmclnt_grant(const struct sockaddr_in *addr, const struct nlm_lock *lock /* Alright, we found a lock. Set the return status * and wake up the caller */ - block->b_status = NLM_LCK_GRANTED; + block->b_status = nlm_granted; wake_up(&block->b_wait); res = nlm_granted; } @@ -211,7 +211,7 @@ restart: /* Now, wake up all processes that sleep on a blocked lock */ list_for_each_entry(block, &nlm_blocked, b_list) { if (block->b_host == host) { - block->b_status = NLM_LCK_DENIED_GRACE_PERIOD; + block->b_status = nlm_lck_denied_grace_period; wake_up(&block->b_wait); } } diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index 80a1a6dccc8f..0b4acc1c5e7d 100644 --- a/fs/lockd/clntproc.c +++ b/fs/lockd/clntproc.c @@ -27,7 +27,7 @@ static int nlmclnt_test(struct nlm_rqst *, struct file_lock *); static int nlmclnt_lock(struct nlm_rqst *, struct file_lock *); static int nlmclnt_unlock(struct nlm_rqst *, struct file_lock *); -static int nlm_stat_to_errno(u32 stat); +static int nlm_stat_to_errno(__be32 stat); static void nlmclnt_locks_init_private(struct file_lock *fl, struct nlm_host *host); static int nlmclnt_cancel(struct nlm_host *, int , struct file_lock *); @@ -325,7 +325,7 @@ nlmclnt_call(struct nlm_rqst *req, u32 proc) } break; } else - if (resp->status == NLM_LCK_DENIED_GRACE_PERIOD) { + if (resp->status == nlm_lck_denied_grace_period) { dprintk("lockd: server in grace period\n"); if (argp->reclaim) { printk(KERN_WARNING @@ -411,10 +411,10 @@ nlmclnt_test(struct nlm_rqst *req, struct file_lock *fl) goto out; switch (req->a_res.status) { - case NLM_LCK_GRANTED: + case nlm_granted: fl->fl_type = F_UNLCK; break; - case NLM_LCK_DENIED: + case nlm_lck_denied: /* * Report the conflicting lock back to the application. */ @@ -524,9 +524,9 @@ again: if (!req->a_args.block) break; /* Did a reclaimer thread notify us of a server reboot? */ - if (resp->status == NLM_LCK_DENIED_GRACE_PERIOD) + if (resp->status == nlm_lck_denied_grace_period) continue; - if (resp->status != NLM_LCK_BLOCKED) + if (resp->status != nlm_lck_blocked) break; /* Wait on an NLM blocking lock */ status = nlmclnt_block(block, req, NLMCLNT_POLL_TIMEOUT); @@ -535,11 +535,11 @@ again: */ if (status < 0) goto out_unblock; - if (resp->status != NLM_LCK_BLOCKED) + if (resp->status != nlm_lck_blocked) break; } - if (resp->status == NLM_LCK_GRANTED) { + if (resp->status == nlm_granted) { down_read(&host->h_rwsem); /* Check whether or not the server has rebooted */ if (fl->fl_u.nfs_fl.state != host->h_state) { @@ -556,7 +556,7 @@ again: out_unblock: nlmclnt_finish_block(block); /* Cancel the blocked request if it is still pending */ - if (resp->status == NLM_LCK_BLOCKED) + if (resp->status == nlm_lck_blocked) nlmclnt_cancel(host, req->a_args.block, fl); out: nlm_release_call(req); @@ -585,12 +585,12 @@ nlmclnt_reclaim(struct nlm_host *host, struct file_lock *fl) req->a_args.reclaim = 1; if ((status = nlmclnt_call(req, NLMPROC_LOCK)) >= 0 - && req->a_res.status == NLM_LCK_GRANTED) + && req->a_res.status == nlm_granted) return 0; printk(KERN_WARNING "lockd: failed to reclaim lock for pid %d " "(errno %d, status %d)\n", fl->fl_pid, - status, req->a_res.status); + status, ntohl(req->a_res.status)); /* * FIXME: This is a serious failure. We can @@ -637,10 +637,10 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl) if (status < 0) goto out; - if (resp->status == NLM_LCK_GRANTED) + if (resp->status == nlm_granted) goto out; - if (resp->status != NLM_LCK_DENIED_NOLOCKS) + if (resp->status != nlm_lck_denied_nolocks) printk("lockd: unexpected unlock status: %d\n", resp->status); /* What to do now? I'm out of my depth... */ status = -ENOLCK; @@ -652,7 +652,7 @@ out: static void nlmclnt_unlock_callback(struct rpc_task *task, void *data) { struct nlm_rqst *req = data; - int status = req->a_res.status; + u32 status = ntohl(req->a_res.status); if (RPC_ASSASSINATED(task)) goto die; @@ -720,6 +720,7 @@ static int nlmclnt_cancel(struct nlm_host *host, int block, struct file_lock *fl static void nlmclnt_cancel_callback(struct rpc_task *task, void *data) { struct nlm_rqst *req = data; + u32 status = ntohl(req->a_res.status); if (RPC_ASSASSINATED(task)) goto die; @@ -731,9 +732,9 @@ static void nlmclnt_cancel_callback(struct rpc_task *task, void *data) } dprintk("lockd: cancel status %u (task %u)\n", - req->a_res.status, task->tk_pid); + status, task->tk_pid); - switch (req->a_res.status) { + switch (status) { case NLM_LCK_GRANTED: case NLM_LCK_DENIED_GRACE_PERIOD: case NLM_LCK_DENIED: @@ -744,7 +745,7 @@ static void nlmclnt_cancel_callback(struct rpc_task *task, void *data) goto retry_cancel; default: printk(KERN_NOTICE "lockd: weird return %d for CANCEL call\n", - req->a_res.status); + status); } die: @@ -768,9 +769,9 @@ static const struct rpc_call_ops nlmclnt_cancel_ops = { * Convert an NLM status code to a generic kernel errno */ static int -nlm_stat_to_errno(u32 status) +nlm_stat_to_errno(__be32 status) { - switch(status) { + switch(ntohl(status)) { case NLM_LCK_GRANTED: return 0; case NLM_LCK_DENIED: diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index 5c054b20fd5e..c7db0a5bccdc 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c @@ -645,7 +645,7 @@ static const struct rpc_call_ops nlmsvc_grant_ops = { * block. */ void -nlmsvc_grant_reply(struct nlm_cookie *cookie, u32 status) +nlmsvc_grant_reply(struct nlm_cookie *cookie, __be32 status) { struct nlm_block *block; @@ -655,7 +655,7 @@ nlmsvc_grant_reply(struct nlm_cookie *cookie, u32 status) return; if (block) { - if (status == NLM_LCK_DENIED_GRACE_PERIOD) { + if (status == nlm_lck_denied_grace_period) { /* Try again in a couple of seconds */ nlmsvc_insert_block(block, 10 * HZ); } else { diff --git a/fs/lockd/svcshare.c b/fs/lockd/svcshare.c index 6220dc2a3f2c..068886de4dda 100644 --- a/fs/lockd/svcshare.c +++ b/fs/lockd/svcshare.c @@ -39,7 +39,7 @@ nlmsvc_share_file(struct nlm_host *host, struct nlm_file *file, return nlm_lck_denied; } - share = (struct nlm_share *) kmalloc(sizeof(*share) + oh->len, + share = kmalloc(sizeof(*share) + oh->len, GFP_KERNEL); if (share == NULL) return nlm_lck_denied_nolocks; diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c index b7c949256e5a..34dae5d70738 100644 --- a/fs/lockd/xdr.c +++ b/fs/lockd/xdr.c @@ -361,7 +361,7 @@ nlmsvc_decode_res(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp) { if (!(p = nlm_decode_cookie(p, &resp->cookie))) return 0; - resp->status = ntohl(*p++); + resp->status = *p++; return xdr_argsize_check(rqstp, p); } @@ -407,8 +407,8 @@ nlmclt_decode_testres(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp) { if (!(p = nlm_decode_cookie(p, &resp->cookie))) return -EIO; - resp->status = ntohl(*p++); - if (resp->status == NLM_LCK_DENIED) { + resp->status = *p++; + if (resp->status == nlm_lck_denied) { struct file_lock *fl = &resp->lock.fl; u32 excl; s32 start, len, end; @@ -506,7 +506,7 @@ nlmclt_decode_res(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp) { if (!(p = nlm_decode_cookie(p, &resp->cookie))) return -EIO; - resp->status = ntohl(*p++); + resp->status = *p++; return 0; } diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c index f4c0b2b9f75a..a78240551219 100644 --- a/fs/lockd/xdr4.c +++ b/fs/lockd/xdr4.c @@ -367,7 +367,7 @@ nlm4svc_decode_res(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp) { if (!(p = nlm4_decode_cookie(p, &resp->cookie))) return 0; - resp->status = ntohl(*p++); + resp->status = *p++; return xdr_argsize_check(rqstp, p); } @@ -413,8 +413,8 @@ nlm4clt_decode_testres(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp) { if (!(p = nlm4_decode_cookie(p, &resp->cookie))) return -EIO; - resp->status = ntohl(*p++); - if (resp->status == NLM_LCK_DENIED) { + resp->status = *p++; + if (resp->status == nlm_lck_denied) { struct file_lock *fl = &resp->lock.fl; u32 excl; s64 start, end, len; @@ -512,7 +512,7 @@ nlm4clt_decode_res(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp) { if (!(p = nlm4_decode_cookie(p, &resp->cookie))) return -EIO; - resp->status = ntohl(*p++); + resp->status = *p++; return 0; } diff --git a/fs/namespace.c b/fs/namespace.c index fde8553faa76..5ef336c1103c 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -368,6 +368,7 @@ static int show_vfsmnt(struct seq_file *m, void *v) { MNT_NOEXEC, ",noexec" }, { MNT_NOATIME, ",noatime" }, { MNT_NODIRATIME, ",nodiratime" }, + { MNT_RELATIME, ",relatime" }, { 0, NULL } }; struct proc_fs_info *fs_infop; @@ -1405,9 +1406,11 @@ long do_mount(char *dev_name, char *dir_name, char *type_page, mnt_flags |= MNT_NOATIME; if (flags & MS_NODIRATIME) mnt_flags |= MNT_NODIRATIME; + if (flags & MS_RELATIME) + mnt_flags |= MNT_RELATIME; flags &= ~(MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_ACTIVE | - MS_NOATIME | MS_NODIRATIME); + MS_NOATIME | MS_NODIRATIME | MS_RELATIME); /* ... and get the mountpoint */ retval = path_lookup(dir_name, LOOKUP_FOLLOW, &nd); diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c index 47462ac94474..67a90bf795d5 100644 --- a/fs/ncpfs/inode.c +++ b/fs/ncpfs/inode.c @@ -327,11 +327,12 @@ static int ncp_parse_options(struct ncp_mount_data_kernel *data, char *options) char *optarg; unsigned long optint; int version = 0; + int ret; data->flags = 0; data->int_flags = 0; data->mounted_uid = 0; - data->wdog_pid = -1; + data->wdog_pid = NULL; data->ncp_fd = ~0; data->time_out = 10; data->retry_count = 20; @@ -343,8 +344,9 @@ static int ncp_parse_options(struct ncp_mount_data_kernel *data, char *options) data->mounted_vol[0] = 0; while ((optval = ncp_getopt("ncpfs", &options, ncp_opts, NULL, &optarg, &optint)) != 0) { - if (optval < 0) - return optval; + ret = optval; + if (ret < 0) + goto err; switch (optval) { case 'u': data->uid = optint; @@ -371,7 +373,7 @@ static int ncp_parse_options(struct ncp_mount_data_kernel *data, char *options) data->flags = optint; break; case 'w': - data->wdog_pid = optint; + data->wdog_pid = find_get_pid(optint); break; case 'n': data->ncp_fd = optint; @@ -380,18 +382,21 @@ static int ncp_parse_options(struct ncp_mount_data_kernel *data, char *options) data->info_fd = optint; break; case 'v': - if (optint < NCP_MOUNT_VERSION_V4) { - return -ECHRNG; - } - if (optint > NCP_MOUNT_VERSION_V5) { - return -ECHRNG; - } + ret = -ECHRNG; + if (optint < NCP_MOUNT_VERSION_V4) + goto err; + if (optint > NCP_MOUNT_VERSION_V5) + goto err; version = optint; break; } } return 0; +err: + put_pid(data->wdog_pid); + data->wdog_pid = NULL; + return ret; } static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent) @@ -409,6 +414,7 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent) #endif struct ncp_entry_info finfo; + data.wdog_pid = NULL; server = kzalloc(sizeof(struct ncp_server), GFP_KERNEL); if (!server) return -ENOMEM; @@ -425,7 +431,7 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent) data.flags = md->flags; data.int_flags = NCP_IMOUNT_LOGGEDIN_POSSIBLE; data.mounted_uid = md->mounted_uid; - data.wdog_pid = md->wdog_pid; + data.wdog_pid = find_get_pid(md->wdog_pid); data.ncp_fd = md->ncp_fd; data.time_out = md->time_out; data.retry_count = md->retry_count; @@ -445,7 +451,7 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent) data.flags = md->flags; data.int_flags = 0; data.mounted_uid = md->mounted_uid; - data.wdog_pid = md->wdog_pid; + data.wdog_pid = find_get_pid(md->wdog_pid); data.ncp_fd = md->ncp_fd; data.time_out = md->time_out; data.retry_count = md->retry_count; @@ -679,6 +685,7 @@ out_fput: */ fput(ncp_filp); out: + put_pid(data.wdog_pid); sb->s_fs_info = NULL; kfree(server); return error; @@ -711,7 +718,8 @@ static void ncp_put_super(struct super_block *sb) if (server->info_filp) fput(server->info_filp); fput(server->ncp_filp); - kill_proc(server->m.wdog_pid, SIGTERM, 1); + kill_pid(server->m.wdog_pid, SIGTERM, 1); + put_pid(server->m.wdog_pid); kfree(server->priv.data); kfree(server->auth.object_name); diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index ee458aeab24a..b3fd29baadc3 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -1877,7 +1877,7 @@ static int nfs4_proc_unlink_setup(struct rpc_message *msg, struct dentry *dir, struct nfs_server *server = NFS_SERVER(dir->d_inode); struct unlink_desc *up; - up = (struct unlink_desc *) kmalloc(sizeof(*up), GFP_KERNEL); + up = kmalloc(sizeof(*up), GFP_KERNEL); if (!up) return -ENOMEM; diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index f37df46d2eaa..248dd92e6a56 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c @@ -787,15 +787,20 @@ exp_get_by_name(svc_client *clp, struct vfsmount *mnt, struct dentry *dentry, key.ex_dentry = dentry; exp = svc_export_lookup(&key); - if (exp != NULL) - switch (cache_check(&svc_export_cache, &exp->h, reqp)) { + if (exp != NULL) { + int err; + + err = cache_check(&svc_export_cache, &exp->h, reqp); + switch (err) { case 0: break; case -EAGAIN: - exp = ERR_PTR(-EAGAIN); + case -ETIMEDOUT: + exp = ERR_PTR(err); break; default: exp = NULL; } + } return exp; } @@ -950,6 +955,8 @@ exp_export(struct nfsctl_export *nxp) exp = exp_get_by_name(clp, nd.mnt, nd.dentry, NULL); + memset(&new, 0, sizeof(new)); + /* must make sure there won't be an ex_fsid clash */ if ((nxp->ex_flags & NFSEXP_FSID) && (fsid_key = exp_get_fsid_key(clp, nxp->ex_dev)) && @@ -980,6 +987,9 @@ exp_export(struct nfsctl_export *nxp) new.h.expiry_time = NEVER; new.h.flags = 0; + new.ex_path = kstrdup(nxp->ex_path, GFP_KERNEL); + if (!new.ex_path) + goto finish; new.ex_client = clp; new.ex_mnt = nd.mnt; new.ex_dentry = nd.dentry; @@ -1000,10 +1010,11 @@ exp_export(struct nfsctl_export *nxp) /* failed to create at least one index */ exp_do_unexport(exp); cache_flush(); - err = -ENOMEM; - } - + } else + err = 0; finish: + if (new.ex_path) + kfree(new.ex_path); if (exp) exp_put(exp); if (fsid_key && !IS_ERR(fsid_key)) @@ -1104,6 +1115,10 @@ exp_rootfh(svc_client *clp, char *path, struct knfsd_fh *f, int maxsize) path, nd.dentry, clp->name, inode->i_sb->s_id, inode->i_ino); exp = exp_parent(clp, nd.mnt, nd.dentry, NULL); + if (IS_ERR(exp)) { + err = PTR_ERR(exp); + goto out; + } if (!exp) { dprintk("nfsd: exp_rootfh export not found.\n"); goto out; @@ -1159,12 +1174,10 @@ exp_pseudoroot(struct auth_domain *clp, struct svc_fh *fhp, mk_fsid_v1(fsidv, 0); exp = exp_find(clp, 1, fsidv, creq); - if (IS_ERR(exp) && PTR_ERR(exp) == -EAGAIN) - return nfserr_dropit; + if (IS_ERR(exp)) + return nfserrno(PTR_ERR(exp)); if (exp == NULL) return nfserr_perm; - else if (IS_ERR(exp)) - return nfserrno(PTR_ERR(exp)); rv = fh_compose(fhp, exp, exp->ex_dentry, NULL); exp_put(exp); return rv; diff --git a/fs/nfsd/lockd.c b/fs/nfsd/lockd.c index 11fdaf7721b4..221acd1f11f6 100644 --- a/fs/nfsd/lockd.c +++ b/fs/nfsd/lockd.c @@ -22,7 +22,7 @@ /* * Note: we hold the dentry use count while the file is open. */ -static u32 +static __be32 nlm_fopen(struct svc_rqst *rqstp, struct nfs_fh *f, struct file **filp) { __be32 nfserr; diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 50bc94243ca1..8522729830db 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -33,13 +33,6 @@ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Note: some routines in this file are just trivial wrappers - * (e.g. nfsd4_lookup()) defined solely for the sake of consistent - * naming. Since all such routines have been declared "inline", - * there shouldn't be any associated overhead. At some point in - * the future, I might inline these "by hand" to clean up a - * little. */ #include <linux/param.h> @@ -161,8 +154,9 @@ do_open_fhandle(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_ } -static inline __be32 -nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open, struct nfs4_stateowner **replay_owner) +static __be32 +nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + struct nfsd4_open *open) { __be32 status; dprintk("NFSD: nfsd4_open filename %.*s op_stateowner %p\n", @@ -179,11 +173,11 @@ nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open status = nfsd4_process_open1(open); if (status == nfserr_replay_me) { struct nfs4_replay *rp = &open->op_stateowner->so_replay; - fh_put(current_fh); - current_fh->fh_handle.fh_size = rp->rp_openfh_len; - memcpy(¤t_fh->fh_handle.fh_base, rp->rp_openfh, + fh_put(&cstate->current_fh); + cstate->current_fh.fh_handle.fh_size = rp->rp_openfh_len; + memcpy(&cstate->current_fh.fh_handle.fh_base, rp->rp_openfh, rp->rp_openfh_len); - status = fh_verify(rqstp, current_fh, 0, MAY_NOP); + status = fh_verify(rqstp, &cstate->current_fh, 0, MAY_NOP); if (status) dprintk("nfsd4_open: replay failed" " restoring previous filehandle\n"); @@ -215,7 +209,8 @@ nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open * (3) set open->op_truncate if the file is to be * truncated after opening, (4) do permission checking. */ - status = do_open_lookup(rqstp, current_fh, open); + status = do_open_lookup(rqstp, &cstate->current_fh, + open); if (status) goto out; break; @@ -227,7 +222,8 @@ nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open * open->op_truncate if the file is to be truncated * after opening, (3) do permission checking. */ - status = do_open_fhandle(rqstp, current_fh, open); + status = do_open_fhandle(rqstp, &cstate->current_fh, + open); if (status) goto out; break; @@ -248,11 +244,11 @@ nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open * successful, it (1) truncates the file if open->op_truncate was * set, (2) sets open->op_stateid, (3) sets open->op_delegation. */ - status = nfsd4_process_open2(rqstp, current_fh, open); + status = nfsd4_process_open2(rqstp, &cstate->current_fh, open); out: if (open->op_stateowner) { nfs4_get_stateowner(open->op_stateowner); - *replay_owner = open->op_stateowner; + cstate->replay_owner = open->op_stateowner; } nfs4_unlock_state(); return status; @@ -261,71 +257,80 @@ out: /* * filehandle-manipulating ops. */ -static inline __be32 -nfsd4_getfh(struct svc_fh *current_fh, struct svc_fh **getfh) +static __be32 +nfsd4_getfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + struct svc_fh **getfh) { - if (!current_fh->fh_dentry) + if (!cstate->current_fh.fh_dentry) return nfserr_nofilehandle; - *getfh = current_fh; + *getfh = &cstate->current_fh; return nfs_ok; } -static inline __be32 -nfsd4_putfh(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_putfh *putfh) +static __be32 +nfsd4_putfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + struct nfsd4_putfh *putfh) { - fh_put(current_fh); - current_fh->fh_handle.fh_size = putfh->pf_fhlen; - memcpy(¤t_fh->fh_handle.fh_base, putfh->pf_fhval, putfh->pf_fhlen); - return fh_verify(rqstp, current_fh, 0, MAY_NOP); + fh_put(&cstate->current_fh); + cstate->current_fh.fh_handle.fh_size = putfh->pf_fhlen; + memcpy(&cstate->current_fh.fh_handle.fh_base, putfh->pf_fhval, + putfh->pf_fhlen); + return fh_verify(rqstp, &cstate->current_fh, 0, MAY_NOP); } -static inline __be32 -nfsd4_putrootfh(struct svc_rqst *rqstp, struct svc_fh *current_fh) +static __be32 +nfsd4_putrootfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + void *arg) { __be32 status; - fh_put(current_fh); - status = exp_pseudoroot(rqstp->rq_client, current_fh, + fh_put(&cstate->current_fh); + status = exp_pseudoroot(rqstp->rq_client, &cstate->current_fh, &rqstp->rq_chandle); return status; } -static inline __be32 -nfsd4_restorefh(struct svc_fh *current_fh, struct svc_fh *save_fh) +static __be32 +nfsd4_restorefh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + void *arg) { - if (!save_fh->fh_dentry) + if (!cstate->save_fh.fh_dentry) return nfserr_restorefh; - fh_dup2(current_fh, save_fh); + fh_dup2(&cstate->current_fh, &cstate->save_fh); return nfs_ok; } -static inline __be32 -nfsd4_savefh(struct svc_fh *current_fh, struct svc_fh *save_fh) +static __be32 +nfsd4_savefh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + void *arg) { - if (!current_fh->fh_dentry) + if (!cstate->current_fh.fh_dentry) return nfserr_nofilehandle; - fh_dup2(save_fh, current_fh); + fh_dup2(&cstate->save_fh, &cstate->current_fh); return nfs_ok; } /* * misc nfsv4 ops */ -static inline __be32 -nfsd4_access(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_access *access) +static __be32 +nfsd4_access(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + struct nfsd4_access *access) { if (access->ac_req_access & ~NFS3_ACCESS_FULL) return nfserr_inval; access->ac_resp_access = access->ac_req_access; - return nfsd_access(rqstp, current_fh, &access->ac_resp_access, &access->ac_supported); + return nfsd_access(rqstp, &cstate->current_fh, &access->ac_resp_access, + &access->ac_supported); } -static inline __be32 -nfsd4_commit(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_commit *commit) +static __be32 +nfsd4_commit(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + struct nfsd4_commit *commit) { __be32 status; @@ -333,14 +338,16 @@ nfsd4_commit(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_com *p++ = nfssvc_boot.tv_sec; *p++ = nfssvc_boot.tv_usec; - status = nfsd_commit(rqstp, current_fh, commit->co_offset, commit->co_count); + status = nfsd_commit(rqstp, &cstate->current_fh, commit->co_offset, + commit->co_count); if (status == nfserr_symlink) status = nfserr_inval; return status; } static __be32 -nfsd4_create(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_create *create) +nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + struct nfsd4_create *create) { struct svc_fh resfh; __be32 status; @@ -348,7 +355,7 @@ nfsd4_create(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_cre fh_init(&resfh, NFS4_FHSIZE); - status = fh_verify(rqstp, current_fh, S_IFDIR, MAY_CREATE); + status = fh_verify(rqstp, &cstate->current_fh, S_IFDIR, MAY_CREATE); if (status == nfserr_symlink) status = nfserr_notdir; if (status) @@ -365,9 +372,10 @@ nfsd4_create(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_cre */ create->cr_linkname[create->cr_linklen] = 0; - status = nfsd_symlink(rqstp, current_fh, create->cr_name, - create->cr_namelen, create->cr_linkname, - create->cr_linklen, &resfh, &create->cr_iattr); + status = nfsd_symlink(rqstp, &cstate->current_fh, + create->cr_name, create->cr_namelen, + create->cr_linkname, create->cr_linklen, + &resfh, &create->cr_iattr); break; case NF4BLK: @@ -375,9 +383,9 @@ nfsd4_create(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_cre if (MAJOR(rdev) != create->cr_specdata1 || MINOR(rdev) != create->cr_specdata2) return nfserr_inval; - status = nfsd_create(rqstp, current_fh, create->cr_name, - create->cr_namelen, &create->cr_iattr, - S_IFBLK, rdev, &resfh); + status = nfsd_create(rqstp, &cstate->current_fh, + create->cr_name, create->cr_namelen, + &create->cr_iattr, S_IFBLK, rdev, &resfh); break; case NF4CHR: @@ -385,28 +393,28 @@ nfsd4_create(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_cre if (MAJOR(rdev) != create->cr_specdata1 || MINOR(rdev) != create->cr_specdata2) return nfserr_inval; - status = nfsd_create(rqstp, current_fh, create->cr_name, - create->cr_namelen, &create->cr_iattr, - S_IFCHR, rdev, &resfh); + status = nfsd_create(rqstp, &cstate->current_fh, + create->cr_name, create->cr_namelen, + &create->cr_iattr,S_IFCHR, rdev, &resfh); break; case NF4SOCK: - status = nfsd_create(rqstp, current_fh, create->cr_name, - create->cr_namelen, &create->cr_iattr, - S_IFSOCK, 0, &resfh); + status = nfsd_create(rqstp, &cstate->current_fh, + create->cr_name, create->cr_namelen, + &create->cr_iattr, S_IFSOCK, 0, &resfh); break; case NF4FIFO: - status = nfsd_create(rqstp, current_fh, create->cr_name, - create->cr_namelen, &create->cr_iattr, - S_IFIFO, 0, &resfh); + status = nfsd_create(rqstp, &cstate->current_fh, + create->cr_name, create->cr_namelen, + &create->cr_iattr, S_IFIFO, 0, &resfh); break; case NF4DIR: create->cr_iattr.ia_valid &= ~ATTR_SIZE; - status = nfsd_create(rqstp, current_fh, create->cr_name, - create->cr_namelen, &create->cr_iattr, - S_IFDIR, 0, &resfh); + status = nfsd_create(rqstp, &cstate->current_fh, + create->cr_name, create->cr_namelen, + &create->cr_iattr, S_IFDIR, 0, &resfh); break; default: @@ -414,21 +422,22 @@ nfsd4_create(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_cre } if (!status) { - fh_unlock(current_fh); - set_change_info(&create->cr_cinfo, current_fh); - fh_dup2(current_fh, &resfh); + fh_unlock(&cstate->current_fh); + set_change_info(&create->cr_cinfo, &cstate->current_fh); + fh_dup2(&cstate->current_fh, &resfh); } fh_put(&resfh); return status; } -static inline __be32 -nfsd4_getattr(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_getattr *getattr) +static __be32 +nfsd4_getattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + struct nfsd4_getattr *getattr) { __be32 status; - status = fh_verify(rqstp, current_fh, 0, MAY_NOP); + status = fh_verify(rqstp, &cstate->current_fh, 0, MAY_NOP); if (status) return status; @@ -438,26 +447,28 @@ nfsd4_getattr(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_ge getattr->ga_bmval[0] &= NFSD_SUPPORTED_ATTRS_WORD0; getattr->ga_bmval[1] &= NFSD_SUPPORTED_ATTRS_WORD1; - getattr->ga_fhp = current_fh; + getattr->ga_fhp = &cstate->current_fh; return nfs_ok; } -static inline __be32 -nfsd4_link(struct svc_rqst *rqstp, struct svc_fh *current_fh, - struct svc_fh *save_fh, struct nfsd4_link *link) +static __be32 +nfsd4_link(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + struct nfsd4_link *link) { __be32 status = nfserr_nofilehandle; - if (!save_fh->fh_dentry) + if (!cstate->save_fh.fh_dentry) return status; - status = nfsd_link(rqstp, current_fh, link->li_name, link->li_namelen, save_fh); + status = nfsd_link(rqstp, &cstate->current_fh, + link->li_name, link->li_namelen, &cstate->save_fh); if (!status) - set_change_info(&link->li_cinfo, current_fh); + set_change_info(&link->li_cinfo, &cstate->current_fh); return status; } static __be32 -nfsd4_lookupp(struct svc_rqst *rqstp, struct svc_fh *current_fh) +nfsd4_lookupp(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + void *arg) { struct svc_fh tmp_fh; __be32 ret; @@ -466,22 +477,27 @@ nfsd4_lookupp(struct svc_rqst *rqstp, struct svc_fh *current_fh) if((ret = exp_pseudoroot(rqstp->rq_client, &tmp_fh, &rqstp->rq_chandle)) != 0) return ret; - if (tmp_fh.fh_dentry == current_fh->fh_dentry) { + if (tmp_fh.fh_dentry == cstate->current_fh.fh_dentry) { fh_put(&tmp_fh); return nfserr_noent; } fh_put(&tmp_fh); - return nfsd_lookup(rqstp, current_fh, "..", 2, current_fh); + return nfsd_lookup(rqstp, &cstate->current_fh, + "..", 2, &cstate->current_fh); } -static inline __be32 -nfsd4_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lookup *lookup) +static __be32 +nfsd4_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + struct nfsd4_lookup *lookup) { - return nfsd_lookup(rqstp, current_fh, lookup->lo_name, lookup->lo_len, current_fh); + return nfsd_lookup(rqstp, &cstate->current_fh, + lookup->lo_name, lookup->lo_len, + &cstate->current_fh); } -static inline __be32 -nfsd4_read(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_read *read) +static __be32 +nfsd4_read(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + struct nfsd4_read *read) { __be32 status; @@ -493,7 +509,8 @@ nfsd4_read(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_read nfs4_lock_state(); /* check stateid */ - if ((status = nfs4_preprocess_stateid_op(current_fh, &read->rd_stateid, + if ((status = nfs4_preprocess_stateid_op(&cstate->current_fh, + &read->rd_stateid, CHECK_FH | RD_STATE, &read->rd_filp))) { dprintk("NFSD: nfsd4_read: couldn't process stateid!\n"); goto out; @@ -504,12 +521,13 @@ nfsd4_read(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_read out: nfs4_unlock_state(); read->rd_rqstp = rqstp; - read->rd_fhp = current_fh; + read->rd_fhp = &cstate->current_fh; return status; } -static inline __be32 -nfsd4_readdir(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_readdir *readdir) +static __be32 +nfsd4_readdir(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + struct nfsd4_readdir *readdir) { u64 cookie = readdir->rd_cookie; static const nfs4_verifier zeroverf; @@ -527,48 +545,51 @@ nfsd4_readdir(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_re return nfserr_bad_cookie; readdir->rd_rqstp = rqstp; - readdir->rd_fhp = current_fh; + readdir->rd_fhp = &cstate->current_fh; return nfs_ok; } -static inline __be32 -nfsd4_readlink(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_readlink *readlink) +static __be32 +nfsd4_readlink(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + struct nfsd4_readlink *readlink) { readlink->rl_rqstp = rqstp; - readlink->rl_fhp = current_fh; + readlink->rl_fhp = &cstate->current_fh; return nfs_ok; } -static inline __be32 -nfsd4_remove(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_remove *remove) +static __be32 +nfsd4_remove(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + struct nfsd4_remove *remove) { __be32 status; if (nfs4_in_grace()) return nfserr_grace; - status = nfsd_unlink(rqstp, current_fh, 0, remove->rm_name, remove->rm_namelen); + status = nfsd_unlink(rqstp, &cstate->current_fh, 0, + remove->rm_name, remove->rm_namelen); if (status == nfserr_symlink) return nfserr_notdir; if (!status) { - fh_unlock(current_fh); - set_change_info(&remove->rm_cinfo, current_fh); + fh_unlock(&cstate->current_fh); + set_change_info(&remove->rm_cinfo, &cstate->current_fh); } return status; } -static inline __be32 -nfsd4_rename(struct svc_rqst *rqstp, struct svc_fh *current_fh, - struct svc_fh *save_fh, struct nfsd4_rename *rename) +static __be32 +nfsd4_rename(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + struct nfsd4_rename *rename) { __be32 status = nfserr_nofilehandle; - if (!save_fh->fh_dentry) + if (!cstate->save_fh.fh_dentry) return status; - if (nfs4_in_grace() && !(save_fh->fh_export->ex_flags + if (nfs4_in_grace() && !(cstate->save_fh.fh_export->ex_flags & NFSEXP_NOSUBTREECHECK)) return nfserr_grace; - status = nfsd_rename(rqstp, save_fh, rename->rn_sname, - rename->rn_snamelen, current_fh, + status = nfsd_rename(rqstp, &cstate->save_fh, rename->rn_sname, + rename->rn_snamelen, &cstate->current_fh, rename->rn_tname, rename->rn_tnamelen); /* the underlying filesystem returns different error's than required @@ -576,27 +597,28 @@ nfsd4_rename(struct svc_rqst *rqstp, struct svc_fh *current_fh, if (status == nfserr_isdir) status = nfserr_exist; else if ((status == nfserr_notdir) && - (S_ISDIR(save_fh->fh_dentry->d_inode->i_mode) && - S_ISDIR(current_fh->fh_dentry->d_inode->i_mode))) + (S_ISDIR(cstate->save_fh.fh_dentry->d_inode->i_mode) && + S_ISDIR(cstate->current_fh.fh_dentry->d_inode->i_mode))) status = nfserr_exist; else if (status == nfserr_symlink) status = nfserr_notdir; if (!status) { - set_change_info(&rename->rn_sinfo, current_fh); - set_change_info(&rename->rn_tinfo, save_fh); + set_change_info(&rename->rn_sinfo, &cstate->current_fh); + set_change_info(&rename->rn_tinfo, &cstate->save_fh); } return status; } -static inline __be32 -nfsd4_setattr(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_setattr *setattr) +static __be32 +nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + struct nfsd4_setattr *setattr) { __be32 status = nfs_ok; if (setattr->sa_iattr.ia_valid & ATTR_SIZE) { nfs4_lock_state(); - status = nfs4_preprocess_stateid_op(current_fh, + status = nfs4_preprocess_stateid_op(&cstate->current_fh, &setattr->sa_stateid, CHECK_FH | WR_STATE, NULL); nfs4_unlock_state(); if (status) { @@ -606,16 +628,18 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_se } status = nfs_ok; if (setattr->sa_acl != NULL) - status = nfsd4_set_nfs4_acl(rqstp, current_fh, setattr->sa_acl); + status = nfsd4_set_nfs4_acl(rqstp, &cstate->current_fh, + setattr->sa_acl); if (status) return status; - status = nfsd_setattr(rqstp, current_fh, &setattr->sa_iattr, + status = nfsd_setattr(rqstp, &cstate->current_fh, &setattr->sa_iattr, 0, (time_t)0); return status; } -static inline __be32 -nfsd4_write(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_write *write) +static __be32 +nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + struct nfsd4_write *write) { stateid_t *stateid = &write->wr_stateid; struct file *filp = NULL; @@ -628,7 +652,7 @@ nfsd4_write(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_writ return nfserr_inval; nfs4_lock_state(); - status = nfs4_preprocess_stateid_op(current_fh, stateid, + status = nfs4_preprocess_stateid_op(&cstate->current_fh, stateid, CHECK_FH | WR_STATE, &filp); if (filp) get_file(filp); @@ -645,9 +669,9 @@ nfsd4_write(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_writ *p++ = nfssvc_boot.tv_sec; *p++ = nfssvc_boot.tv_usec; - status = nfsd_write(rqstp, current_fh, filp, write->wr_offset, - rqstp->rq_vec, write->wr_vlen, write->wr_buflen, - &write->wr_how_written); + status = nfsd_write(rqstp, &cstate->current_fh, filp, + write->wr_offset, rqstp->rq_vec, write->wr_vlen, + write->wr_buflen, &write->wr_how_written); if (filp) fput(filp); @@ -662,13 +686,14 @@ nfsd4_write(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_writ * to NFS_OK after the call; NVERIFY by mapping NFSERR_NOT_SAME to NFS_OK. */ static __be32 -nfsd4_verify(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_verify *verify) +_nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + struct nfsd4_verify *verify) { __be32 *buf, *p; int count; __be32 status; - status = fh_verify(rqstp, current_fh, 0, MAY_NOP); + status = fh_verify(rqstp, &cstate->current_fh, 0, MAY_NOP); if (status) return status; @@ -689,8 +714,9 @@ nfsd4_verify(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_ver if (!buf) return nfserr_resource; - status = nfsd4_encode_fattr(current_fh, current_fh->fh_export, - current_fh->fh_dentry, buf, + status = nfsd4_encode_fattr(&cstate->current_fh, + cstate->current_fh.fh_export, + cstate->current_fh.fh_dentry, buf, &count, verify->ve_bmval, rqstp); @@ -712,6 +738,26 @@ out_kfree: return status; } +static __be32 +nfsd4_nverify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + struct nfsd4_verify *verify) +{ + __be32 status; + + status = _nfsd4_verify(rqstp, cstate, verify); + return status == nfserr_not_same ? nfs_ok : status; +} + +static __be32 +nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + struct nfsd4_verify *verify) +{ + __be32 status; + + status = _nfsd4_verify(rqstp, cstate, verify); + return status == nfserr_same ? nfs_ok : status; +} + /* * NULL call. */ @@ -727,6 +773,42 @@ static inline void nfsd4_increment_op_stats(u32 opnum) nfsdstats.nfs4_opcount[opnum]++; } +static void cstate_free(struct nfsd4_compound_state *cstate) +{ + if (cstate == NULL) + return; + fh_put(&cstate->current_fh); + fh_put(&cstate->save_fh); + BUG_ON(cstate->replay_owner); + kfree(cstate); +} + +static struct nfsd4_compound_state *cstate_alloc(void) +{ + struct nfsd4_compound_state *cstate; + + cstate = kmalloc(sizeof(struct nfsd4_compound_state), GFP_KERNEL); + if (cstate == NULL) + return NULL; + fh_init(&cstate->current_fh, NFS4_FHSIZE); + fh_init(&cstate->save_fh, NFS4_FHSIZE); + cstate->replay_owner = NULL; + return cstate; +} + +typedef __be32(*nfsd4op_func)(struct svc_rqst *, struct nfsd4_compound_state *, + void *); + +struct nfsd4_operation { + nfsd4op_func op_func; + u32 op_flags; +/* Most ops require a valid current filehandle; a few don't: */ +#define ALLOWED_WITHOUT_FH 1 +/* GETATTR and ops not listed as returning NFS4ERR_MOVED: */ +#define ALLOWED_ON_ABSENT_FS 2 +}; + +static struct nfsd4_operation nfsd4_ops[]; /* * COMPOUND call. @@ -737,21 +819,15 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, struct nfsd4_compoundres *resp) { struct nfsd4_op *op; - struct svc_fh *current_fh = NULL; - struct svc_fh *save_fh = NULL; - struct nfs4_stateowner *replay_owner = NULL; - int slack_space; /* in words, not bytes! */ + struct nfsd4_operation *opdesc; + struct nfsd4_compound_state *cstate = NULL; + int slack_bytes; __be32 status; status = nfserr_resource; - current_fh = kmalloc(sizeof(*current_fh), GFP_KERNEL); - if (current_fh == NULL) - goto out; - fh_init(current_fh, NFS4_FHSIZE); - save_fh = kmalloc(sizeof(*save_fh), GFP_KERNEL); - if (save_fh == NULL) + cstate = cstate_alloc(); + if (cstate == NULL) goto out; - fh_init(save_fh, NFS4_FHSIZE); resp->xbuf = &rqstp->rq_res; resp->p = rqstp->rq_res.head[0].iov_base + rqstp->rq_res.head[0].iov_len; @@ -790,164 +866,44 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, * failed response to the next operation. If we don't * have enough room, fail with ERR_RESOURCE. */ -/* FIXME - is slack_space *really* words, or bytes??? - neilb */ - slack_space = (char *)resp->end - (char *)resp->p; - if (slack_space < COMPOUND_SLACK_SPACE + COMPOUND_ERR_SLACK_SPACE) { - BUG_ON(slack_space < COMPOUND_ERR_SLACK_SPACE); + slack_bytes = (char *)resp->end - (char *)resp->p; + if (slack_bytes < COMPOUND_SLACK_SPACE + + COMPOUND_ERR_SLACK_SPACE) { + BUG_ON(slack_bytes < COMPOUND_ERR_SLACK_SPACE); op->status = nfserr_resource; goto encode_op; } - /* All operations except RENEW, SETCLIENTID, RESTOREFH - * SETCLIENTID_CONFIRM, PUTFH and PUTROOTFH - * require a valid current filehandle - */ - if (!current_fh->fh_dentry) { - if (!((op->opnum == OP_PUTFH) || - (op->opnum == OP_PUTROOTFH) || - (op->opnum == OP_SETCLIENTID) || - (op->opnum == OP_SETCLIENTID_CONFIRM) || - (op->opnum == OP_RENEW) || - (op->opnum == OP_RESTOREFH) || - (op->opnum == OP_RELEASE_LOCKOWNER))) { + opdesc = &nfsd4_ops[op->opnum]; + + if (!cstate->current_fh.fh_dentry) { + if (!(opdesc->op_flags & ALLOWED_WITHOUT_FH)) { op->status = nfserr_nofilehandle; goto encode_op; } - } - /* Check must be done at start of each operation, except - * for GETATTR and ops not listed as returning NFS4ERR_MOVED - */ - else if (current_fh->fh_export->ex_fslocs.migrated && - !((op->opnum == OP_GETATTR) || - (op->opnum == OP_PUTROOTFH) || - (op->opnum == OP_PUTPUBFH) || - (op->opnum == OP_RENEW) || - (op->opnum == OP_SETCLIENTID) || - (op->opnum == OP_RELEASE_LOCKOWNER))) { + } else if (cstate->current_fh.fh_export->ex_fslocs.migrated && + !(opdesc->op_flags & ALLOWED_ON_ABSENT_FS)) { op->status = nfserr_moved; goto encode_op; } - switch (op->opnum) { - case OP_ACCESS: - op->status = nfsd4_access(rqstp, current_fh, &op->u.access); - break; - case OP_CLOSE: - op->status = nfsd4_close(rqstp, current_fh, &op->u.close, &replay_owner); - break; - case OP_COMMIT: - op->status = nfsd4_commit(rqstp, current_fh, &op->u.commit); - break; - case OP_CREATE: - op->status = nfsd4_create(rqstp, current_fh, &op->u.create); - break; - case OP_DELEGRETURN: - op->status = nfsd4_delegreturn(rqstp, current_fh, &op->u.delegreturn); - break; - case OP_GETATTR: - op->status = nfsd4_getattr(rqstp, current_fh, &op->u.getattr); - break; - case OP_GETFH: - op->status = nfsd4_getfh(current_fh, &op->u.getfh); - break; - case OP_LINK: - op->status = nfsd4_link(rqstp, current_fh, save_fh, &op->u.link); - break; - case OP_LOCK: - op->status = nfsd4_lock(rqstp, current_fh, &op->u.lock, &replay_owner); - break; - case OP_LOCKT: - op->status = nfsd4_lockt(rqstp, current_fh, &op->u.lockt); - break; - case OP_LOCKU: - op->status = nfsd4_locku(rqstp, current_fh, &op->u.locku, &replay_owner); - break; - case OP_LOOKUP: - op->status = nfsd4_lookup(rqstp, current_fh, &op->u.lookup); - break; - case OP_LOOKUPP: - op->status = nfsd4_lookupp(rqstp, current_fh); - break; - case OP_NVERIFY: - op->status = nfsd4_verify(rqstp, current_fh, &op->u.nverify); - if (op->status == nfserr_not_same) - op->status = nfs_ok; - break; - case OP_OPEN: - op->status = nfsd4_open(rqstp, current_fh, &op->u.open, &replay_owner); - break; - case OP_OPEN_CONFIRM: - op->status = nfsd4_open_confirm(rqstp, current_fh, &op->u.open_confirm, &replay_owner); - break; - case OP_OPEN_DOWNGRADE: - op->status = nfsd4_open_downgrade(rqstp, current_fh, &op->u.open_downgrade, &replay_owner); - break; - case OP_PUTFH: - op->status = nfsd4_putfh(rqstp, current_fh, &op->u.putfh); - break; - case OP_PUTROOTFH: - op->status = nfsd4_putrootfh(rqstp, current_fh); - break; - case OP_READ: - op->status = nfsd4_read(rqstp, current_fh, &op->u.read); - break; - case OP_READDIR: - op->status = nfsd4_readdir(rqstp, current_fh, &op->u.readdir); - break; - case OP_READLINK: - op->status = nfsd4_readlink(rqstp, current_fh, &op->u.readlink); - break; - case OP_REMOVE: - op->status = nfsd4_remove(rqstp, current_fh, &op->u.remove); - break; - case OP_RENAME: - op->status = nfsd4_rename(rqstp, current_fh, save_fh, &op->u.rename); - break; - case OP_RENEW: - op->status = nfsd4_renew(&op->u.renew); - break; - case OP_RESTOREFH: - op->status = nfsd4_restorefh(current_fh, save_fh); - break; - case OP_SAVEFH: - op->status = nfsd4_savefh(current_fh, save_fh); - break; - case OP_SETATTR: - op->status = nfsd4_setattr(rqstp, current_fh, &op->u.setattr); - break; - case OP_SETCLIENTID: - op->status = nfsd4_setclientid(rqstp, &op->u.setclientid); - break; - case OP_SETCLIENTID_CONFIRM: - op->status = nfsd4_setclientid_confirm(rqstp, &op->u.setclientid_confirm); - break; - case OP_VERIFY: - op->status = nfsd4_verify(rqstp, current_fh, &op->u.verify); - if (op->status == nfserr_same) - op->status = nfs_ok; - break; - case OP_WRITE: - op->status = nfsd4_write(rqstp, current_fh, &op->u.write); - break; - case OP_RELEASE_LOCKOWNER: - op->status = nfsd4_release_lockowner(rqstp, &op->u.release_lockowner); - break; - default: + + if (opdesc->op_func) + op->status = opdesc->op_func(rqstp, cstate, &op->u); + else BUG_ON(op->status == nfs_ok); - break; - } encode_op: if (op->status == nfserr_replay_me) { - op->replay = &replay_owner->so_replay; + op->replay = &cstate->replay_owner->so_replay; nfsd4_encode_replay(resp, op); status = op->status = op->replay->rp_status; } else { nfsd4_encode_operation(resp, op); status = op->status; } - if (replay_owner && (replay_owner != (void *)(-1))) { - nfs4_put_stateowner(replay_owner); - replay_owner = NULL; + if (cstate->replay_owner) { + nfs4_put_stateowner(cstate->replay_owner); + cstate->replay_owner = NULL; } /* XXX Ugh, we need to get rid of this kind of special case: */ if (op->opnum == OP_READ && op->u.read.rd_filp) @@ -958,15 +914,124 @@ encode_op: out: nfsd4_release_compoundargs(args); - if (current_fh) - fh_put(current_fh); - kfree(current_fh); - if (save_fh) - fh_put(save_fh); - kfree(save_fh); + cstate_free(cstate); return status; } +static struct nfsd4_operation nfsd4_ops[OP_RELEASE_LOCKOWNER+1] = { + [OP_ACCESS] = { + .op_func = (nfsd4op_func)nfsd4_access, + }, + [OP_CLOSE] = { + .op_func = (nfsd4op_func)nfsd4_close, + }, + [OP_COMMIT] = { + .op_func = (nfsd4op_func)nfsd4_commit, + }, + [OP_CREATE] = { + .op_func = (nfsd4op_func)nfsd4_create, + }, + [OP_DELEGRETURN] = { + .op_func = (nfsd4op_func)nfsd4_delegreturn, + }, + [OP_GETATTR] = { + .op_func = (nfsd4op_func)nfsd4_getattr, + .op_flags = ALLOWED_ON_ABSENT_FS, + }, + [OP_GETFH] = { + .op_func = (nfsd4op_func)nfsd4_getfh, + }, + [OP_LINK] = { + .op_func = (nfsd4op_func)nfsd4_link, + }, + [OP_LOCK] = { + .op_func = (nfsd4op_func)nfsd4_lock, + }, + [OP_LOCKT] = { + .op_func = (nfsd4op_func)nfsd4_lockt, + }, + [OP_LOCKU] = { + .op_func = (nfsd4op_func)nfsd4_locku, + }, + [OP_LOOKUP] = { + .op_func = (nfsd4op_func)nfsd4_lookup, + }, + [OP_LOOKUPP] = { + .op_func = (nfsd4op_func)nfsd4_lookupp, + }, + [OP_NVERIFY] = { + .op_func = (nfsd4op_func)nfsd4_nverify, + }, + [OP_OPEN] = { + .op_func = (nfsd4op_func)nfsd4_open, + }, + [OP_OPEN_CONFIRM] = { + .op_func = (nfsd4op_func)nfsd4_open_confirm, + }, + [OP_OPEN_DOWNGRADE] = { + .op_func = (nfsd4op_func)nfsd4_open_downgrade, + }, + [OP_PUTFH] = { + .op_func = (nfsd4op_func)nfsd4_putfh, + .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, + }, + [OP_PUTPUBFH] = { + /* unsupported; just for future reference: */ + .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, + }, + [OP_PUTROOTFH] = { + .op_func = (nfsd4op_func)nfsd4_putrootfh, + .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, + }, + [OP_READ] = { + .op_func = (nfsd4op_func)nfsd4_read, + }, + [OP_READDIR] = { + .op_func = (nfsd4op_func)nfsd4_readdir, + }, + [OP_READLINK] = { + .op_func = (nfsd4op_func)nfsd4_readlink, + }, + [OP_REMOVE] = { + .op_func = (nfsd4op_func)nfsd4_remove, + }, + [OP_RENAME] = { + .op_func = (nfsd4op_func)nfsd4_rename, + }, + [OP_RENEW] = { + .op_func = (nfsd4op_func)nfsd4_renew, + .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, + }, + [OP_RESTOREFH] = { + .op_func = (nfsd4op_func)nfsd4_restorefh, + .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, + }, + [OP_SAVEFH] = { + .op_func = (nfsd4op_func)nfsd4_savefh, + }, + [OP_SETATTR] = { + .op_func = (nfsd4op_func)nfsd4_setattr, + }, + [OP_SETCLIENTID] = { + .op_func = (nfsd4op_func)nfsd4_setclientid, + .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, + }, + [OP_SETCLIENTID_CONFIRM] = { + .op_func = (nfsd4op_func)nfsd4_setclientid_confirm, + .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, + }, + [OP_VERIFY] = { + .op_func = (nfsd4op_func)nfsd4_verify, + }, + [OP_WRITE] = { + .op_func = (nfsd4op_func)nfsd4_write, + }, + [OP_RELEASE_LOCKOWNER] = { + .op_func = (nfsd4op_func)nfsd4_release_lockowner, + .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, + }, +}; + #define nfs4svc_decode_voidargs NULL #define nfs4svc_release_void NULL #define nfsd4_voidres nfsd4_voidargs diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index b7179bd45a1e..9de89df961f4 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -711,7 +711,8 @@ out_err: * */ __be32 -nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid) +nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + struct nfsd4_setclientid *setclid) { __be32 ip_addr = rqstp->rq_addr.sin_addr.s_addr; struct xdr_netobj clname = { @@ -876,7 +877,9 @@ out: * NOTE: callback information will be processed here in a future patch */ __be32 -nfsd4_setclientid_confirm(struct svc_rqst *rqstp, struct nfsd4_setclientid_confirm *setclientid_confirm) +nfsd4_setclientid_confirm(struct svc_rqst *rqstp, + struct nfsd4_compound_state *cstate, + struct nfsd4_setclientid_confirm *setclientid_confirm) { __be32 ip_addr = rqstp->rq_addr.sin_addr.s_addr; struct nfs4_client *conf, *unconf; @@ -1833,7 +1836,8 @@ static void laundromat_main(struct work_struct *); static DECLARE_DELAYED_WORK(laundromat_work, laundromat_main); __be32 -nfsd4_renew(clientid_t *clid) +nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + clientid_t *clid) { struct nfs4_client *clp; __be32 status; @@ -2241,24 +2245,25 @@ check_replay: } __be32 -nfsd4_open_confirm(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_confirm *oc, struct nfs4_stateowner **replay_owner) +nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + struct nfsd4_open_confirm *oc) { __be32 status; struct nfs4_stateowner *sop; struct nfs4_stateid *stp; dprintk("NFSD: nfsd4_open_confirm on file %.*s\n", - (int)current_fh->fh_dentry->d_name.len, - current_fh->fh_dentry->d_name.name); + (int)cstate->current_fh.fh_dentry->d_name.len, + cstate->current_fh.fh_dentry->d_name.name); - status = fh_verify(rqstp, current_fh, S_IFREG, 0); + status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0); if (status) return status; nfs4_lock_state(); - if ((status = nfs4_preprocess_seqid_op(current_fh, oc->oc_seqid, - &oc->oc_req_stateid, + if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh, + oc->oc_seqid, &oc->oc_req_stateid, CHECK_FH | CONFIRM | OPEN_STATE, &oc->oc_stateowner, &stp, NULL))) goto out; @@ -2278,7 +2283,7 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfs out: if (oc->oc_stateowner) { nfs4_get_stateowner(oc->oc_stateowner); - *replay_owner = oc->oc_stateowner; + cstate->replay_owner = oc->oc_stateowner; } nfs4_unlock_state(); return status; @@ -2310,22 +2315,25 @@ reset_union_bmap_deny(unsigned long deny, unsigned long *bmap) } __be32 -nfsd4_open_downgrade(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_downgrade *od, struct nfs4_stateowner **replay_owner) +nfsd4_open_downgrade(struct svc_rqst *rqstp, + struct nfsd4_compound_state *cstate, + struct nfsd4_open_downgrade *od) { __be32 status; struct nfs4_stateid *stp; unsigned int share_access; dprintk("NFSD: nfsd4_open_downgrade on file %.*s\n", - (int)current_fh->fh_dentry->d_name.len, - current_fh->fh_dentry->d_name.name); + (int)cstate->current_fh.fh_dentry->d_name.len, + cstate->current_fh.fh_dentry->d_name.name); if (!access_valid(od->od_share_access) || !deny_valid(od->od_share_deny)) return nfserr_inval; nfs4_lock_state(); - if ((status = nfs4_preprocess_seqid_op(current_fh, od->od_seqid, + if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh, + od->od_seqid, &od->od_stateid, CHECK_FH | OPEN_STATE, &od->od_stateowner, &stp, NULL))) @@ -2355,7 +2363,7 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct n out: if (od->od_stateowner) { nfs4_get_stateowner(od->od_stateowner); - *replay_owner = od->od_stateowner; + cstate->replay_owner = od->od_stateowner; } nfs4_unlock_state(); return status; @@ -2365,18 +2373,20 @@ out: * nfs4_unlock_state() called after encode */ __be32 -nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_close *close, struct nfs4_stateowner **replay_owner) +nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + struct nfsd4_close *close) { __be32 status; struct nfs4_stateid *stp; dprintk("NFSD: nfsd4_close on file %.*s\n", - (int)current_fh->fh_dentry->d_name.len, - current_fh->fh_dentry->d_name.name); + (int)cstate->current_fh.fh_dentry->d_name.len, + cstate->current_fh.fh_dentry->d_name.name); nfs4_lock_state(); /* check close_lru for replay */ - if ((status = nfs4_preprocess_seqid_op(current_fh, close->cl_seqid, + if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh, + close->cl_seqid, &close->cl_stateid, CHECK_FH | OPEN_STATE | CLOSE_STATE, &close->cl_stateowner, &stp, NULL))) @@ -2397,22 +2407,24 @@ nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_clos out: if (close->cl_stateowner) { nfs4_get_stateowner(close->cl_stateowner); - *replay_owner = close->cl_stateowner; + cstate->replay_owner = close->cl_stateowner; } nfs4_unlock_state(); return status; } __be32 -nfsd4_delegreturn(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_delegreturn *dr) +nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + struct nfsd4_delegreturn *dr) { __be32 status; - if ((status = fh_verify(rqstp, current_fh, S_IFREG, 0))) + if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) goto out; nfs4_lock_state(); - status = nfs4_preprocess_stateid_op(current_fh, &dr->dr_stateid, DELEG_RET, NULL); + status = nfs4_preprocess_stateid_op(&cstate->current_fh, + &dr->dr_stateid, DELEG_RET, NULL); nfs4_unlock_state(); out: return status; @@ -2635,7 +2647,8 @@ check_lock_length(u64 offset, u64 length) * LOCK operation */ __be32 -nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock *lock, struct nfs4_stateowner **replay_owner) +nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + struct nfsd4_lock *lock) { struct nfs4_stateowner *open_sop = NULL; struct nfs4_stateowner *lock_sop = NULL; @@ -2654,7 +2667,8 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock if (check_lock_length(lock->lk_offset, lock->lk_length)) return nfserr_inval; - if ((status = fh_verify(rqstp, current_fh, S_IFREG, MAY_LOCK))) { + if ((status = fh_verify(rqstp, &cstate->current_fh, + S_IFREG, MAY_LOCK))) { dprintk("NFSD: nfsd4_lock: permission denied!\n"); return status; } @@ -2675,7 +2689,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock goto out; /* validate and update open stateid and open seqid */ - status = nfs4_preprocess_seqid_op(current_fh, + status = nfs4_preprocess_seqid_op(&cstate->current_fh, lock->lk_new_open_seqid, &lock->lk_new_open_stateid, CHECK_FH | OPEN_STATE, @@ -2702,7 +2716,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock goto out; } else { /* lock (lock owner + lock stateid) already exists */ - status = nfs4_preprocess_seqid_op(current_fh, + status = nfs4_preprocess_seqid_op(&cstate->current_fh, lock->lk_old_lock_seqid, &lock->lk_old_lock_stateid, CHECK_FH | LOCK_STATE, @@ -2759,7 +2773,6 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock conflock.fl_ops = NULL; conflock.fl_lmops = NULL; err = posix_lock_file_conf(filp, &file_lock, &conflock); - dprintk("NFSD: nfsd4_lock: posix_lock_file_conf status %d\n",status); switch (-err) { case 0: /* success! */ update_stateid(&lock_stp->st_stateid); @@ -2785,7 +2798,7 @@ out: release_stateowner(lock_sop); if (lock->lk_replay_owner) { nfs4_get_stateowner(lock->lk_replay_owner); - *replay_owner = lock->lk_replay_owner; + cstate->replay_owner = lock->lk_replay_owner; } nfs4_unlock_state(); return status; @@ -2795,7 +2808,8 @@ out: * LOCKT operation */ __be32 -nfsd4_lockt(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lockt *lockt) +nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + struct nfsd4_lockt *lockt) { struct inode *inode; struct file file; @@ -2816,14 +2830,14 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock if (STALE_CLIENTID(&lockt->lt_clientid)) goto out; - if ((status = fh_verify(rqstp, current_fh, S_IFREG, 0))) { + if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) { dprintk("NFSD: nfsd4_lockt: fh_verify() failed!\n"); if (status == nfserr_symlink) status = nfserr_inval; goto out; } - inode = current_fh->fh_dentry->d_inode; + inode = cstate->current_fh.fh_dentry->d_inode; locks_init_lock(&file_lock); switch (lockt->lt_type) { case NFS4_READ_LT: @@ -2862,7 +2876,7 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock * only the dentry:inode set. */ memset(&file, 0, sizeof (struct file)); - file.f_path.dentry = current_fh->fh_dentry; + file.f_path.dentry = cstate->current_fh.fh_dentry; status = nfs_ok; if (posix_test_lock(&file, &file_lock, &conflock)) { @@ -2875,7 +2889,8 @@ out: } __be32 -nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_locku *locku, struct nfs4_stateowner **replay_owner) +nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + struct nfsd4_locku *locku) { struct nfs4_stateid *stp; struct file *filp = NULL; @@ -2892,7 +2907,7 @@ nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock nfs4_lock_state(); - if ((status = nfs4_preprocess_seqid_op(current_fh, + if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh, locku->lu_seqid, &locku->lu_stateid, CHECK_FH | LOCK_STATE, @@ -2933,7 +2948,7 @@ nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock out: if (locku->lu_stateowner) { nfs4_get_stateowner(locku->lu_stateowner); - *replay_owner = locku->lu_stateowner; + cstate->replay_owner = locku->lu_stateowner; } nfs4_unlock_state(); return status; @@ -2968,7 +2983,9 @@ out: } __be32 -nfsd4_release_lockowner(struct svc_rqst *rqstp, struct nfsd4_release_lockowner *rlockowner) +nfsd4_release_lockowner(struct svc_rqst *rqstp, + struct nfsd4_compound_state *cstate, + struct nfsd4_release_lockowner *rlockowner) { clientid_t *clid = &rlockowner->rl_clientid; struct nfs4_stateowner *sop; diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index f3f239db04bb..fea46368afb2 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -1845,15 +1845,11 @@ nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd, exp_get(exp); if (d_mountpoint(dentry)) { - if (nfsd_cross_mnt(cd->rd_rqstp, &dentry, &exp)) { - /* - * -EAGAIN is the only error returned from - * nfsd_cross_mnt() and it indicates that an - * up-call has been initiated to fill in the export - * options on exp. When the answer comes back, - * this call will be retried. - */ - nfserr = nfserr_dropit; + int err; + + err = nfsd_cross_mnt(cd->rd_rqstp, &dentry, &exp); + if (err) { + nfserr = nfserrno(err); goto out_put; } diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index 727ab3bd450d..b06bf9f70efc 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c @@ -169,9 +169,11 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) exp = exp_find(rqstp->rq_client, 0, tfh, &rqstp->rq_chandle); } - error = nfserr_dropit; - if (IS_ERR(exp) && PTR_ERR(exp) == -EAGAIN) + if (IS_ERR(exp) && (PTR_ERR(exp) == -EAGAIN + || PTR_ERR(exp) == -ETIMEDOUT)) { + error = nfserrno(PTR_ERR(exp)); goto out; + } error = nfserr_stale; if (!exp || IS_ERR(exp)) diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 4883d7586229..7a79c23aa6d4 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -99,7 +99,7 @@ static struct raparm_hbucket raparm_hash[RAPARM_HASH_SIZE]; /* * Called from nfsd_lookup and encode_dirent. Check if we have crossed * a mount point. - * Returns -EAGAIN leaving *dpp and *expp unchanged, + * Returns -EAGAIN or -ETIMEDOUT leaving *dpp and *expp unchanged, * or nfs_ok having possibly changed *dpp and *expp */ int diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c index edc91ca3792a..f27e5378caf2 100644 --- a/fs/ocfs2/alloc.c +++ b/fs/ocfs2/alloc.c @@ -1959,7 +1959,7 @@ int ocfs2_prepare_truncate(struct ocfs2_super *osb, goto bail; } - *tc = kcalloc(1, sizeof(struct ocfs2_truncate_context), GFP_KERNEL); + *tc = kzalloc(sizeof(struct ocfs2_truncate_context), GFP_KERNEL); if (!(*tc)) { status = -ENOMEM; mlog_errno(status); diff --git a/fs/ocfs2/cluster/heartbeat.c b/fs/ocfs2/cluster/heartbeat.c index 4cd9a9580456..a25ef5a50386 100644 --- a/fs/ocfs2/cluster/heartbeat.c +++ b/fs/ocfs2/cluster/heartbeat.c @@ -1553,7 +1553,7 @@ static struct config_item *o2hb_heartbeat_group_make_item(struct config_group *g struct o2hb_region *reg = NULL; struct config_item *ret = NULL; - reg = kcalloc(1, sizeof(struct o2hb_region), GFP_KERNEL); + reg = kzalloc(sizeof(struct o2hb_region), GFP_KERNEL); if (reg == NULL) goto out; /* ENOMEM */ @@ -1679,7 +1679,7 @@ struct config_group *o2hb_alloc_hb_set(void) struct o2hb_heartbeat_group *hs = NULL; struct config_group *ret = NULL; - hs = kcalloc(1, sizeof(struct o2hb_heartbeat_group), GFP_KERNEL); + hs = kzalloc(sizeof(struct o2hb_heartbeat_group), GFP_KERNEL); if (hs == NULL) goto out; diff --git a/fs/ocfs2/cluster/nodemanager.c b/fs/ocfs2/cluster/nodemanager.c index 357f1d551771..b17333a0606b 100644 --- a/fs/ocfs2/cluster/nodemanager.c +++ b/fs/ocfs2/cluster/nodemanager.c @@ -714,7 +714,7 @@ static struct config_item *o2nm_node_group_make_item(struct config_group *group, if (strlen(name) > O2NM_MAX_NAME_LEN) goto out; /* ENAMETOOLONG */ - node = kcalloc(1, sizeof(struct o2nm_node), GFP_KERNEL); + node = kzalloc(sizeof(struct o2nm_node), GFP_KERNEL); if (node == NULL) goto out; /* ENOMEM */ @@ -825,8 +825,8 @@ static struct config_group *o2nm_cluster_group_make_group(struct config_group *g if (o2nm_single_cluster) goto out; /* ENOSPC */ - cluster = kcalloc(1, sizeof(struct o2nm_cluster), GFP_KERNEL); - ns = kcalloc(1, sizeof(struct o2nm_node_group), GFP_KERNEL); + cluster = kzalloc(sizeof(struct o2nm_cluster), GFP_KERNEL); + ns = kzalloc(sizeof(struct o2nm_node_group), GFP_KERNEL); defs = kcalloc(3, sizeof(struct config_group *), GFP_KERNEL); o2hb_group = o2hb_alloc_hb_set(); if (cluster == NULL || ns == NULL || o2hb_group == NULL || defs == NULL) diff --git a/fs/ocfs2/cluster/tcp.c b/fs/ocfs2/cluster/tcp.c index 457753df1ae7..ae4ff4a6636b 100644 --- a/fs/ocfs2/cluster/tcp.c +++ b/fs/ocfs2/cluster/tcp.c @@ -324,7 +324,7 @@ static struct o2net_sock_container *sc_alloc(struct o2nm_node *node) struct page *page = NULL; page = alloc_page(GFP_NOFS); - sc = kcalloc(1, sizeof(*sc), GFP_NOFS); + sc = kzalloc(sizeof(*sc), GFP_NOFS); if (sc == NULL || page == NULL) goto out; @@ -714,7 +714,7 @@ int o2net_register_handler(u32 msg_type, u32 key, u32 max_len, goto out; } - nmh = kcalloc(1, sizeof(struct o2net_msg_handler), GFP_NOFS); + nmh = kzalloc(sizeof(struct o2net_msg_handler), GFP_NOFS); if (nmh == NULL) { ret = -ENOMEM; goto out; @@ -1918,9 +1918,9 @@ int o2net_init(void) o2quo_init(); - o2net_hand = kcalloc(1, sizeof(struct o2net_handshake), GFP_KERNEL); - o2net_keep_req = kcalloc(1, sizeof(struct o2net_msg), GFP_KERNEL); - o2net_keep_resp = kcalloc(1, sizeof(struct o2net_msg), GFP_KERNEL); + o2net_hand = kzalloc(sizeof(struct o2net_handshake), GFP_KERNEL); + o2net_keep_req = kzalloc(sizeof(struct o2net_msg), GFP_KERNEL); + o2net_keep_resp = kzalloc(sizeof(struct o2net_msg), GFP_KERNEL); if (!o2net_hand || !o2net_keep_req || !o2net_keep_resp) { kfree(o2net_hand); kfree(o2net_keep_req); diff --git a/fs/ocfs2/dlm/dlmdomain.c b/fs/ocfs2/dlm/dlmdomain.c index 420a375a3949..f0b25f2dd205 100644 --- a/fs/ocfs2/dlm/dlmdomain.c +++ b/fs/ocfs2/dlm/dlmdomain.c @@ -920,7 +920,7 @@ static int dlm_try_to_join_domain(struct dlm_ctxt *dlm) mlog_entry("%p", dlm); - ctxt = kcalloc(1, sizeof(*ctxt), GFP_KERNEL); + ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL); if (!ctxt) { status = -ENOMEM; mlog_errno(status); @@ -1223,7 +1223,7 @@ static struct dlm_ctxt *dlm_alloc_ctxt(const char *domain, int i; struct dlm_ctxt *dlm = NULL; - dlm = kcalloc(1, sizeof(*dlm), GFP_KERNEL); + dlm = kzalloc(sizeof(*dlm), GFP_KERNEL); if (!dlm) { mlog_errno(-ENOMEM); goto leave; diff --git a/fs/ocfs2/dlm/dlmlock.c b/fs/ocfs2/dlm/dlmlock.c index 42a1b91979b5..e5ca3db197f6 100644 --- a/fs/ocfs2/dlm/dlmlock.c +++ b/fs/ocfs2/dlm/dlmlock.c @@ -408,13 +408,13 @@ struct dlm_lock * dlm_new_lock(int type, u8 node, u64 cookie, struct dlm_lock *lock; int kernel_allocated = 0; - lock = kcalloc(1, sizeof(*lock), GFP_NOFS); + lock = kzalloc(sizeof(*lock), GFP_NOFS); if (!lock) return NULL; if (!lksb) { /* zero memory only if kernel-allocated */ - lksb = kcalloc(1, sizeof(*lksb), GFP_NOFS); + lksb = kzalloc(sizeof(*lksb), GFP_NOFS); if (!lksb) { kfree(lock); return NULL; diff --git a/fs/ocfs2/dlm/dlmmaster.c b/fs/ocfs2/dlm/dlmmaster.c index 856012b4fa49..0ad872055cb3 100644 --- a/fs/ocfs2/dlm/dlmmaster.c +++ b/fs/ocfs2/dlm/dlmmaster.c @@ -1939,7 +1939,7 @@ int dlm_dispatch_assert_master(struct dlm_ctxt *dlm, int ignore_higher, u8 request_from, u32 flags) { struct dlm_work_item *item; - item = kcalloc(1, sizeof(*item), GFP_NOFS); + item = kzalloc(sizeof(*item), GFP_NOFS); if (!item) return -ENOMEM; diff --git a/fs/ocfs2/dlm/dlmrecovery.c b/fs/ocfs2/dlm/dlmrecovery.c index fb3e2b0817f1..367a11e9e2ed 100644 --- a/fs/ocfs2/dlm/dlmrecovery.c +++ b/fs/ocfs2/dlm/dlmrecovery.c @@ -757,7 +757,7 @@ static int dlm_init_recovery_area(struct dlm_ctxt *dlm, u8 dead_node) } BUG_ON(num == dead_node); - ndata = kcalloc(1, sizeof(*ndata), GFP_NOFS); + ndata = kzalloc(sizeof(*ndata), GFP_NOFS); if (!ndata) { dlm_destroy_recovery_area(dlm, dead_node); return -ENOMEM; @@ -842,7 +842,7 @@ int dlm_request_all_locks_handler(struct o2net_msg *msg, u32 len, void *data) } BUG_ON(lr->dead_node != dlm->reco.dead_node); - item = kcalloc(1, sizeof(*item), GFP_NOFS); + item = kzalloc(sizeof(*item), GFP_NOFS); if (!item) { dlm_put(dlm); return -ENOMEM; @@ -1323,7 +1323,7 @@ int dlm_mig_lockres_handler(struct o2net_msg *msg, u32 len, void *data) ret = -ENOMEM; buf = kmalloc(be16_to_cpu(msg->data_len), GFP_NOFS); - item = kcalloc(1, sizeof(*item), GFP_NOFS); + item = kzalloc(sizeof(*item), GFP_NOFS); if (!buf || !item) goto leave; diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index e9a82ad95c1e..9fd590b9bde3 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c @@ -153,6 +153,14 @@ int ocfs2_should_update_atime(struct inode *inode, ((vfsmnt->mnt_flags & MNT_NODIRATIME) && S_ISDIR(inode->i_mode))) return 0; + if (vfsmnt->mnt_flags & MNT_RELATIME) { + if ((timespec_compare(&inode->i_atime, &inode->i_mtime) <= 0) || + (timespec_compare(&inode->i_atime, &inode->i_ctime) <= 0)) + return 1; + + return 0; + } + now = CURRENT_TIME; if ((now.tv_sec - inode->i_atime.tv_sec <= osb->s_atime_quantum)) return 0; diff --git a/fs/ocfs2/localalloc.c b/fs/ocfs2/localalloc.c index 698d79a74ef8..4dedd9789108 100644 --- a/fs/ocfs2/localalloc.c +++ b/fs/ocfs2/localalloc.c @@ -776,7 +776,7 @@ static int ocfs2_local_alloc_reserve_for_window(struct ocfs2_super *osb, { int status; - *ac = kcalloc(1, sizeof(struct ocfs2_alloc_context), GFP_KERNEL); + *ac = kzalloc(sizeof(struct ocfs2_alloc_context), GFP_KERNEL); if (!(*ac)) { status = -ENOMEM; mlog_errno(status); diff --git a/fs/ocfs2/slot_map.c b/fs/ocfs2/slot_map.c index aa6f5aadedc4..2d3ac32cb74e 100644 --- a/fs/ocfs2/slot_map.c +++ b/fs/ocfs2/slot_map.c @@ -175,7 +175,7 @@ int ocfs2_init_slot_info(struct ocfs2_super *osb) struct buffer_head *bh = NULL; struct ocfs2_slot_info *si; - si = kcalloc(1, sizeof(struct ocfs2_slot_info), GFP_KERNEL); + si = kzalloc(sizeof(struct ocfs2_slot_info), GFP_KERNEL); if (!si) { status = -ENOMEM; mlog_errno(status); diff --git a/fs/ocfs2/suballoc.c b/fs/ocfs2/suballoc.c index 000d71cca6c5..6dbb11762759 100644 --- a/fs/ocfs2/suballoc.c +++ b/fs/ocfs2/suballoc.c @@ -488,7 +488,7 @@ int ocfs2_reserve_new_metadata(struct ocfs2_super *osb, int status; u32 slot; - *ac = kcalloc(1, sizeof(struct ocfs2_alloc_context), GFP_KERNEL); + *ac = kzalloc(sizeof(struct ocfs2_alloc_context), GFP_KERNEL); if (!(*ac)) { status = -ENOMEM; mlog_errno(status); @@ -530,7 +530,7 @@ int ocfs2_reserve_new_inode(struct ocfs2_super *osb, { int status; - *ac = kcalloc(1, sizeof(struct ocfs2_alloc_context), GFP_KERNEL); + *ac = kzalloc(sizeof(struct ocfs2_alloc_context), GFP_KERNEL); if (!(*ac)) { status = -ENOMEM; mlog_errno(status); @@ -595,7 +595,7 @@ int ocfs2_reserve_clusters(struct ocfs2_super *osb, mlog_entry_void(); - *ac = kcalloc(1, sizeof(struct ocfs2_alloc_context), GFP_KERNEL); + *ac = kzalloc(sizeof(struct ocfs2_alloc_context), GFP_KERNEL); if (!(*ac)) { status = -ENOMEM; mlog_errno(status); diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index a6d2f8cc165b..6e300a88a47e 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c @@ -1231,7 +1231,7 @@ static int ocfs2_setup_osb_uuid(struct ocfs2_super *osb, const unsigned char *uu BUG_ON(uuid_bytes != OCFS2_VOL_UUID_LEN); - osb->uuid_str = kcalloc(1, OCFS2_VOL_UUID_LEN * 2 + 1, GFP_KERNEL); + osb->uuid_str = kzalloc(OCFS2_VOL_UUID_LEN * 2 + 1, GFP_KERNEL); if (osb->uuid_str == NULL) return -ENOMEM; @@ -1262,7 +1262,7 @@ static int ocfs2_initialize_super(struct super_block *sb, mlog_entry_void(); - osb = kcalloc(1, sizeof(struct ocfs2_super), GFP_KERNEL); + osb = kzalloc(sizeof(struct ocfs2_super), GFP_KERNEL); if (!osb) { status = -ENOMEM; mlog_errno(status); @@ -1387,7 +1387,7 @@ static int ocfs2_initialize_super(struct super_block *sb, */ /* initialize our journal structure */ - journal = kcalloc(1, sizeof(struct ocfs2_journal), GFP_KERNEL); + journal = kzalloc(sizeof(struct ocfs2_journal), GFP_KERNEL); if (!journal) { mlog(ML_ERROR, "unable to alloc journal\n"); status = -ENOMEM; diff --git a/fs/ocfs2/vote.c b/fs/ocfs2/vote.c index 0315a8b61ed6..0afd8b9af70f 100644 --- a/fs/ocfs2/vote.c +++ b/fs/ocfs2/vote.c @@ -479,7 +479,7 @@ static struct ocfs2_net_wait_ctxt *ocfs2_new_net_wait_ctxt(unsigned int response { struct ocfs2_net_wait_ctxt *w; - w = kcalloc(1, sizeof(*w), GFP_NOFS); + w = kzalloc(sizeof(*w), GFP_NOFS); if (!w) { mlog_errno(-ENOMEM); goto bail; @@ -642,7 +642,7 @@ static struct ocfs2_vote_msg * ocfs2_new_vote_request(struct ocfs2_super *osb, BUG_ON(!ocfs2_is_valid_vote_request(type)); - request = kcalloc(1, sizeof(*request), GFP_NOFS); + request = kzalloc(sizeof(*request), GFP_NOFS); if (!request) { mlog_errno(-ENOMEM); } else { diff --git a/fs/pipe.c b/fs/pipe.c index f8b6bdcb879a..9a06e8e48e8d 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -207,7 +207,7 @@ int generic_pipe_buf_pin(struct pipe_inode_info *info, struct pipe_buffer *buf) return 0; } -static struct pipe_buf_operations anon_pipe_buf_ops = { +static const struct pipe_buf_operations anon_pipe_buf_ops = { .can_merge = 1, .map = generic_pipe_buf_map, .unmap = generic_pipe_buf_unmap, @@ -243,7 +243,7 @@ pipe_read(struct kiocb *iocb, const struct iovec *_iov, if (bufs) { int curbuf = pipe->curbuf; struct pipe_buffer *buf = pipe->bufs + curbuf; - struct pipe_buf_operations *ops = buf->ops; + const struct pipe_buf_operations *ops = buf->ops; void *addr; size_t chars = buf->len; int error, atomic; @@ -365,7 +365,7 @@ pipe_write(struct kiocb *iocb, const struct iovec *_iov, int lastbuf = (pipe->curbuf + pipe->nrbufs - 1) & (PIPE_BUFFERS-1); struct pipe_buffer *buf = pipe->bufs + lastbuf; - struct pipe_buf_operations *ops = buf->ops; + const struct pipe_buf_operations *ops = buf->ops; int offset = buf->offset + buf->len; if (ops->can_merge && offset + chars <= PAGE_SIZE) { @@ -756,7 +756,7 @@ const struct file_operations rdwr_fifo_fops = { .fasync = pipe_rdwr_fasync, }; -static struct file_operations read_pipe_fops = { +static const struct file_operations read_pipe_fops = { .llseek = no_llseek, .read = do_sync_read, .aio_read = pipe_read, @@ -768,7 +768,7 @@ static struct file_operations read_pipe_fops = { .fasync = pipe_read_fasync, }; -static struct file_operations write_pipe_fops = { +static const struct file_operations write_pipe_fops = { .llseek = no_llseek, .read = bad_pipe_r, .write = do_sync_write, @@ -780,7 +780,7 @@ static struct file_operations write_pipe_fops = { .fasync = pipe_write_fasync, }; -static struct file_operations rdwr_pipe_fops = { +static const struct file_operations rdwr_pipe_fops = { .llseek = no_llseek, .read = do_sync_read, .aio_read = pipe_read, diff --git a/fs/read_write.c b/fs/read_write.c index 1d3dda4fa70c..707ac21700d3 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -450,8 +450,6 @@ unsigned long iov_shorten(struct iovec *iov, unsigned long nr_segs, size_t to) return seg; } -EXPORT_UNUSED_SYMBOL(iov_shorten); /* June 2006 */ - ssize_t do_sync_readv_writev(struct file *filp, const struct iovec *iov, unsigned long nr_segs, size_t len, loff_t *ppos, iov_fn_t fn) { diff --git a/fs/reiserfs/xattr_acl.c b/fs/reiserfs/xattr_acl.c index 97ae1b92bc47..5296a29cc5eb 100644 --- a/fs/reiserfs/xattr_acl.c +++ b/fs/reiserfs/xattr_acl.c @@ -135,7 +135,7 @@ static void *posix_acl_to_disk(const struct posix_acl *acl, size_t * size) int n; *size = reiserfs_acl_size(acl->a_count); - ext_acl = (reiserfs_acl_header *) kmalloc(sizeof(reiserfs_acl_header) + + ext_acl = kmalloc(sizeof(reiserfs_acl_header) + acl->a_count * sizeof(reiserfs_acl_entry), GFP_NOFS); diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c index 4af4cd729a5a..84dfe3f3482e 100644 --- a/fs/smbfs/inode.c +++ b/fs/smbfs/inode.c @@ -482,12 +482,13 @@ smb_put_super(struct super_block *sb) smb_close_socket(server); if (server->conn_pid) - kill_proc(server->conn_pid, SIGTERM, 1); + kill_pid(server->conn_pid, SIGTERM, 1); kfree(server->ops); smb_unload_nls(server); sb->s_fs_info = NULL; smb_unlock_server(server); + put_pid(server->conn_pid); kfree(server); } @@ -530,7 +531,7 @@ static int smb_fill_super(struct super_block *sb, void *raw_data, int silent) INIT_LIST_HEAD(&server->xmitq); INIT_LIST_HEAD(&server->recvq); server->conn_error = 0; - server->conn_pid = 0; + server->conn_pid = NULL; server->state = CONN_INVALID; /* no connection yet */ server->generation = 0; diff --git a/fs/smbfs/proc.c b/fs/smbfs/proc.c index a5ced9e0c6c4..feac46050619 100644 --- a/fs/smbfs/proc.c +++ b/fs/smbfs/proc.c @@ -877,7 +877,7 @@ smb_newconn(struct smb_sb_info *server, struct smb_conn_opt *opt) goto out_putf; server->sock_file = filp; - server->conn_pid = current->pid; + server->conn_pid = get_pid(task_pid(current)); server->opt = *opt; server->generation += 1; server->state = CONN_VALID; @@ -971,8 +971,8 @@ smb_newconn(struct smb_sb_info *server, struct smb_conn_opt *opt) } VERBOSE("protocol=%d, max_xmit=%d, pid=%d capabilities=0x%x\n", - server->opt.protocol, server->opt.max_xmit, server->conn_pid, - server->opt.capabilities); + server->opt.protocol, server->opt.max_xmit, + pid_nr(server->conn_pid), server->opt.capabilities); /* FIXME: this really should be done by smbmount. */ if (server->opt.max_xmit > SMB_MAX_PACKET_SIZE) { diff --git a/fs/smbfs/smbiod.c b/fs/smbfs/smbiod.c index e67540441288..89eaf31f1d46 100644 --- a/fs/smbfs/smbiod.c +++ b/fs/smbfs/smbiod.c @@ -152,7 +152,7 @@ int smbiod_retry(struct smb_sb_info *server) { struct list_head *head; struct smb_request *req; - pid_t pid = server->conn_pid; + struct pid *pid = get_pid(server->conn_pid); int result = 0; VERBOSE("state: %d\n", server->state); @@ -222,7 +222,7 @@ int smbiod_retry(struct smb_sb_info *server) /* * Note: use the "priv" flag, as a user process may need to reconnect. */ - result = kill_proc(pid, SIGUSR1, 1); + result = kill_pid(pid, SIGUSR1, 1); if (result) { /* FIXME: this is most likely fatal, umount? */ printk(KERN_ERR "smb_retry: signal failed [%d]\n", result); @@ -233,6 +233,7 @@ int smbiod_retry(struct smb_sb_info *server) /* FIXME: The retried requests should perhaps get a "time boost". */ out: + put_pid(pid); return result; } diff --git a/fs/splice.c b/fs/splice.c index bbd0aeb3f68e..2fca6ebf4cc2 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -42,7 +42,7 @@ struct splice_pipe_desc { struct partial_page *partial; /* pages[] may not be contig */ int nr_pages; /* number of pages in map */ unsigned int flags; /* splice flags */ - struct pipe_buf_operations *ops;/* ops associated with output pipe */ + const struct pipe_buf_operations *ops;/* ops associated with output pipe */ }; /* @@ -139,7 +139,7 @@ error: return err; } -static struct pipe_buf_operations page_cache_pipe_buf_ops = { +static const struct pipe_buf_operations page_cache_pipe_buf_ops = { .can_merge = 0, .map = generic_pipe_buf_map, .unmap = generic_pipe_buf_unmap, @@ -159,7 +159,7 @@ static int user_page_pipe_buf_steal(struct pipe_inode_info *pipe, return generic_pipe_buf_steal(pipe, buf); } -static struct pipe_buf_operations user_page_pipe_buf_ops = { +static const struct pipe_buf_operations user_page_pipe_buf_ops = { .can_merge = 0, .map = generic_pipe_buf_map, .unmap = generic_pipe_buf_unmap, @@ -724,7 +724,7 @@ static ssize_t __splice_from_pipe(struct pipe_inode_info *pipe, for (;;) { if (pipe->nrbufs) { struct pipe_buffer *buf = pipe->bufs + pipe->curbuf; - struct pipe_buf_operations *ops = buf->ops; + const struct pipe_buf_operations *ops = buf->ops; sd.len = buf->len; if (sd.len > sd.total_len) |