]> git.openfabrics.org - ~shefty/rdma-dev.git/commitdiff
Merge branch 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jdelv...
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 14 Dec 2010 21:31:23 +0000 (13:31 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 14 Dec 2010 21:31:23 +0000 (13:31 -0800)
* 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jdelvare/staging:
  hwmon: (adm1026) Allow 1 as a valid divider value
  hwmon: (adm1026) Fix setting fan_div
  hwmon: (it87) Fix manual fan speed control on IT8721F

51 files changed:
Documentation/filesystems/Locking
Documentation/filesystems/vfs.txt
fs/btrfs/disk-io.c
fs/btrfs/extent-tree.c
fs/btrfs/file.c
fs/btrfs/free-space-cache.c
fs/btrfs/inode.c
fs/btrfs/ioctl.c
fs/btrfs/ioctl.h
fs/btrfs/orphan.c
fs/btrfs/super.c
fs/btrfs/volumes.c
fs/btrfs/volumes.h
fs/ceph/dir.c
fs/ceph/ioctl.h
fs/ceph/locks.c
fs/ceph/mds_client.c
fs/ceph/mds_client.h
fs/cifs/Makefile
fs/cifs/README
fs/cifs/cifs_fs_sb.h
fs/cifs/cifsacl.c
fs/cifs/cifsacl.h
fs/cifs/cifsfs.c
fs/cifs/cifsglob.h
fs/cifs/cifsproto.h
fs/cifs/cifssmb.c
fs/cifs/connect.c
fs/cifs/file.c
fs/cifs/inode.c
fs/cifs/readdir.c
fs/fuse/file.c
fs/nfs/dir.c
fs/nfs/file.c
fs/nfs/inode.c
fs/nfs/mount_clnt.c
fs/nfs/nfs4proc.c
fs/nfs/pagelist.c
fs/nfs/read.c
fs/nfs/super.c
fs/nfs/write.c
fs/nfsd/nfs3xdr.c
fs/nfsd/xdr4.h
fs/xfs/xfs_rename.c
include/linux/fs.h
include/linux/nfs_fs.h
include/linux/nfs_page.h
mm/filemap.c
mm/truncate.c
mm/vmscan.c
net/sunrpc/svc_xprt.c

index a91f30890011ddf69ba9b859484966c943db7fb5..b6426f15b4ae85f5469b962806004237b9b5607e 100644 (file)
@@ -173,12 +173,13 @@ prototypes:
        sector_t (*bmap)(struct address_space *, sector_t);
        int (*invalidatepage) (struct page *, unsigned long);
        int (*releasepage) (struct page *, int);
+       void (*freepage)(struct page *);
        int (*direct_IO)(int, struct kiocb *, const struct iovec *iov,
                        loff_t offset, unsigned long nr_segs);
        int (*launder_page) (struct page *);
 
 locking rules:
-       All except set_page_dirty may block
+       All except set_page_dirty and freepage may block
 
                        BKL     PageLocked(page)        i_mutex
 writepage:             no      yes, unlocks (see below)
@@ -193,6 +194,7 @@ perform_write:              no      n/a                     yes
 bmap:                  no
 invalidatepage:                no      yes
 releasepage:           no      yes
+freepage:              no      yes
 direct_IO:             no
 launder_page:          no      yes
 
@@ -288,6 +290,9 @@ buffers from the page in preparation for freeing it.  It returns zero to
 indicate that the buffers are (or may be) freeable.  If ->releasepage is zero,
 the kernel assumes that the fs has no private interest in the buffers.
 
+       ->freepage() is called when the kernel is done dropping the page
+from the page cache.
+
        ->launder_page() may be called prior to releasing a page if
 it is still found to be dirty. It returns zero if the page was successfully
 cleaned, or an error value if not. Note that in order to prevent the page
index 55c28b79d8dce3afcb239f45cc1cc62c44685d3c..20899e095e7e6879580b53aa9aa0282fb4b5ce63 100644 (file)
@@ -534,6 +534,7 @@ struct address_space_operations {
        sector_t (*bmap)(struct address_space *, sector_t);
        int (*invalidatepage) (struct page *, unsigned long);
        int (*releasepage) (struct page *, int);
+       void (*freepage)(struct page *);
        ssize_t (*direct_IO)(int, struct kiocb *, const struct iovec *iov,
                        loff_t offset, unsigned long nr_segs);
        struct page* (*get_xip_page)(struct address_space *, sector_t,
@@ -678,6 +679,12 @@ struct address_space_operations {
         need to ensure this.  Possibly it can clear the PageUptodate
         bit if it cannot free private data yet.
 
+  freepage: freepage is called once the page is no longer visible in
+        the page cache in order to allow the cleanup of any private
+       data. Since it may be called by the memory reclaimer, it
+       should not assume that the original address_space mapping still
+       exists, and it should not block.
+
   direct_IO: called by the generic read/write routines to perform
         direct_IO - that is IO requests which bypass the page cache
         and transfer data directly between the storage and the
index c547cca26a266e962bbb760c0616e0846439d81d..51d2e4de34ebe58d4eb5d2c99d1fc1bb83f692f9 100644 (file)
@@ -696,6 +696,7 @@ static int btree_submit_bio_hook(struct inode *inode, int rw, struct bio *bio,
                                   __btree_submit_bio_done);
 }
 
+#ifdef CONFIG_MIGRATION
 static int btree_migratepage(struct address_space *mapping,
                        struct page *newpage, struct page *page)
 {
@@ -712,12 +713,9 @@ static int btree_migratepage(struct address_space *mapping,
        if (page_has_private(page) &&
            !try_to_release_page(page, GFP_KERNEL))
                return -EAGAIN;
-#ifdef CONFIG_MIGRATION
        return migrate_page(mapping, newpage, page);
-#else
-       return -ENOSYS;
-#endif
 }
+#endif
 
 static int btree_writepage(struct page *page, struct writeback_control *wbc)
 {
@@ -1009,7 +1007,10 @@ static int find_and_setup_root(struct btrfs_root *tree_root,
        blocksize = btrfs_level_size(root, btrfs_root_level(&root->root_item));
        root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item),
                                     blocksize, generation);
-       BUG_ON(!root->node);
+       if (!root->node || !btrfs_buffer_uptodate(root->node, generation)) {
+               free_extent_buffer(root->node);
+               return -EIO;
+       }
        root->commit_root = btrfs_root_node(root);
        return 0;
 }
index bcd59c7dfb574def82517a80affe6a9ddf756a92..227e5815d8382393d4adc4d0a340ee636bca9d3e 100644 (file)
@@ -429,6 +429,7 @@ err:
 
 static int cache_block_group(struct btrfs_block_group_cache *cache,
                             struct btrfs_trans_handle *trans,
+                            struct btrfs_root *root,
                             int load_cache_only)
 {
        struct btrfs_fs_info *fs_info = cache->fs_info;
@@ -442,9 +443,12 @@ static int cache_block_group(struct btrfs_block_group_cache *cache,
 
        /*
         * We can't do the read from on-disk cache during a commit since we need
-        * to have the normal tree locking.
+        * to have the normal tree locking.  Also if we are currently trying to
+        * allocate blocks for the tree root we can't do the fast caching since
+        * we likely hold important locks.
         */
-       if (!trans->transaction->in_commit) {
+       if (!trans->transaction->in_commit &&
+           (root && root != root->fs_info->tree_root)) {
                spin_lock(&cache->lock);
                if (cache->cached != BTRFS_CACHE_NO) {
                        spin_unlock(&cache->lock);
@@ -2741,6 +2745,7 @@ static int cache_save_setup(struct btrfs_block_group_cache *block_group,
        struct btrfs_root *root = block_group->fs_info->tree_root;
        struct inode *inode = NULL;
        u64 alloc_hint = 0;
+       int dcs = BTRFS_DC_ERROR;
        int num_pages = 0;
        int retries = 0;
        int ret = 0;
@@ -2795,6 +2800,8 @@ again:
 
        spin_lock(&block_group->lock);
        if (block_group->cached != BTRFS_CACHE_FINISHED) {
+               /* We're not cached, don't bother trying to write stuff out */
+               dcs = BTRFS_DC_WRITTEN;
                spin_unlock(&block_group->lock);
                goto out_put;
        }
@@ -2821,6 +2828,8 @@ again:
        ret = btrfs_prealloc_file_range_trans(inode, trans, 0, 0, num_pages,
                                              num_pages, num_pages,
                                              &alloc_hint);
+       if (!ret)
+               dcs = BTRFS_DC_SETUP;
        btrfs_free_reserved_data_space(inode, num_pages);
 out_put:
        iput(inode);
@@ -2828,10 +2837,7 @@ out_free:
        btrfs_release_path(root, path);
 out:
        spin_lock(&block_group->lock);
-       if (ret)
-               block_group->disk_cache_state = BTRFS_DC_ERROR;
-       else
-               block_group->disk_cache_state = BTRFS_DC_SETUP;
+       block_group->disk_cache_state = dcs;
        spin_unlock(&block_group->lock);
 
        return ret;
@@ -3037,7 +3043,13 @@ static void set_avail_alloc_bits(struct btrfs_fs_info *fs_info, u64 flags)
 
 u64 btrfs_reduce_alloc_profile(struct btrfs_root *root, u64 flags)
 {
-       u64 num_devices = root->fs_info->fs_devices->rw_devices;
+       /*
+        * we add in the count of missing devices because we want
+        * to make sure that any RAID levels on a degraded FS
+        * continue to be honored.
+        */
+       u64 num_devices = root->fs_info->fs_devices->rw_devices +
+               root->fs_info->fs_devices->missing_devices;
 
        if (num_devices == 1)
                flags &= ~(BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID0);
@@ -4080,7 +4092,7 @@ static int update_block_group(struct btrfs_trans_handle *trans,
                 * space back to the block group, otherwise we will leak space.
                 */
                if (!alloc && cache->cached == BTRFS_CACHE_NO)
-                       cache_block_group(cache, trans, 1);
+                       cache_block_group(cache, trans, NULL, 1);
 
                byte_in_group = bytenr - cache->key.objectid;
                WARN_ON(byte_in_group > cache->key.offset);
@@ -4930,11 +4942,31 @@ search:
                btrfs_get_block_group(block_group);
                search_start = block_group->key.objectid;
 
+               /*
+                * this can happen if we end up cycling through all the
+                * raid types, but we want to make sure we only allocate
+                * for the proper type.
+                */
+               if (!block_group_bits(block_group, data)) {
+                   u64 extra = BTRFS_BLOCK_GROUP_DUP |
+                               BTRFS_BLOCK_GROUP_RAID1 |
+                               BTRFS_BLOCK_GROUP_RAID10;
+
+                       /*
+                        * if they asked for extra copies and this block group
+                        * doesn't provide them, bail.  This does allow us to
+                        * fill raid0 from raid1.
+                        */
+                       if ((data & extra) && !(block_group->flags & extra))
+                               goto loop;
+               }
+
 have_block_group:
                if (unlikely(block_group->cached == BTRFS_CACHE_NO)) {
                        u64 free_percent;
 
-                       ret = cache_block_group(block_group, trans, 1);
+                       ret = cache_block_group(block_group, trans,
+                                               orig_root, 1);
                        if (block_group->cached == BTRFS_CACHE_FINISHED)
                                goto have_block_group;
 
@@ -4958,7 +4990,8 @@ have_block_group:
                        if (loop > LOOP_CACHING_NOWAIT ||
                            (loop > LOOP_FIND_IDEAL &&
                             atomic_read(&space_info->caching_threads) < 2)) {
-                               ret = cache_block_group(block_group, trans, 0);
+                               ret = cache_block_group(block_group, trans,
+                                                       orig_root, 0);
                                BUG_ON(ret);
                        }
                        found_uncached_bg = true;
@@ -5515,7 +5548,7 @@ int btrfs_alloc_logged_file_extent(struct btrfs_trans_handle *trans,
        u64 num_bytes = ins->offset;
 
        block_group = btrfs_lookup_block_group(root->fs_info, ins->objectid);
-       cache_block_group(block_group, trans, 0);
+       cache_block_group(block_group, trans, NULL, 0);
        caching_ctl = get_caching_control(block_group);
 
        if (!caching_ctl) {
@@ -6300,9 +6333,13 @@ int btrfs_drop_snapshot(struct btrfs_root *root,
                                           NULL, NULL);
                BUG_ON(ret < 0);
                if (ret > 0) {
-                       ret = btrfs_del_orphan_item(trans, tree_root,
-                                                   root->root_key.objectid);
-                       BUG_ON(ret);
+                       /* if we fail to delete the orphan item this time
+                        * around, it'll get picked up the next time.
+                        *
+                        * The most common failure here is just -ENOENT.
+                        */
+                       btrfs_del_orphan_item(trans, tree_root,
+                                             root->root_key.objectid);
                }
        }
 
@@ -7878,7 +7915,14 @@ static u64 update_block_group_flags(struct btrfs_root *root, u64 flags)
        u64 stripped = BTRFS_BLOCK_GROUP_RAID0 |
                BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID10;
 
-       num_devices = root->fs_info->fs_devices->rw_devices;
+       /*
+        * we add in the count of missing devices because we want
+        * to make sure that any RAID levels on a degraded FS
+        * continue to be honored.
+        */
+       num_devices = root->fs_info->fs_devices->rw_devices +
+               root->fs_info->fs_devices->missing_devices;
+
        if (num_devices == 1) {
                stripped |= BTRFS_BLOCK_GROUP_DUP;
                stripped = flags & ~stripped;
@@ -8247,7 +8291,6 @@ int btrfs_read_block_groups(struct btrfs_root *root)
                        break;
                if (ret != 0)
                        goto error;
-
                leaf = path->nodes[0];
                btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
                cache = kzalloc(sizeof(*cache), GFP_NOFS);
index c1faded5fca03a7cbcb509908cfdf3cc8362ce1f..66836d85763bbfd2dafe3821a1be30f173784fdc 100644 (file)
@@ -48,30 +48,34 @@ static noinline int btrfs_copy_from_user(loff_t pos, int num_pages,
                                         struct page **prepared_pages,
                                         struct iov_iter *i)
 {
-       size_t copied;
+       size_t copied = 0;
        int pg = 0;
        int offset = pos & (PAGE_CACHE_SIZE - 1);
+       int total_copied = 0;
 
        while (write_bytes > 0) {
                size_t count = min_t(size_t,
                                     PAGE_CACHE_SIZE - offset, write_bytes);
                struct page *page = prepared_pages[pg];
-again:
-               if (unlikely(iov_iter_fault_in_readable(i, count)))
-                       return -EFAULT;
-
-               /* Copy data from userspace to the current page */
-               copied = iov_iter_copy_from_user(page, i, offset, count);
+               /*
+                * Copy data from userspace to the current page
+                *
+                * Disable pagefault to avoid recursive lock since
+                * the pages are already locked
+                */
+               pagefault_disable();
+               copied = iov_iter_copy_from_user_atomic(page, i, offset, count);
+               pagefault_enable();
 
                /* Flush processor's dcache for this page */
                flush_dcache_page(page);
                iov_iter_advance(i, copied);
                write_bytes -= copied;
+               total_copied += copied;
 
+               /* Return to btrfs_file_aio_write to fault page */
                if (unlikely(copied == 0)) {
-                       count = min_t(size_t, PAGE_CACHE_SIZE - offset,
-                                     iov_iter_single_seg_count(i));
-                       goto again;
+                       break;
                }
 
                if (unlikely(copied < PAGE_CACHE_SIZE - offset)) {
@@ -81,7 +85,7 @@ again:
                        offset = 0;
                }
        }
-       return 0;
+       return total_copied;
 }
 
 /*
@@ -854,6 +858,8 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb,
        unsigned long last_index;
        int will_write;
        int buffered = 0;
+       int copied = 0;
+       int dirty_pages = 0;
 
        will_write = ((file->f_flags & O_DSYNC) || IS_SYNC(inode) ||
                      (file->f_flags & O_DIRECT));
@@ -970,7 +976,17 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb,
                WARN_ON(num_pages > nrptrs);
                memset(pages, 0, sizeof(struct page *) * nrptrs);
 
-               ret = btrfs_delalloc_reserve_space(inode, write_bytes);
+               /*
+                * Fault pages before locking them in prepare_pages
+                * to avoid recursive lock
+                */
+               if (unlikely(iov_iter_fault_in_readable(&i, write_bytes))) {
+                       ret = -EFAULT;
+                       goto out;
+               }
+
+               ret = btrfs_delalloc_reserve_space(inode,
+                                       num_pages << PAGE_CACHE_SHIFT);
                if (ret)
                        goto out;
 
@@ -978,37 +994,49 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb,
                                    pos, first_index, last_index,
                                    write_bytes);
                if (ret) {
-                       btrfs_delalloc_release_space(inode, write_bytes);
+                       btrfs_delalloc_release_space(inode,
+                                       num_pages << PAGE_CACHE_SHIFT);
                        goto out;
                }
 
-               ret = btrfs_copy_from_user(pos, num_pages,
+               copied = btrfs_copy_from_user(pos, num_pages,
                                           write_bytes, pages, &i);
-               if (ret == 0) {
+               dirty_pages = (copied + PAGE_CACHE_SIZE - 1) >>
+                                       PAGE_CACHE_SHIFT;
+
+               if (num_pages > dirty_pages) {
+                       if (copied > 0)
+                               atomic_inc(
+                                       &BTRFS_I(inode)->outstanding_extents);
+                       btrfs_delalloc_release_space(inode,
+                                       (num_pages - dirty_pages) <<
+                                       PAGE_CACHE_SHIFT);
+               }
+
+               if (copied > 0) {
                        dirty_and_release_pages(NULL, root, file, pages,
-                                               num_pages, pos, write_bytes);
+                                               dirty_pages, pos, copied);
                }
 
                btrfs_drop_pages(pages, num_pages);
-               if (ret) {
-                       btrfs_delalloc_release_space(inode, write_bytes);
-                       goto out;
-               }
 
-               if (will_write) {
-                       filemap_fdatawrite_range(inode->i_mapping, pos,
-                                                pos + write_bytes - 1);
-               } else {
-                       balance_dirty_pages_ratelimited_nr(inode->i_mapping,
-                                                          num_pages);
-                       if (num_pages <
-                           (root->leafsize >> PAGE_CACHE_SHIFT) + 1)
-                               btrfs_btree_balance_dirty(root, 1);
-                       btrfs_throttle(root);
+               if (copied > 0) {
+                       if (will_write) {
+                               filemap_fdatawrite_range(inode->i_mapping, pos,
+                                                        pos + copied - 1);
+                       } else {
+                               balance_dirty_pages_ratelimited_nr(
+                                                       inode->i_mapping,
+                                                       dirty_pages);
+                               if (dirty_pages <
+                               (root->leafsize >> PAGE_CACHE_SHIFT) + 1)
+                                       btrfs_btree_balance_dirty(root, 1);
+                               btrfs_throttle(root);
+                       }
                }
 
-               pos += write_bytes;
-               num_written += write_bytes;
+               pos += copied;
+               num_written += copied;
 
                cond_resched();
        }
index 22ee0dc2e6b8a712900c68a8c44df4a453fb86f0..60d684266959bbf8f96c14873e9a1f57e069a29e 100644 (file)
@@ -290,7 +290,7 @@ int load_free_space_cache(struct btrfs_fs_info *fs_info,
                       (unsigned long long)BTRFS_I(inode)->generation,
                       (unsigned long long)generation,
                       (unsigned long long)block_group->key.objectid);
-               goto out;
+               goto free_cache;
        }
 
        if (!num_entries)
@@ -524,6 +524,12 @@ int btrfs_write_out_cache(struct btrfs_root *root,
                return 0;
        }
 
+       node = rb_first(&block_group->free_space_offset);
+       if (!node) {
+               iput(inode);
+               return 0;
+       }
+
        last_index = (i_size_read(inode) - 1) >> PAGE_CACHE_SHIFT;
        filemap_write_and_wait(inode->i_mapping);
        btrfs_wait_ordered_range(inode, inode->i_size &
@@ -543,10 +549,6 @@ int btrfs_write_out_cache(struct btrfs_root *root,
         */
        first_page_offset = (sizeof(u32) * num_checksums) + sizeof(u64);
 
-       node = rb_first(&block_group->free_space_offset);
-       if (!node)
-               goto out_free;
-
        /*
         * Lock all pages first so we can lock the extent safely.
         *
index 8039390bd6a6f7bc1d1026d917dcaeb93aa067e6..72f31ecb5c90085a2d6adfdc9b690ee038bf508f 100644 (file)
@@ -495,7 +495,7 @@ again:
                add_async_extent(async_cow, start, num_bytes,
                                 total_compressed, pages, nr_pages_ret);
 
-               if (start + num_bytes < end && start + num_bytes < actual_end) {
+               if (start + num_bytes < end) {
                        start += num_bytes;
                        pages = NULL;
                        cond_resched();
@@ -5712,9 +5712,9 @@ static void btrfs_end_dio_bio(struct bio *bio, int err)
 
        if (err) {
                printk(KERN_ERR "btrfs direct IO failed ino %lu rw %lu "
-                     "disk_bytenr %lu len %u err no %d\n",
-                     dip->inode->i_ino, bio->bi_rw, bio->bi_sector,
-                     bio->bi_size, err);
+                     "sector %#Lx len %u err no %d\n",
+                     dip->inode->i_ino, bio->bi_rw,
+                     (unsigned long long)bio->bi_sector, bio->bi_size, err);
                dip->errors = 1;
 
                /*
@@ -5934,8 +5934,7 @@ free_ordered:
         */
        if (write) {
                struct btrfs_ordered_extent *ordered;
-               ordered = btrfs_lookup_ordered_extent(inode,
-                                                     dip->logical_offset);
+               ordered = btrfs_lookup_ordered_extent(inode, file_offset);
                if (!test_bit(BTRFS_ORDERED_PREALLOC, &ordered->flags) &&
                    !test_bit(BTRFS_ORDERED_NOCOW, &ordered->flags))
                        btrfs_free_reserved_extent(root, ordered->start,
index f1c9bb4079ed8b3aaf2a01bb5211923f8e231986..f87552a1d7ea0beeb540aa59ddac3754242304cc 100644 (file)
@@ -947,23 +947,42 @@ out:
 
 static noinline int btrfs_ioctl_snap_create(struct file *file,
                                            void __user *arg, int subvol,
-                                           int async)
+                                           int v2)
 {
        struct btrfs_ioctl_vol_args *vol_args = NULL;
-       struct btrfs_ioctl_async_vol_args *async_vol_args = NULL;
+       struct btrfs_ioctl_vol_args_v2 *vol_args_v2 = NULL;
        char *name;
        u64 fd;
-       u64 transid = 0;
        int ret;
 
-       if (async) {
-               async_vol_args = memdup_user(arg, sizeof(*async_vol_args));
-               if (IS_ERR(async_vol_args))
-                       return PTR_ERR(async_vol_args);
+       if (v2) {
+               u64 transid = 0;
+               u64 *ptr = NULL;
 
-               name = async_vol_args->name;
-               fd = async_vol_args->fd;
-               async_vol_args->name[BTRFS_SNAPSHOT_NAME_MAX] = '\0';
+               vol_args_v2 = memdup_user(arg, sizeof(*vol_args_v2));
+               if (IS_ERR(vol_args_v2))
+                       return PTR_ERR(vol_args_v2);
+
+               if (vol_args_v2->flags & ~BTRFS_SUBVOL_CREATE_ASYNC) {
+                       ret = -EINVAL;
+                       goto out;
+               }
+
+               name = vol_args_v2->name;
+               fd = vol_args_v2->fd;
+               vol_args_v2->name[BTRFS_SUBVOL_NAME_MAX] = '\0';
+
+               if (vol_args_v2->flags & BTRFS_SUBVOL_CREATE_ASYNC)
+                       ptr = &transid;
+
+               ret = btrfs_ioctl_snap_create_transid(file, name, fd,
+                                                     subvol, ptr);
+
+               if (ret == 0 && ptr &&
+                   copy_to_user(arg +
+                                offsetof(struct btrfs_ioctl_vol_args_v2,
+                                         transid), ptr, sizeof(*ptr)))
+                       ret = -EFAULT;
        } else {
                vol_args = memdup_user(arg, sizeof(*vol_args));
                if (IS_ERR(vol_args))
@@ -971,20 +990,13 @@ static noinline int btrfs_ioctl_snap_create(struct file *file,
                name = vol_args->name;
                fd = vol_args->fd;
                vol_args->name[BTRFS_PATH_NAME_MAX] = '\0';
-       }
-
-       ret = btrfs_ioctl_snap_create_transid(file, name, fd,
-                                             subvol, &transid);
 
-       if (!ret && async) {
-               if (copy_to_user(arg +
-                               offsetof(struct btrfs_ioctl_async_vol_args,
-                               transid), &transid, sizeof(transid)))
-                       return -EFAULT;
+               ret = btrfs_ioctl_snap_create_transid(file, name, fd,
+                                                     subvol, NULL);
        }
-
+out:
        kfree(vol_args);
-       kfree(async_vol_args);
+       kfree(vol_args_v2);
 
        return ret;
 }
@@ -2246,7 +2258,7 @@ long btrfs_ioctl(struct file *file, unsigned int
                return btrfs_ioctl_getversion(file, argp);
        case BTRFS_IOC_SNAP_CREATE:
                return btrfs_ioctl_snap_create(file, argp, 0, 0);
-       case BTRFS_IOC_SNAP_CREATE_ASYNC:
+       case BTRFS_IOC_SNAP_CREATE_V2:
                return btrfs_ioctl_snap_create(file, argp, 0, 1);
        case BTRFS_IOC_SUBVOL_CREATE:
                return btrfs_ioctl_snap_create(file, argp, 1, 0);
index 17c99ebdf96049a8ad028cd6e138355df86f0c9e..c344d12c646bf7d1cbb953f8c4aba6257b6db8b9 100644 (file)
@@ -30,11 +30,15 @@ struct btrfs_ioctl_vol_args {
        char name[BTRFS_PATH_NAME_MAX + 1];
 };
 
-#define BTRFS_SNAPSHOT_NAME_MAX 4079
-struct btrfs_ioctl_async_vol_args {
+#define BTRFS_SUBVOL_CREATE_ASYNC      (1ULL << 0)
+
+#define BTRFS_SUBVOL_NAME_MAX 4039
+struct btrfs_ioctl_vol_args_v2 {
        __s64 fd;
        __u64 transid;
-       char name[BTRFS_SNAPSHOT_NAME_MAX + 1];
+       __u64 flags;
+       __u64 unused[4];
+       char name[BTRFS_SUBVOL_NAME_MAX + 1];
 };
 
 #define BTRFS_INO_LOOKUP_PATH_MAX 4080
@@ -187,6 +191,6 @@ struct btrfs_ioctl_space_args {
                                    struct btrfs_ioctl_space_args)
 #define BTRFS_IOC_START_SYNC _IOR(BTRFS_IOCTL_MAGIC, 24, __u64)
 #define BTRFS_IOC_WAIT_SYNC  _IOW(BTRFS_IOCTL_MAGIC, 22, __u64)
-#define BTRFS_IOC_SNAP_CREATE_ASYNC _IOW(BTRFS_IOCTL_MAGIC, 23, \
-                                  struct btrfs_ioctl_async_vol_args)
+#define BTRFS_IOC_SNAP_CREATE_V2 _IOW(BTRFS_IOCTL_MAGIC, 23, \
+                                  struct btrfs_ioctl_vol_args_v2)
 #endif
index 79cba5fbc28ef8061e2d599110a3a525216a7bfd..f8be250963a09a283b8ec4ab04bcb1c3a962427e 100644 (file)
@@ -56,8 +56,12 @@ int btrfs_del_orphan_item(struct btrfs_trans_handle *trans,
                return -ENOMEM;
 
        ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
-       if (ret)
+       if (ret < 0)
                goto out;
+       if (ret) {
+               ret = -ENOENT;
+               goto out;
+       }
 
        ret = btrfs_del_item(trans, root, path);
 
index dbb51ea7a13c4b83e46c6c1f03d8d936cf75bed7..883c6fa1367eb866002d7f67d3ae2ce6497f4367 100644 (file)
@@ -685,9 +685,9 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
                mutex_unlock(&root->d_inode->i_mutex);
 
                if (IS_ERR(new_root)) {
+                       dput(root);
                        deactivate_locked_super(s);
                        error = PTR_ERR(new_root);
-                       dput(root);
                        goto error_free_subvol_name;
                }
                if (!new_root->d_inode) {
index cc04dc1445d64da8694401c2cbc2fde27105b8f9..6b9884507837581ba6231bc6c4cfb85a036b82f6 100644 (file)
@@ -412,12 +412,16 @@ static noinline int device_list_add(const char *path,
 
                device->fs_devices = fs_devices;
                fs_devices->num_devices++;
-       } else if (strcmp(device->name, path)) {
+       } else if (!device->name || strcmp(device->name, path)) {
                name = kstrdup(path, GFP_NOFS);
                if (!name)
                        return -ENOMEM;
                kfree(device->name);
                device->name = name;
+               if (device->missing) {
+                       fs_devices->missing_devices--;
+                       device->missing = 0;
+               }
        }
 
        if (found_transid > fs_devices->latest_trans) {
@@ -1236,6 +1240,9 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
 
        device->fs_devices->num_devices--;
 
+       if (device->missing)
+               root->fs_info->fs_devices->missing_devices--;
+
        next_device = list_entry(root->fs_info->fs_devices->devices.next,
                                 struct btrfs_device, dev_list);
        if (device->bdev == root->fs_info->sb->s_bdev)
@@ -3080,7 +3087,9 @@ static struct btrfs_device *add_missing_dev(struct btrfs_root *root,
        device->devid = devid;
        device->work.func = pending_bios_fn;
        device->fs_devices = fs_devices;
+       device->missing = 1;
        fs_devices->num_devices++;
+       fs_devices->missing_devices++;
        spin_lock_init(&device->io_lock);
        INIT_LIST_HEAD(&device->dev_alloc_list);
        memcpy(device->uuid, dev_uuid, BTRFS_UUID_SIZE);
@@ -3278,6 +3287,15 @@ static int read_one_dev(struct btrfs_root *root,
                        device = add_missing_dev(root, devid, dev_uuid);
                        if (!device)
                                return -ENOMEM;
+               } else if (!device->missing) {
+                       /*
+                        * this happens when a device that was properly setup
+                        * in the device info lists suddenly goes bad.
+                        * device->bdev is NULL, and so we have to set
+                        * device->missing to one here
+                        */
+                       root->fs_info->fs_devices->missing_devices++;
+                       device->missing = 1;
                }
        }
 
index 2b638b6e4eeae7cb9428490a897c1e10a9aaad1f..2740db49eb04d7a8de03d18e5935a97ff43ef9db 100644 (file)
@@ -44,6 +44,7 @@ struct btrfs_device {
 
        int writeable;
        int in_fs_metadata;
+       int missing;
 
        spinlock_t io_lock;
 
@@ -93,6 +94,7 @@ struct btrfs_fs_devices {
        u64 num_devices;
        u64 open_devices;
        u64 rw_devices;
+       u64 missing_devices;
        u64 total_rw_bytes;
        struct block_device *latest_bdev;
 
index 7d447af84ec4861acee8cd82bcecf80a892132b1..158c700fdca5e4f62763377a8374217d6371b68b 100644 (file)
@@ -114,8 +114,8 @@ static int __dcache_readdir(struct file *filp,
        spin_lock(&dcache_lock);
 
        /* start at beginning? */
-       if (filp->f_pos == 2 || (last &&
-                                filp->f_pos < ceph_dentry(last)->offset)) {
+       if (filp->f_pos == 2 || last == NULL ||
+           filp->f_pos < ceph_dentry(last)->offset) {
                if (list_empty(&parent->d_subdirs))
                        goto out_unlock;
                p = parent->d_subdirs.prev;
index a6ce54e94eb5ab435670093cd6ad789e72cc627b..52e8fd74d450b9e2895eb7c29d80e38b77eb0807 100644 (file)
@@ -4,7 +4,7 @@
 #include <linux/ioctl.h>
 #include <linux/types.h>
 
-#define CEPH_IOCTL_MAGIC 0x98
+#define CEPH_IOCTL_MAGIC 0x97
 
 /* just use u64 to align sanely on all archs */
 struct ceph_ioctl_layout {
index 40abde93c345d054279fd51cbca998525c4931c7..476b329867d41cf2cec7b3e2ad51e5f3885d9d7a 100644 (file)
  * Implement fcntl and flock locking functions.
  */
 static int ceph_lock_message(u8 lock_type, u16 operation, struct file *file,
-                            u64 pid, u64 pid_ns,
-                            int cmd, u64 start, u64 length, u8 wait)
+                            int cmd, u8 wait, struct file_lock *fl)
 {
        struct inode *inode = file->f_dentry->d_inode;
        struct ceph_mds_client *mdsc =
                ceph_sb_to_client(inode->i_sb)->mdsc;
        struct ceph_mds_request *req;
        int err;
+       u64 length = 0;
 
        req = ceph_mdsc_create_request(mdsc, operation, USE_AUTH_MDS);
        if (IS_ERR(req))
                return PTR_ERR(req);
        req->r_inode = igrab(inode);
 
+       /* mds requires start and length rather than start and end */
+       if (LLONG_MAX == fl->fl_end)
+               length = 0;
+       else
+               length = fl->fl_end - fl->fl_start + 1;
+
        dout("ceph_lock_message: rule: %d, op: %d, pid: %llu, start: %llu, "
             "length: %llu, wait: %d, type`: %d", (int)lock_type,
-            (int)operation, pid, start, length, wait, cmd);
+            (int)operation, (u64)fl->fl_pid, fl->fl_start,
+            length, wait, fl->fl_type);
+
 
        req->r_args.filelock_change.rule = lock_type;
        req->r_args.filelock_change.type = cmd;
-       req->r_args.filelock_change.pid = cpu_to_le64(pid);
+       req->r_args.filelock_change.pid = cpu_to_le64((u64)fl->fl_pid);
        /* This should be adjusted, but I'm not sure if
           namespaces actually get id numbers*/
        req->r_args.filelock_change.pid_namespace =
-               cpu_to_le64((u64)pid_ns);
-       req->r_args.filelock_change.start = cpu_to_le64(start);
+               cpu_to_le64((u64)(unsigned long)fl->fl_nspid);
+       req->r_args.filelock_change.start = cpu_to_le64(fl->fl_start);
        req->r_args.filelock_change.length = cpu_to_le64(length);
        req->r_args.filelock_change.wait = wait;
 
        err = ceph_mdsc_do_request(mdsc, inode, req);
+
+       if ( operation == CEPH_MDS_OP_GETFILELOCK){
+               fl->fl_pid = le64_to_cpu(req->r_reply_info.filelock_reply->pid);
+               if (CEPH_LOCK_SHARED == req->r_reply_info.filelock_reply->type)
+                       fl->fl_type = F_RDLCK;
+               else if (CEPH_LOCK_EXCL == req->r_reply_info.filelock_reply->type)
+                       fl->fl_type = F_WRLCK;
+               else
+                       fl->fl_type = F_UNLCK;
+
+               fl->fl_start = le64_to_cpu(req->r_reply_info.filelock_reply->start);
+               length = le64_to_cpu(req->r_reply_info.filelock_reply->start) +
+                                                le64_to_cpu(req->r_reply_info.filelock_reply->length);
+               if (length >= 1)
+                       fl->fl_end = length -1;
+               else
+                       fl->fl_end = 0;
+
+       }
        ceph_mdsc_put_request(req);
        dout("ceph_lock_message: rule: %d, op: %d, pid: %llu, start: %llu, "
-            "length: %llu, wait: %d, type`: %d err code %d", (int)lock_type,
-            (int)operation, pid, start, length, wait, cmd, err);
+            "length: %llu, wait: %d, type`: %d, err code %d", (int)lock_type,
+            (int)operation, (u64)fl->fl_pid, fl->fl_start,
+            length, wait, fl->fl_type, err);
        return err;
 }
 
@@ -54,7 +82,6 @@ static int ceph_lock_message(u8 lock_type, u16 operation, struct file *file,
  */
 int ceph_lock(struct file *file, int cmd, struct file_lock *fl)
 {
-       u64 length;
        u8 lock_cmd;
        int err;
        u8 wait = 0;
@@ -76,29 +103,20 @@ int ceph_lock(struct file *file, int cmd, struct file_lock *fl)
        else
                lock_cmd = CEPH_LOCK_UNLOCK;
 
-       if (LLONG_MAX == fl->fl_end)
-               length = 0;
-       else
-               length = fl->fl_end - fl->fl_start + 1;
-
-       err = ceph_lock_message(CEPH_LOCK_FCNTL, op, file,
-                               (u64)fl->fl_pid,
-                               (u64)(unsigned long)fl->fl_nspid,
-                               lock_cmd, fl->fl_start,
-                               length, wait);
+       err = ceph_lock_message(CEPH_LOCK_FCNTL, op, file, lock_cmd, wait, fl);
        if (!err) {
-               dout("mds locked, locking locally");
-               err = posix_lock_file(file, fl, NULL);
-               if (err && (CEPH_MDS_OP_SETFILELOCK == op)) {
-                       /* undo! This should only happen if the kernel detects
-                        * local deadlock. */
-                       ceph_lock_message(CEPH_LOCK_FCNTL, op, file,
-                                         (u64)fl->fl_pid,
-                                         (u64)(unsigned long)fl->fl_nspid,
-                                         CEPH_LOCK_UNLOCK, fl->fl_start,
-                                         length, 0);
-                       dout("got %d on posix_lock_file, undid lock", err);
+               if ( op != CEPH_MDS_OP_GETFILELOCK ){
+                       dout("mds locked, locking locally");
+                       err = posix_lock_file(file, fl, NULL);
+                       if (err && (CEPH_MDS_OP_SETFILELOCK == op)) {
+                               /* undo! This should only happen if the kernel detects
+                                * local deadlock. */
+                               ceph_lock_message(CEPH_LOCK_FCNTL, op, file,
+                                                 CEPH_LOCK_UNLOCK, 0, fl);
+                               dout("got %d on posix_lock_file, undid lock", err);
+                       }
                }
+
        } else {
                dout("mds returned error code %d", err);
        }
@@ -107,7 +125,6 @@ int ceph_lock(struct file *file, int cmd, struct file_lock *fl)
 
 int ceph_flock(struct file *file, int cmd, struct file_lock *fl)
 {
-       u64 length;
        u8 lock_cmd;
        int err;
        u8 wait = 1;
@@ -127,26 +144,15 @@ int ceph_flock(struct file *file, int cmd, struct file_lock *fl)
                lock_cmd = CEPH_LOCK_EXCL;
        else
                lock_cmd = CEPH_LOCK_UNLOCK;
-       /* mds requires start and length rather than start and end */
-       if (LLONG_MAX == fl->fl_end)
-               length = 0;
-       else
-               length = fl->fl_end - fl->fl_start + 1;
 
        err = ceph_lock_message(CEPH_LOCK_FLOCK, CEPH_MDS_OP_SETFILELOCK,
-                               file, (u64)fl->fl_pid,
-                               (u64)(unsigned long)fl->fl_nspid,
-                               lock_cmd, fl->fl_start,
-                               length, wait);
+                               file, lock_cmd, wait, fl);
        if (!err) {
                err = flock_lock_file_wait(file, fl);
                if (err) {
                        ceph_lock_message(CEPH_LOCK_FLOCK,
                                          CEPH_MDS_OP_SETFILELOCK,
-                                         file, (u64)fl->fl_pid,
-                                         (u64)(unsigned long)fl->fl_nspid,
-                                         CEPH_LOCK_UNLOCK, fl->fl_start,
-                                         length, 0);
+                                         file, CEPH_LOCK_UNLOCK, 0, fl);
                        dout("got %d on flock_lock_file_wait, undid lock", err);
                }
        } else {
index 098b185084791730ba0143111126bc066fdb9afb..38800eaa81d066bd8f06a401d082ecd3bb3f6fea 100644 (file)
@@ -201,6 +201,38 @@ out_bad:
        return err;
 }
 
+/*
+ * parse fcntl F_GETLK results
+ */
+static int parse_reply_info_filelock(void **p, void *end,
+                struct ceph_mds_reply_info_parsed *info)
+{
+       if (*p + sizeof(*info->filelock_reply) > end)
+               goto bad;
+
+       info->filelock_reply = *p;
+       *p += sizeof(*info->filelock_reply);
+
+       if (unlikely(*p != end))
+               goto bad;
+       return 0;
+
+bad:
+       return -EIO;
+}
+
+/*
+ * parse extra results
+ */
+static int parse_reply_info_extra(void **p, void *end,
+                struct ceph_mds_reply_info_parsed *info)
+{
+       if (info->head->op == CEPH_MDS_OP_GETFILELOCK)
+               return parse_reply_info_filelock(p, end, info);
+       else
+               return parse_reply_info_dir(p, end, info);
+}
+
 /*
  * parse entire mds reply
  */
@@ -223,10 +255,10 @@ static int parse_reply_info(struct ceph_msg *msg,
                        goto out_bad;
        }
 
-       /* dir content */
+       /* extra */
        ceph_decode_32_safe(&p, end, len, bad);
        if (len > 0) {
-               err = parse_reply_info_dir(&p, p+len, info);
+               err = parse_reply_info_extra(&p, p+len, info);
                if (err < 0)
                        goto out_bad;
        }
@@ -2074,7 +2106,7 @@ static void handle_reply(struct ceph_mds_session *session, struct ceph_msg *msg)
 
        mutex_lock(&session->s_mutex);
        if (err < 0) {
-               pr_err("mdsc_handle_reply got corrupt reply mds%d\n", mds);
+               pr_err("mdsc_handle_reply got corrupt reply mds%d(tid:%lld)\n", mds, tid);
                ceph_msg_dump(msg);
                goto out_err;
        }
@@ -2094,7 +2126,8 @@ static void handle_reply(struct ceph_mds_session *session, struct ceph_msg *msg)
        mutex_lock(&req->r_fill_mutex);
        err = ceph_fill_trace(mdsc->fsc->sb, req, req->r_session);
        if (err == 0) {
-               if (result == 0 && rinfo->dir_nr)
+               if (result == 0 && req->r_op != CEPH_MDS_OP_GETFILELOCK &&
+                   rinfo->dir_nr)
                        ceph_readdir_prepopulate(req, req->r_session);
                ceph_unreserve_caps(mdsc, &req->r_caps_reservation);
        }
index 9341fd4f14320060a395c37f81b4a67b01c020d7..aabe563b54db308af80ee9fff18dd81610a9cf94 100644 (file)
@@ -42,26 +42,37 @@ struct ceph_mds_reply_info_in {
 };
 
 /*
- * parsed info about an mds reply, including information about the
- * target inode and/or its parent directory and dentry, and directory
- * contents (for readdir results).
+ * parsed info about an mds reply, including information about
+ * either: 1) the target inode and/or its parent directory and dentry,
+ * and directory contents (for readdir results), or
+ * 2) the file range lock info (for fcntl F_GETLK results).
  */
 struct ceph_mds_reply_info_parsed {
        struct ceph_mds_reply_head    *head;
 
+       /* trace */
        struct ceph_mds_reply_info_in diri, targeti;
        struct ceph_mds_reply_dirfrag *dirfrag;
        char                          *dname;
        u32                           dname_len;
        struct ceph_mds_reply_lease   *dlease;
 
-       struct ceph_mds_reply_dirfrag *dir_dir;
-       int                           dir_nr;
-       char                          **dir_dname;
-       u32                           *dir_dname_len;
-       struct ceph_mds_reply_lease   **dir_dlease;
-       struct ceph_mds_reply_info_in *dir_in;
-       u8                            dir_complete, dir_end;
+       /* extra */
+       union {
+               /* for fcntl F_GETLK results */
+               struct ceph_filelock *filelock_reply;
+
+               /* for readdir results */
+               struct {
+                       struct ceph_mds_reply_dirfrag *dir_dir;
+                       int                           dir_nr;
+                       char                          **dir_dname;
+                       u32                           *dir_dname_len;
+                       struct ceph_mds_reply_lease   **dir_dlease;
+                       struct ceph_mds_reply_info_in *dir_in;
+                       u8                            dir_complete, dir_end;
+               };
+       };
 
        /* encoded blob describing snapshot contexts for certain
           operations (e.g., open) */
index adefa60a9bdc10108ec9c802e4cbe1ea26f3f6e0..43b19dd391912476c395ffbabaaabbacc28d0146 100644 (file)
@@ -6,7 +6,9 @@ obj-$(CONFIG_CIFS) += cifs.o
 cifs-y := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o \
          link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o \
          md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o \
-         readdir.o ioctl.o sess.o export.o cifsacl.o
+         readdir.o ioctl.o sess.o export.o
+
+cifs-$(CONFIG_CIFS_ACL) += cifsacl.o
 
 cifs-$(CONFIG_CIFS_UPCALL) += cifs_spnego.o
 
index ee68d1036544d591930af8119d5e7450634adfff..46af99ab3614d545675e41e788686b39fd51204b 100644 (file)
@@ -337,6 +337,15 @@ A partial list of the supported mount options follows:
   wsize                default write size (default 57344)
                maximum wsize currently allowed by CIFS is 57344 (fourteen
                4096 byte pages)
+  actimeo=n    attribute cache timeout in seconds (default 1 second).
+               After this timeout, the cifs client requests fresh attribute
+               information from the server. This option allows to tune the
+               attribute cache timeout to suit the workload needs. Shorter
+               timeouts mean better the cache coherency, but increased number
+               of calls to the server. Longer timeouts mean reduced number
+               of calls to the server at the expense of less stricter cache
+               coherency checks (i.e. incorrect attribute cache for a short
+               period of time).
   rw           mount the network share read-write (note that the
                server may still consider the share read-only)
   ro           mount network share read-only
index e9a393c9c2ca4ddb8ec3d75cfcf0766234ec1789..7852cd6770517a8a5da7877fb788a834a0534c86 100644 (file)
@@ -48,6 +48,7 @@ struct cifs_sb_info {
        struct nls_table *local_nls;
        unsigned int rsize;
        unsigned int wsize;
+       unsigned long actimeo; /* attribute cache timeout (jiffies) */
        atomic_t active;
        uid_t   mnt_uid;
        gid_t   mnt_gid;
index c6ebea088ac7c2bf6d01d3ac02910f0164a4b4b3..a437ec391a015fb7c05725543d6c118eadefc466 100644 (file)
@@ -30,8 +30,6 @@
 #include "cifs_debug.h"
 
 
-#ifdef CONFIG_CIFS_EXPERIMENTAL
-
 static struct cifs_wksid wksidarr[NUM_WK_SIDS] = {
        {{1, 0, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0} }, "null user"},
        {{1, 1, {0, 0, 0, 0, 0, 1}, {0, 0, 0, 0, 0} }, "nobody"},
@@ -774,4 +772,3 @@ int mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode)
 
        return rc;
 }
-#endif /* CONFIG_CIFS_EXPERIMENTAL */
index 6c8096cf51557764aa10af6c28d108d3e93ce6e7..c4ae7d0365631f5d01db610ef3153502f2531c9d 100644 (file)
@@ -74,11 +74,7 @@ struct cifs_wksid {
        char sidname[SIDNAMELENGTH];
 } __attribute__((packed));
 
-#ifdef CONFIG_CIFS_EXPERIMENTAL
-
 extern int match_sid(struct cifs_sid *);
 extern int compare_sids(const struct cifs_sid *, const struct cifs_sid *);
 
-#endif /*  CONFIG_CIFS_EXPERIMENTAL */
-
 #endif /* _CIFSACL_H */
index 76c8a906a63eee2369123f0ea1f433ad58692b1e..3936aa7f2c2285cfb59857f8fe1925528920543a 100644 (file)
@@ -463,6 +463,8 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m)
 
        seq_printf(s, ",rsize=%d", cifs_sb->rsize);
        seq_printf(s, ",wsize=%d", cifs_sb->wsize);
+       /* convert actimeo and display it in seconds */
+               seq_printf(s, ",actimeo=%lu", cifs_sb->actimeo / HZ);
 
        return 0;
 }
@@ -935,7 +937,6 @@ init_cifs(void)
        GlobalCurrentXid = 0;
        GlobalTotalActiveXid = 0;
        GlobalMaxActiveXid = 0;
-       memset(Local_System_Name, 0, 15);
        spin_lock_init(&cifs_tcp_ses_lock);
        spin_lock_init(&cifs_file_list_lock);
        spin_lock_init(&GlobalMid_Lock);
index b577bf0a1bb3622491ed0a885ca30b9e7684d24e..7136c0c3e2f961ec2c57d882163a1ffbc0e50ef1 100644 (file)
 
 #define CIFS_MIN_RCV_POOL 4
 
+/*
+ * default attribute cache timeout (jiffies)
+ */
+#define CIFS_DEF_ACTIMEO (1 * HZ)
+
+/*
+ * max attribute cache timeout (jiffies) - 2^30
+ */
+#define CIFS_MAX_ACTIMEO (1 << 30)
+
 /*
  * MAX_REQ is the maximum number of requests that WE will send
  * on one socket concurrently. It also matches the most common
@@ -746,8 +756,6 @@ GLOBAL_EXTERN unsigned int GlobalTotalActiveXid; /* prot by GlobalMid_Sem */
 GLOBAL_EXTERN unsigned int GlobalMaxActiveXid; /* prot by GlobalMid_Sem */
 GLOBAL_EXTERN spinlock_t GlobalMid_Lock;  /* protects above & list operations */
                                          /* on midQ entries */
-GLOBAL_EXTERN char Local_System_Name[15];
-
 /*
  *  Global counters, updated atomically
  */
index db961dc4fd3d30b4bbdf15924c1e58fded05b10e..e6d1481b16c1403cbe1c7fcae04e11abcc3f91f9 100644 (file)
@@ -54,7 +54,8 @@ do {                                                          \
             __func__, curr_xid, (int)rc);                      \
 } while (0)
 extern char *build_path_from_dentry(struct dentry *);
-extern char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb);
+extern char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb,
+                                       struct cifsTconInfo *tcon);
 extern char *build_wildcard_path_from_dentry(struct dentry *direntry);
 extern char *cifs_compose_mount_options(const char *sb_mountdata,
                const char *fullpath, const struct dfs_info3_param *ref,
@@ -79,9 +80,7 @@ extern bool is_valid_oplock_break(struct smb_hdr *smb,
                                  struct TCP_Server_Info *);
 extern bool is_size_safe_to_change(struct cifsInodeInfo *, __u64 eof);
 extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *, bool);
-#ifdef CONFIG_CIFS_EXPERIMENTAL
 extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *, bool);
-#endif
 extern unsigned int smbCalcSize(struct smb_hdr *ptr);
 extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr);
 extern int decode_negTokenInit(unsigned char *security_blob, int length,
index 2f2632b6df5a1efd960bf44502d280e0e9499908..67acfb3acad271a51be1a1446d4f9828119e6b39 100644 (file)
@@ -2478,95 +2478,6 @@ querySymLinkRetry:
 }
 
 #ifdef CONFIG_CIFS_EXPERIMENTAL
-/* Initialize NT TRANSACT SMB into small smb request buffer.
-   This assumes that all NT TRANSACTS that we init here have
-   total parm and data under about 400 bytes (to fit in small cifs
-   buffer size), which is the case so far, it easily fits. NB:
-       Setup words themselves and ByteCount
-       MaxSetupCount (size of returned setup area) and
-       MaxParameterCount (returned parms size) must be set by caller */
-static int
-smb_init_nttransact(const __u16 sub_command, const int setup_count,
-                  const int parm_len, struct cifsTconInfo *tcon,
-                  void **ret_buf)
-{
-       int rc;
-       __u32 temp_offset;
-       struct smb_com_ntransact_req *pSMB;
-
-       rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
-                               (void **)&pSMB);
-       if (rc)
-               return rc;
-       *ret_buf = (void *)pSMB;
-       pSMB->Reserved = 0;
-       pSMB->TotalParameterCount = cpu_to_le32(parm_len);
-       pSMB->TotalDataCount  = 0;
-       pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
-                                         MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
-       pSMB->ParameterCount = pSMB->TotalParameterCount;
-       pSMB->DataCount  = pSMB->TotalDataCount;
-       temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
-                       (setup_count * 2) - 4 /* for rfc1001 length itself */;
-       pSMB->ParameterOffset = cpu_to_le32(temp_offset);
-       pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
-       pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
-       pSMB->SubCommand = cpu_to_le16(sub_command);
-       return 0;
-}
-
-static int
-validate_ntransact(char *buf, char **ppparm, char **ppdata,
-                  __u32 *pparmlen, __u32 *pdatalen)
-{
-       char *end_of_smb;
-       __u32 data_count, data_offset, parm_count, parm_offset;
-       struct smb_com_ntransact_rsp *pSMBr;
-
-       *pdatalen = 0;
-       *pparmlen = 0;
-
-       if (buf == NULL)
-               return -EINVAL;
-
-       pSMBr = (struct smb_com_ntransact_rsp *)buf;
-
-       /* ByteCount was converted from little endian in SendReceive */
-       end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
-                       (char *)&pSMBr->ByteCount;
-
-       data_offset = le32_to_cpu(pSMBr->DataOffset);
-       data_count = le32_to_cpu(pSMBr->DataCount);
-       parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
-       parm_count = le32_to_cpu(pSMBr->ParameterCount);
-
-       *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
-       *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
-
-       /* should we also check that parm and data areas do not overlap? */
-       if (*ppparm > end_of_smb) {
-               cFYI(1, "parms start after end of smb");
-               return -EINVAL;
-       } else if (parm_count + *ppparm > end_of_smb) {
-               cFYI(1, "parm end after end of smb");
-               return -EINVAL;
-       } else if (*ppdata > end_of_smb) {
-               cFYI(1, "data starts after end of smb");
-               return -EINVAL;
-       } else if (data_count + *ppdata > end_of_smb) {
-               cFYI(1, "data %p + count %d (%p) past smb end %p start %p",
-                       *ppdata, data_count, (data_count + *ppdata),
-                       end_of_smb, pSMBr);
-               return -EINVAL;
-       } else if (parm_count + data_count > pSMBr->ByteCount) {
-               cFYI(1, "parm count and data count larger than SMB");
-               return -EINVAL;
-       }
-       *pdatalen = data_count;
-       *pparmlen = parm_count;
-       return 0;
-}
-
 int
 CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
                        const unsigned char *searchName,
@@ -3056,7 +2967,97 @@ GetExtAttrOut:
 
 #endif /* CONFIG_POSIX */
 
-#ifdef CONFIG_CIFS_EXPERIMENTAL
+#ifdef CONFIG_CIFS_ACL
+/*
+ * Initialize NT TRANSACT SMB into small smb request buffer.  This assumes that
+ * all NT TRANSACTS that we init here have total parm and data under about 400
+ * bytes (to fit in small cifs buffer size), which is the case so far, it
+ * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
+ * returned setup area) and MaxParameterCount (returned parms size) must be set
+ * by caller
+ */
+static int
+smb_init_nttransact(const __u16 sub_command, const int setup_count,
+                  const int parm_len, struct cifsTconInfo *tcon,
+                  void **ret_buf)
+{
+       int rc;
+       __u32 temp_offset;
+       struct smb_com_ntransact_req *pSMB;
+
+       rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
+                               (void **)&pSMB);
+       if (rc)
+               return rc;
+       *ret_buf = (void *)pSMB;
+       pSMB->Reserved = 0;
+       pSMB->TotalParameterCount = cpu_to_le32(parm_len);
+       pSMB->TotalDataCount  = 0;
+       pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
+                                         MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
+       pSMB->ParameterCount = pSMB->TotalParameterCount;
+       pSMB->DataCount  = pSMB->TotalDataCount;
+       temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
+                       (setup_count * 2) - 4 /* for rfc1001 length itself */;
+       pSMB->ParameterOffset = cpu_to_le32(temp_offset);
+       pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
+       pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
+       pSMB->SubCommand = cpu_to_le16(sub_command);
+       return 0;
+}
+
+static int
+validate_ntransact(char *buf, char **ppparm, char **ppdata,
+                  __u32 *pparmlen, __u32 *pdatalen)
+{
+       char *end_of_smb;
+       __u32 data_count, data_offset, parm_count, parm_offset;
+       struct smb_com_ntransact_rsp *pSMBr;
+
+       *pdatalen = 0;
+       *pparmlen = 0;
+
+       if (buf == NULL)
+               return -EINVAL;
+
+       pSMBr = (struct smb_com_ntransact_rsp *)buf;
+
+       /* ByteCount was converted from little endian in SendReceive */
+       end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
+                       (char *)&pSMBr->ByteCount;
+
+       data_offset = le32_to_cpu(pSMBr->DataOffset);
+       data_count = le32_to_cpu(pSMBr->DataCount);
+       parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
+       parm_count = le32_to_cpu(pSMBr->ParameterCount);
+
+       *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
+       *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
+
+       /* should we also check that parm and data areas do not overlap? */
+       if (*ppparm > end_of_smb) {
+               cFYI(1, "parms start after end of smb");
+               return -EINVAL;
+       } else if (parm_count + *ppparm > end_of_smb) {
+               cFYI(1, "parm end after end of smb");
+               return -EINVAL;
+       } else if (*ppdata > end_of_smb) {
+               cFYI(1, "data starts after end of smb");
+               return -EINVAL;
+       } else if (data_count + *ppdata > end_of_smb) {
+               cFYI(1, "data %p + count %d (%p) past smb end %p start %p",
+                       *ppdata, data_count, (data_count + *ppdata),
+                       end_of_smb, pSMBr);
+               return -EINVAL;
+       } else if (parm_count + data_count > pSMBr->ByteCount) {
+               cFYI(1, "parm count and data count larger than SMB");
+               return -EINVAL;
+       }
+       *pdatalen = data_count;
+       *pparmlen = parm_count;
+       return 0;
+}
+
 /* Get Security Descriptor (by handle) from remote server for a file or dir */
 int
 CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
@@ -3214,7 +3215,7 @@ setCifsAclRetry:
        return (rc);
 }
 
-#endif /* CONFIG_CIFS_EXPERIMENTAL */
+#endif /* CONFIG_CIFS_ACL */
 
 /* Legacy Query Path Information call for lookup to old servers such
    as Win9x/WinME */
index 32fa4d9b5dbc11537dfc09653215a9540668e109..cc1a8604a790b46767e066a59ef897f314144163 100644 (file)
@@ -105,6 +105,7 @@ struct smb_vol {
        unsigned int wsize;
        bool sockopt_tcp_nodelay:1;
        unsigned short int port;
+       unsigned long actimeo; /* attribute cache timeout (jiffies) */
        char *prepath;
        struct sockaddr_storage srcaddr; /* allow binding to a local IP */
        struct nls_table *local_nls;
@@ -806,23 +807,20 @@ cifs_parse_mount_options(char *options, const char *devname,
        short int override_gid = -1;
        bool uid_specified = false;
        bool gid_specified = false;
+       char *nodename = utsname()->nodename;
 
        separator[0] = ',';
        separator[1] = 0;
 
-       if (Local_System_Name[0] != 0)
-               memcpy(vol->source_rfc1001_name, Local_System_Name, 15);
-       else {
-               char *nodename = utsname()->nodename;
-               int n = strnlen(nodename, 15);
-               memset(vol->source_rfc1001_name, 0x20, 15);
-               for (i = 0; i < n; i++) {
-                       /* does not have to be perfect mapping since field is
-                       informational, only used for servers that do not support
-                       port 445 and it can be overridden at mount time */
-                       vol->source_rfc1001_name[i] = toupper(nodename[i]);
-               }
-       }
+       /*
+        * does not have to be perfect mapping since field is
+        * informational, only used for servers that do not support
+        * port 445 and it can be overridden at mount time
+        */
+       memset(vol->source_rfc1001_name, 0x20, 15);
+       for (i = 0; i < strnlen(nodename, 15); i++)
+               vol->source_rfc1001_name[i] = toupper(nodename[i]);
+
        vol->source_rfc1001_name[15] = 0;
        /* null target name indicates to use *SMBSERVR default called name
           if we end up sending RFC1001 session initialize */
@@ -840,6 +838,8 @@ cifs_parse_mount_options(char *options, const char *devname,
        /* default to using server inode numbers where available */
        vol->server_ino = 1;
 
+       vol->actimeo = CIFS_DEF_ACTIMEO;
+
        if (!options)
                return 1;
 
@@ -1214,6 +1214,16 @@ cifs_parse_mount_options(char *options, const char *devname,
                                        printk(KERN_WARNING "CIFS: server net"
                                        "biosname longer than 15 truncated.\n");
                        }
+               } else if (strnicmp(data, "actimeo", 7) == 0) {
+                       if (value && *value) {
+                               vol->actimeo = HZ * simple_strtoul(value,
+                                                                  &value, 0);
+                               if (vol->actimeo > CIFS_MAX_ACTIMEO) {
+                                       cERROR(1, "CIFS: attribute cache"
+                                                       "timeout too large");
+                                       return 1;
+                               }
+                       }
                } else if (strnicmp(data, "credentials", 4) == 0) {
                        /* ignore */
                } else if (strnicmp(data, "version", 3) == 0) {
@@ -2571,6 +2581,8 @@ static void setup_cifs_sb(struct smb_vol *pvolume_info,
        cFYI(1, "file mode: 0x%x  dir mode: 0x%x",
                cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode);
 
+       cifs_sb->actimeo = pvolume_info->actimeo;
+
        if (pvolume_info->noperm)
                cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
        if (pvolume_info->setuids)
@@ -2821,13 +2833,13 @@ remote_path_check:
        /* check if a whole path (including prepath) is not remote */
        if (!rc && cifs_sb->prepathlen && tcon) {
                /* build_path_to_root works only when we have a valid tcon */
-               full_path = cifs_build_path_to_root(cifs_sb);
+               full_path = cifs_build_path_to_root(cifs_sb, tcon);
                if (full_path == NULL) {
                        rc = -ENOMEM;
                        goto mount_fail_check;
                }
                rc = is_path_accessible(xid, tcon, cifs_sb, full_path);
-               if (rc != -EREMOTE) {
+               if (rc != 0 && rc != -EREMOTE) {
                        kfree(full_path);
                        goto mount_fail_check;
                }
index b857ce5db7755143affed1224c778d34ddc77b99..5a28660ca2b5e619955c05d74d9d84b95a994a4b 100644 (file)
@@ -1108,7 +1108,6 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file,
        return total_written;
 }
 
-#ifdef CONFIG_CIFS_EXPERIMENTAL
 struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode,
                                        bool fsuid_only)
 {
@@ -1142,7 +1141,6 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode,
        spin_unlock(&cifs_file_list_lock);
        return NULL;
 }
-#endif
 
 struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode,
                                        bool fsuid_only)
index 28cb6e735943f935d3ed9408f34152ba35f100b7..589f3e3f6e0023b1f8b09f1e030119896117c94f 100644 (file)
@@ -686,7 +686,7 @@ int cifs_get_inode_info(struct inode **pinode,
                        cFYI(1, "cifs_sfu_type failed: %d", tmprc);
        }
 
-#ifdef CONFIG_CIFS_EXPERIMENTAL
+#ifdef CONFIG_CIFS_ACL
        /* fill in 0777 bits from ACL */
        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
                rc = cifs_acl_to_fattr(cifs_sb, &fattr, *pinode, full_path,
@@ -697,7 +697,7 @@ int cifs_get_inode_info(struct inode **pinode,
                        goto cgii_exit;
                }
        }
-#endif
+#endif /* CONFIG_CIFS_ACL */
 
        /* fill in remaining high mode bits e.g. SUID, VTX */
        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)
@@ -728,12 +728,12 @@ static const struct inode_operations cifs_ipc_inode_ops = {
        .lookup = cifs_lookup,
 };
 
-char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb)
+char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb,
+                               struct cifsTconInfo *tcon)
 {
        int pplen = cifs_sb->prepathlen;
        int dfsplen;
        char *full_path = NULL;
-       struct cifsTconInfo *tcon = cifs_sb_master_tcon(cifs_sb);
 
        /* if no prefix path, simply set path to the root of share to "" */
        if (pplen == 0) {
@@ -875,7 +875,7 @@ struct inode *cifs_root_iget(struct super_block *sb, unsigned long ino)
        char *full_path;
        struct cifsTconInfo *tcon = cifs_sb_master_tcon(cifs_sb);
 
-       full_path = cifs_build_path_to_root(cifs_sb);
+       full_path = cifs_build_path_to_root(cifs_sb, tcon);
        if (full_path == NULL)
                return ERR_PTR(-ENOMEM);
 
@@ -1653,6 +1653,7 @@ static bool
 cifs_inode_needs_reval(struct inode *inode)
 {
        struct cifsInodeInfo *cifs_i = CIFS_I(inode);
+       struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
 
        if (cifs_i->clientCanCacheRead)
                return false;
@@ -1663,12 +1664,12 @@ cifs_inode_needs_reval(struct inode *inode)
        if (cifs_i->time == 0)
                return true;
 
-       /* FIXME: the actimeo should be tunable */
-       if (time_after_eq(jiffies, cifs_i->time + HZ))
+       if (!time_in_range(jiffies, cifs_i->time,
+                               cifs_i->time + cifs_sb->actimeo))
                return true;
 
        /* hardlinked files w/ noserverino get "special" treatment */
-       if (!(CIFS_SB(inode->i_sb)->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) &&
+       if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) &&
            S_ISREG(inode->i_mode) && inode->i_nlink != 1)
                return true;
 
@@ -2121,7 +2122,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
 
        if (attrs->ia_valid & ATTR_MODE) {
                rc = 0;
-#ifdef CONFIG_CIFS_EXPERIMENTAL
+#ifdef CONFIG_CIFS_ACL
                if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
                        rc = mode_to_cifs_acl(inode, full_path, mode);
                        if (rc) {
@@ -2130,7 +2131,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
                                goto cifs_setattr_exit;
                        }
                } else
-#endif
+#endif /* CONFIG_CIFS_ACL */
                if (((mode & S_IWUGO) == 0) &&
                    (cifsInode->cifsAttrs & ATTR_READONLY) == 0) {
 
index 32d300e8f20eb4a6676b8da50187a4b04146fcb8..a73eb9f4bdaf3608c2bf6f5dc124b5fabdd4445b 100644 (file)
@@ -759,18 +759,6 @@ static int cifs_filldir(char *pfindEntry, struct file *file, filldir_t filldir,
        rc = filldir(direntry, qstring.name, qstring.len, file->f_pos,
                     ino, fattr.cf_dtype);
 
-       /*
-        * we can not return filldir errors to the caller since they are
-        * "normal" when the stat blocksize is too small - we return remapped
-        * error instead
-        *
-        * FIXME: This looks bogus. filldir returns -EOVERFLOW in the above
-        * case already. Why should we be clobbering other errors from it?
-        */
-       if (rc) {
-               cFYI(1, "filldir rc = %d", rc);
-               rc = -EOVERFLOW;
-       }
        dput(tmp_dentry);
        return rc;
 }
index 9242d294fe90d382fb7a40f1220923baea71c97e..8b984a2cebbda185af01a6d4d5f8c31c89fc6fbe 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/module.h>
+#include <linux/compat.h>
 
 static const struct file_operations fuse_direct_io_file_operations;
 
@@ -1627,6 +1628,58 @@ static int fuse_ioctl_copy_user(struct page **pages, struct iovec *iov,
        return 0;
 }
 
+/*
+ * CUSE servers compiled on 32bit broke on 64bit kernels because the
+ * ABI was defined to be 'struct iovec' which is different on 32bit
+ * and 64bit.  Fortunately we can determine which structure the server
+ * used from the size of the reply.
+ */
+static int fuse_copy_ioctl_iovec(struct iovec *dst, void *src,
+                                size_t transferred, unsigned count,
+                                bool is_compat)
+{
+#ifdef CONFIG_COMPAT
+       if (count * sizeof(struct compat_iovec) == transferred) {
+               struct compat_iovec *ciov = src;
+               unsigned i;
+
+               /*
+                * With this interface a 32bit server cannot support
+                * non-compat (i.e. ones coming from 64bit apps) ioctl
+                * requests
+                */
+               if (!is_compat)
+                       return -EINVAL;
+
+               for (i = 0; i < count; i++) {
+                       dst[i].iov_base = compat_ptr(ciov[i].iov_base);
+                       dst[i].iov_len = ciov[i].iov_len;
+               }
+               return 0;
+       }
+#endif
+
+       if (count * sizeof(struct iovec) != transferred)
+               return -EIO;
+
+       memcpy(dst, src, transferred);
+       return 0;
+}
+
+/* Make sure iov_length() won't overflow */
+static int fuse_verify_ioctl_iov(struct iovec *iov, size_t count)
+{
+       size_t n;
+       u32 max = FUSE_MAX_PAGES_PER_REQ << PAGE_SHIFT;
+
+       for (n = 0; n < count; n++) {
+               if (iov->iov_len > (size_t) max)
+                       return -ENOMEM;
+               max -= iov->iov_len;
+       }
+       return 0;
+}
+
 /*
  * For ioctls, there is no generic way to determine how much memory
  * needs to be read and/or written.  Furthermore, ioctls are allowed
@@ -1808,18 +1861,25 @@ long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg,
                    in_iovs + out_iovs > FUSE_IOCTL_MAX_IOV)
                        goto out;
 
-               err = -EIO;
-               if ((in_iovs + out_iovs) * sizeof(struct iovec) != transferred)
-                       goto out;
-
-               /* okay, copy in iovs and retry */
                vaddr = kmap_atomic(pages[0], KM_USER0);
-               memcpy(page_address(iov_page), vaddr, transferred);
+               err = fuse_copy_ioctl_iovec(page_address(iov_page), vaddr,
+                                           transferred, in_iovs + out_iovs,
+                                           (flags & FUSE_IOCTL_COMPAT) != 0);
                kunmap_atomic(vaddr, KM_USER0);
+               if (err)
+                       goto out;
 
                in_iov = page_address(iov_page);
                out_iov = in_iov + in_iovs;
 
+               err = fuse_verify_ioctl_iov(in_iov, in_iovs);
+               if (err)
+                       goto out;
+
+               err = fuse_verify_ioctl_iov(out_iov, out_iovs);
+               if (err)
+                       goto out;
+
                goto retry;
        }
 
index f0a384e2ae633a1dc2de619d102d5935ff32a273..996dd8989a9135203cab110f57e7c1f8df49e200 100644 (file)
@@ -57,7 +57,7 @@ static int nfs_rename(struct inode *, struct dentry *,
                      struct inode *, struct dentry *);
 static int nfs_fsync_dir(struct file *, int);
 static loff_t nfs_llseek_dir(struct file *, loff_t, int);
-static int nfs_readdir_clear_array(struct page*, gfp_t);
+static void nfs_readdir_clear_array(struct page*);
 
 const struct file_operations nfs_dir_operations = {
        .llseek         = nfs_llseek_dir,
@@ -83,8 +83,8 @@ const struct inode_operations nfs_dir_inode_operations = {
        .setattr        = nfs_setattr,
 };
 
-const struct address_space_operations nfs_dir_addr_space_ops = {
-       .releasepage = nfs_readdir_clear_array,
+const struct address_space_operations nfs_dir_aops = {
+       .freepage = nfs_readdir_clear_array,
 };
 
 #ifdef CONFIG_NFS_V3
@@ -178,6 +178,7 @@ typedef struct {
        struct page     *page;
        unsigned long   page_index;
        u64             *dir_cookie;
+       u64             last_cookie;
        loff_t          current_index;
        decode_dirent_t decode;
 
@@ -213,17 +214,15 @@ void nfs_readdir_release_array(struct page *page)
  * we are freeing strings created by nfs_add_to_readdir_array()
  */
 static
-int nfs_readdir_clear_array(struct page *page, gfp_t mask)
+void nfs_readdir_clear_array(struct page *page)
 {
-       struct nfs_cache_array *array = nfs_readdir_get_array(page);
+       struct nfs_cache_array *array;
        int i;
 
-       if (IS_ERR(array))
-               return PTR_ERR(array);
+       array = kmap_atomic(page, KM_USER0);
        for (i = 0; i < array->size; i++)
                kfree(array->array[i].string.name);
-       nfs_readdir_release_array(page);
-       return 0;
+       kunmap_atomic(array, KM_USER0);
 }
 
 /*
@@ -272,7 +271,7 @@ int nfs_readdir_add_to_array(struct nfs_entry *entry, struct page *page)
                goto out;
        array->last_cookie = entry->cookie;
        array->size++;
-       if (entry->eof == 1)
+       if (entry->eof != 0)
                array->eof_index = array->size;
 out:
        nfs_readdir_release_array(page);
@@ -312,15 +311,14 @@ int nfs_readdir_search_for_cookie(struct nfs_cache_array *array, nfs_readdir_des
        for (i = 0; i < array->size; i++) {
                if (array->array[i].cookie == *desc->dir_cookie) {
                        desc->cache_entry_index = i;
-                       status = 0;
-                       goto out;
+                       return 0;
                }
        }
-       if (i == array->eof_index) {
-               desc->eof = 1;
+       if (array->eof_index >= 0) {
                status = -EBADCOOKIE;
+               if (*desc->dir_cookie == array->last_cookie)
+                       desc->eof = 1;
        }
-out:
        return status;
 }
 
@@ -328,10 +326,7 @@ static
 int nfs_readdir_search_array(nfs_readdir_descriptor_t *desc)
 {
        struct nfs_cache_array *array;
-       int status = -EBADCOOKIE;
-
-       if (desc->dir_cookie == NULL)
-               goto out;
+       int status;
 
        array = nfs_readdir_get_array(desc->page);
        if (IS_ERR(array)) {
@@ -344,6 +339,10 @@ int nfs_readdir_search_array(nfs_readdir_descriptor_t *desc)
        else
                status = nfs_readdir_search_for_cookie(array, desc);
 
+       if (status == -EAGAIN) {
+               desc->last_cookie = array->last_cookie;
+               desc->page_index++;
+       }
        nfs_readdir_release_array(desc->page);
 out:
        return status;
@@ -490,7 +489,7 @@ int nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *en
 
                count++;
 
-               if (desc->plus == 1)
+               if (desc->plus != 0)
                        nfs_prime_dcache(desc->file->f_path.dentry, entry);
 
                status = nfs_readdir_add_to_array(entry, page);
@@ -498,7 +497,7 @@ int nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *en
                        break;
        } while (!entry->eof);
 
-       if (count == 0 || (status == -EBADCOOKIE && entry->eof == 1)) {
+       if (count == 0 || (status == -EBADCOOKIE && entry->eof != 0)) {
                array = nfs_readdir_get_array(page);
                if (!IS_ERR(array)) {
                        array->eof_index = array->size;
@@ -563,7 +562,7 @@ int nfs_readdir_xdr_to_array(nfs_readdir_descriptor_t *desc, struct page *page,
        unsigned int array_size = ARRAY_SIZE(pages);
 
        entry.prev_cookie = 0;
-       entry.cookie = *desc->dir_cookie;
+       entry.cookie = desc->last_cookie;
        entry.eof = 0;
        entry.fh = nfs_alloc_fhandle();
        entry.fattr = nfs_alloc_fattr();
@@ -636,6 +635,8 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page* page)
 static
 void cache_page_release(nfs_readdir_descriptor_t *desc)
 {
+       if (!desc->page->mapping)
+               nfs_readdir_clear_array(desc->page);
        page_cache_release(desc->page);
        desc->page = NULL;
 }
@@ -660,9 +661,8 @@ int find_cache_page(nfs_readdir_descriptor_t *desc)
                return PTR_ERR(desc->page);
 
        res = nfs_readdir_search_array(desc);
-       if (res == 0)
-               return 0;
-       cache_page_release(desc);
+       if (res != 0)
+               cache_page_release(desc);
        return res;
 }
 
@@ -672,22 +672,16 @@ int readdir_search_pagecache(nfs_readdir_descriptor_t *desc)
 {
        int res;
 
-       if (desc->page_index == 0)
+       if (desc->page_index == 0) {
                desc->current_index = 0;
-       while (1) {
-               res = find_cache_page(desc);
-               if (res != -EAGAIN)
-                       break;
-               desc->page_index++;
+               desc->last_cookie = 0;
        }
+       do {
+               res = find_cache_page(desc);
+       } while (res == -EAGAIN);
        return res;
 }
 
-static inline unsigned int dt_type(struct inode *inode)
-{
-       return (inode->i_mode >> 12) & 15;
-}
-
 /*
  * Once we've found the start of the dirent within a page: fill 'er up...
  */
@@ -717,13 +711,12 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent,
                        break;
                }
                file->f_pos++;
-               desc->cache_entry_index = i;
                if (i < (array->size-1))
                        *desc->dir_cookie = array->array[i+1].cookie;
                else
                        *desc->dir_cookie = array->last_cookie;
        }
-       if (i == array->eof_index)
+       if (array->eof_index >= 0)
                desc->eof = 1;
 
        nfs_readdir_release_array(desc->page);
@@ -764,6 +757,7 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent,
        }
 
        desc->page_index = 0;
+       desc->last_cookie = *desc->dir_cookie;
        desc->page = page;
 
        status = nfs_readdir_xdr_to_array(desc, page, inode);
@@ -791,7 +785,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
        struct inode    *inode = dentry->d_inode;
        nfs_readdir_descriptor_t my_desc,
                        *desc = &my_desc;
-       int res = -ENOMEM;
+       int res;
 
        dfprintk(FILE, "NFS: readdir(%s/%s) starting at cookie %llu\n",
                        dentry->d_parent->d_name.name, dentry->d_name.name,
@@ -816,7 +810,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
        if (res < 0)
                goto out;
 
-       while (desc->eof != 1) {
+       do {
                res = readdir_search_pagecache(desc);
 
                if (res == -EBADCOOKIE) {
@@ -844,7 +838,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
                res = nfs_do_filldir(desc, dirent, filldir);
                if (res < 0)
                        break;
-       }
+       } while (!desc->eof);
 out:
        nfs_unblock_sillyrename(dentry);
        if (res > 0)
index 60677f9f13110d1a98774595de819fddf2c0ccdf..7bf029ef4084c6e7f02e05e355382168e85e2cb8 100644 (file)
@@ -693,6 +693,7 @@ do_getlk(struct file *filp, int cmd, struct file_lock *fl, int is_local)
 {
        struct inode *inode = filp->f_mapping->host;
        int status = 0;
+       unsigned int saved_type = fl->fl_type;
 
        /* Try local locking first */
        posix_test_lock(filp, fl);
@@ -700,6 +701,7 @@ do_getlk(struct file *filp, int cmd, struct file_lock *fl, int is_local)
                /* found a conflict */
                goto out;
        }
+       fl->fl_type = saved_type;
 
        if (nfs_have_delegation(inode, FMODE_READ))
                goto out_noconflict;
index 314f57164602eda0762c0a226db44aa19be461f5..e67e31c734163c6fe6c0eef0d338a2b87ae55763 100644 (file)
@@ -289,6 +289,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
                } else if (S_ISDIR(inode->i_mode)) {
                        inode->i_op = NFS_SB(sb)->nfs_client->rpc_ops->dir_inode_ops;
                        inode->i_fop = &nfs_dir_operations;
+                       inode->i_data.a_ops = &nfs_dir_aops;
                        if (nfs_server_capable(inode, NFS_CAP_READDIRPLUS))
                                set_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(inode)->flags);
                        /* Deal with crossing mountpoints */
index eceafe74f4737ea5fbcea90b8ac19749737667b9..4f981f1f668925cba6bebe6ed4cf485da6a56dbb 100644 (file)
@@ -505,13 +505,13 @@ static struct rpc_procinfo mnt3_procedures[] = {
 
 static struct rpc_version mnt_version1 = {
        .number         = 1,
-       .nrprocs        = 2,
+       .nrprocs        = ARRAY_SIZE(mnt_procedures),
        .procs          = mnt_procedures,
 };
 
 static struct rpc_version mnt_version3 = {
        .number         = 3,
-       .nrprocs        = 2,
+       .nrprocs        = ARRAY_SIZE(mnt3_procedures),
        .procs          = mnt3_procedures,
 };
 
index 6a653ffd8e4e121e37c29d88ff2f5b0b4dbe264f..4435e5e1f904e3e5ba26f4eb578fc30c5f6d997b 100644 (file)
@@ -3361,6 +3361,8 @@ static ssize_t nfs4_proc_get_acl(struct inode *inode, void *buf, size_t buflen)
        ret = nfs_revalidate_inode(server, inode);
        if (ret < 0)
                return ret;
+       if (NFS_I(inode)->cache_validity & NFS_INO_INVALID_ACL)
+               nfs_zap_acl_cache(inode);
        ret = nfs4_read_cached_acl(inode, buf, buflen);
        if (ret != -ENOENT)
                return ret;
@@ -3389,6 +3391,13 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t bufl
        nfs_inode_return_delegation(inode);
        buf_to_pages(buf, buflen, arg.acl_pages, &arg.acl_pgbase);
        ret = nfs4_call_sync(server, &msg, &arg, &res, 1);
+       /*
+        * Acl update can result in inode attribute update.
+        * so mark the attribute cache invalid.
+        */
+       spin_lock(&inode->i_lock);
+       NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATTR;
+       spin_unlock(&inode->i_lock);
        nfs_access_zap_cache(inode);
        nfs_zap_acl_cache(inode);
        return ret;
index 137b549e63dbcfa3971aac43091eb91a29a7b69f..b68536cc9046ec937b9b4ccddb98b2acf468f1db 100644 (file)
@@ -115,7 +115,7 @@ int nfs_set_page_tag_locked(struct nfs_page *req)
 {
        if (!nfs_lock_request_dontget(req))
                return 0;
-       if (req->wb_page != NULL)
+       if (test_bit(PG_MAPPED, &req->wb_flags))
                radix_tree_tag_set(&NFS_I(req->wb_context->path.dentry->d_inode)->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED);
        return 1;
 }
@@ -125,7 +125,7 @@ int nfs_set_page_tag_locked(struct nfs_page *req)
  */
 void nfs_clear_page_tag_locked(struct nfs_page *req)
 {
-       if (req->wb_page != NULL) {
+       if (test_bit(PG_MAPPED, &req->wb_flags)) {
                struct inode *inode = req->wb_context->path.dentry->d_inode;
                struct nfs_inode *nfsi = NFS_I(inode);
 
index e4b62c6f5a6e9eb721eda53d836c41055ab2e1b7..aedcaa7f291fbe4405f2b68c13f407c7de6be9ba 100644 (file)
@@ -152,7 +152,6 @@ static void nfs_readpage_release(struct nfs_page *req)
                        (long long)NFS_FILEID(req->wb_context->path.dentry->d_inode),
                        req->wb_bytes,
                        (long long)req_offset(req));
-       nfs_clear_request(req);
        nfs_release_request(req);
 }
 
index 3c045044fca25183147704f3689c744549ebd77b..4100630c9a5b65f47bb5379ee2bc62f78e60284e 100644 (file)
@@ -1069,12 +1069,10 @@ static int nfs_parse_mount_options(char *raw,
                        mnt->flags |= NFS_MOUNT_VER3;
                        mnt->version = 3;
                        break;
-#ifdef CONFIG_NFS_V4
                case Opt_v4:
                        mnt->flags &= ~NFS_MOUNT_VER3;
                        mnt->version = 4;
                        break;
-#endif
                case Opt_udp:
                        mnt->flags &= ~NFS_MOUNT_TCP;
                        mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP;
@@ -1286,12 +1284,10 @@ static int nfs_parse_mount_options(char *raw,
                                mnt->flags |= NFS_MOUNT_VER3;
                                mnt->version = 3;
                                break;
-#ifdef CONFIG_NFS_V4
                        case NFS4_VERSION:
                                mnt->flags &= ~NFS_MOUNT_VER3;
                                mnt->version = 4;
                                break;
-#endif
                        default:
                                goto out_invalid_value;
                        }
index 4c14c17a5276a410bb383e3650f106ab56cf47d6..10d648ea128bf6345df70da0e15ee8ce443ab8e6 100644 (file)
@@ -390,6 +390,7 @@ static int nfs_inode_add_request(struct inode *inode, struct nfs_page *req)
                if (nfs_have_delegation(inode, FMODE_WRITE))
                        nfsi->change_attr++;
        }
+       set_bit(PG_MAPPED, &req->wb_flags);
        SetPagePrivate(req->wb_page);
        set_page_private(req->wb_page, (unsigned long)req);
        nfsi->npages++;
@@ -415,6 +416,7 @@ static void nfs_inode_remove_request(struct nfs_page *req)
        spin_lock(&inode->i_lock);
        set_page_private(req->wb_page, 0);
        ClearPagePrivate(req->wb_page);
+       clear_bit(PG_MAPPED, &req->wb_flags);
        radix_tree_delete(&nfsi->nfs_page_tree, req->wb_index);
        nfsi->npages--;
        if (!nfsi->npages) {
@@ -422,7 +424,6 @@ static void nfs_inode_remove_request(struct nfs_page *req)
                iput(inode);
        } else
                spin_unlock(&inode->i_lock);
-       nfs_clear_request(req);
        nfs_release_request(req);
 }
 
index 2a533a0af2a98ed91afb84e71669d328cb67a866..7e84a852cdae8117334fec6ee00d085fc29c0c66 100644 (file)
@@ -260,9 +260,11 @@ void fill_post_wcc(struct svc_fh *fhp)
        err = vfs_getattr(fhp->fh_export->ex_path.mnt, fhp->fh_dentry,
                        &fhp->fh_post_attr);
        fhp->fh_post_change = fhp->fh_dentry->d_inode->i_version;
-       if (err)
+       if (err) {
                fhp->fh_post_saved = 0;
-       else
+               /* Grab the ctime anyway - set_change_info might use it */
+               fhp->fh_post_attr.ctime = fhp->fh_dentry->d_inode->i_ctime;
+       } else
                fhp->fh_post_saved = 1;
 }
 
index 4d476ff08ae6add1ec3a1b597909f1375af78b7b..60fce3dc5cb5d9f90d22b9f9c91ddc7ddeb9ff1d 100644 (file)
@@ -484,18 +484,17 @@ static inline bool nfsd4_not_cached(struct nfsd4_compoundres *resp)
 static inline void
 set_change_info(struct nfsd4_change_info *cinfo, struct svc_fh *fhp)
 {
-       BUG_ON(!fhp->fh_pre_saved || !fhp->fh_post_saved);
-       cinfo->atomic = 1;
+       BUG_ON(!fhp->fh_pre_saved);
+       cinfo->atomic = fhp->fh_post_saved;
        cinfo->change_supported = IS_I_VERSION(fhp->fh_dentry->d_inode);
-       if (cinfo->change_supported) {
-               cinfo->before_change = fhp->fh_pre_change;
-               cinfo->after_change = fhp->fh_post_change;
-       } else {
-               cinfo->before_ctime_sec = fhp->fh_pre_ctime.tv_sec;
-               cinfo->before_ctime_nsec = fhp->fh_pre_ctime.tv_nsec;
-               cinfo->after_ctime_sec = fhp->fh_post_attr.ctime.tv_sec;
-               cinfo->after_ctime_nsec = fhp->fh_post_attr.ctime.tv_nsec;
-       }
+
+       cinfo->before_change = fhp->fh_pre_change;
+       cinfo->after_change = fhp->fh_post_change;
+       cinfo->before_ctime_sec = fhp->fh_pre_ctime.tv_sec;
+       cinfo->before_ctime_nsec = fhp->fh_pre_ctime.tv_nsec;
+       cinfo->after_ctime_sec = fhp->fh_post_attr.ctime.tv_sec;
+       cinfo->after_ctime_nsec = fhp->fh_post_attr.ctime.tv_nsec;
+
 }
 
 int nfs4svc_encode_voidres(struct svc_rqst *, __be32 *, void *);
index d2af0a8381a63975e9668d1aa7babb942bd4f4e2..77a59891734e925318f4a91723f96eb55f7b5ae8 100644 (file)
@@ -297,6 +297,7 @@ xfs_rename(
         * it and some incremental backup programs won't work without it.
         */
        xfs_trans_ichgtime(tp, src_ip, XFS_ICHGTIME_CHG);
+       xfs_trans_log_inode(tp, src_ip, XFS_ILOG_CORE);
 
        /*
         * Adjust the link count on src_dp.  This is necessary when
index c9e06cc70dad585c6c185db2d1503d3fad4a5a48..090f0eacde296ec52a06fe5eb1b13c07808b7ada 100644 (file)
@@ -602,6 +602,7 @@ struct address_space_operations {
        sector_t (*bmap)(struct address_space *, sector_t);
        void (*invalidatepage) (struct page *, unsigned long);
        int (*releasepage) (struct page *, gfp_t);
+       void (*freepage)(struct page *);
        ssize_t (*direct_IO)(int, struct kiocb *, const struct iovec *iov,
                        loff_t offset, unsigned long nr_segs);
        int (*get_xip_mem)(struct address_space *, pgoff_t, int,
index c66fdb7d6998129701f6eaa653f1d28dd641e332..29d504d5d1c31f5698433657dd534c1500f317b2 100644 (file)
@@ -401,6 +401,7 @@ extern const struct inode_operations nfs3_file_inode_operations;
 #endif /* CONFIG_NFS_V3 */
 extern const struct file_operations nfs_file_operations;
 extern const struct address_space_operations nfs_file_aops;
+extern const struct address_space_operations nfs_dir_aops;
 
 static inline struct nfs_open_context *nfs_file_open_context(struct file *filp)
 {
index f8b60e7f4c44d9b652a94bca2ab8945130bdb061..d55cee73f63477a326b73cf7eb15e3e277567b14 100644 (file)
@@ -29,6 +29,7 @@
  */
 enum {
        PG_BUSY = 0,
+       PG_MAPPED,
        PG_CLEAN,
        PG_NEED_COMMIT,
        PG_NEED_RESCHED,
index ea89840fc65fa2b499ce3c19c657e9e8a680b240..6b9aee20f2426b88024a25749402fc5ca1ff7a0a 100644 (file)
@@ -143,13 +143,18 @@ void __remove_from_page_cache(struct page *page)
 void remove_from_page_cache(struct page *page)
 {
        struct address_space *mapping = page->mapping;
+       void (*freepage)(struct page *);
 
        BUG_ON(!PageLocked(page));
 
+       freepage = mapping->a_ops->freepage;
        spin_lock_irq(&mapping->tree_lock);
        __remove_from_page_cache(page);
        spin_unlock_irq(&mapping->tree_lock);
        mem_cgroup_uncharge_cache_page(page);
+
+       if (freepage)
+               freepage(page);
 }
 EXPORT_SYMBOL(remove_from_page_cache);
 
index ba887bff48c5a263c315a6ef098284df4df5bb44..3c2d5ddfa0d49f3cf31449e214d8fbd50e92ad08 100644 (file)
@@ -390,6 +390,10 @@ invalidate_complete_page2(struct address_space *mapping, struct page *page)
        __remove_from_page_cache(page);
        spin_unlock_irq(&mapping->tree_lock);
        mem_cgroup_uncharge_cache_page(page);
+
+       if (mapping->a_ops->freepage)
+               mapping->a_ops->freepage(page);
+
        page_cache_release(page);       /* pagecache ref */
        return 1;
 failed:
index d31d7ce52c0ea2dbbf85b26019c9fdd70fab624a..9ca587c692748adbc715b440ff5aa8c89357c511 100644 (file)
@@ -494,9 +494,16 @@ static int __remove_mapping(struct address_space *mapping, struct page *page)
                spin_unlock_irq(&mapping->tree_lock);
                swapcache_free(swap, page);
        } else {
+               void (*freepage)(struct page *);
+
+               freepage = mapping->a_ops->freepage;
+
                __remove_from_page_cache(page);
                spin_unlock_irq(&mapping->tree_lock);
                mem_cgroup_uncharge_cache_page(page);
+
+               if (freepage != NULL)
+                       freepage(page);
        }
 
        return 1;
index ea2ff78dcf7b7ec4f2555210af82379017e6e291..3f2c5559ca1a49a496b9d531625c1e175fb029c8 100644 (file)
@@ -212,6 +212,7 @@ int svc_create_xprt(struct svc_serv *serv, const char *xprt_name,
        spin_lock(&svc_xprt_class_lock);
        list_for_each_entry(xcl, &svc_xprt_class_list, xcl_list) {
                struct svc_xprt *newxprt;
+               unsigned short newport;
 
                if (strcmp(xprt_name, xcl->xcl_name))
                        continue;
@@ -230,8 +231,9 @@ int svc_create_xprt(struct svc_serv *serv, const char *xprt_name,
                spin_lock_bh(&serv->sv_lock);
                list_add(&newxprt->xpt_list, &serv->sv_permsocks);
                spin_unlock_bh(&serv->sv_lock);
+               newport = svc_xprt_local_port(newxprt);
                clear_bit(XPT_BUSY, &newxprt->xpt_flags);
-               return svc_xprt_local_port(newxprt);
+               return newport;
        }
  err:
        spin_unlock(&svc_xprt_class_lock);
@@ -425,8 +427,13 @@ void svc_xprt_received(struct svc_xprt *xprt)
 {
        BUG_ON(!test_bit(XPT_BUSY, &xprt->xpt_flags));
        xprt->xpt_pool = NULL;
+       /* As soon as we clear busy, the xprt could be closed and
+        * 'put', so we need a reference to call svc_xprt_enqueue with:
+        */
+       svc_xprt_get(xprt);
        clear_bit(XPT_BUSY, &xprt->xpt_flags);
        svc_xprt_enqueue(xprt);
+       svc_xprt_put(xprt);
 }
 EXPORT_SYMBOL_GPL(svc_xprt_received);