* @nr_segs: size of iovec array
  *
  * The presence of this routine in the address space ops vector means
- * the NFS client supports direct I/O.  However, we shunt off direct
- * read and write requests before the VFS gets them, so this method
- * should never be called.
+ * the NFS client supports direct I/O. However, for most direct IO, we
+ * shunt off direct read and write requests before the VFS gets them,
+ * so this method is only ever called for swap.
  */
 ssize_t nfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, loff_t pos, unsigned long nr_segs)
 {
+#ifndef CONFIG_NFS_SWAP
        dprintk("NFS: nfs_direct_IO (%s) off/no(%Ld/%lu) EINVAL\n",
                        iocb->ki_filp->f_path.dentry->d_name.name,
                        (long long) pos, nr_segs);
 
        return -EINVAL;
+#else
+       VM_BUG_ON(iocb->ki_left != PAGE_SIZE);
+       VM_BUG_ON(iocb->ki_nbytes != PAGE_SIZE);
+
+       if (rw == READ || rw == KERNEL_READ)
+               return nfs_file_direct_read(iocb, iov, nr_segs, pos,
+                               rw == READ ? true : false);
+       return nfs_file_direct_write(iocb, iov, nr_segs, pos,
+                               rw == WRITE ? true : false);
+#endif /* CONFIG_NFS_SWAP */
 }
 
 static void nfs_direct_release_pages(struct page **pages, unsigned int npages)
  */
 static ssize_t nfs_direct_read_schedule_segment(struct nfs_pageio_descriptor *desc,
                                                const struct iovec *iov,
-                                               loff_t pos)
+                                               loff_t pos, bool uio)
 {
        struct nfs_direct_req *dreq = desc->pg_dreq;
        struct nfs_open_context *ctx = dreq->ctx;
                                          GFP_KERNEL);
                if (!pagevec)
                        break;
-               down_read(¤t->mm->mmap_sem);
-               result = get_user_pages(current, current->mm, user_addr,
+               if (uio) {
+                       down_read(¤t->mm->mmap_sem);
+                       result = get_user_pages(current, current->mm, user_addr,
                                        npages, 1, 0, pagevec, NULL);
-               up_read(¤t->mm->mmap_sem);
-               if (result < 0)
-                       break;
+                       up_read(¤t->mm->mmap_sem);
+                       if (result < 0)
+                               break;
+               } else {
+                       WARN_ON(npages != 1);
+                       result = get_kernel_page(user_addr, 1, pagevec);
+                       if (WARN_ON(result != 1))
+                               break;
+               }
+
                if ((unsigned)result < npages) {
                        bytes = result * PAGE_SIZE;
                        if (bytes <= pgbase) {
 static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq,
                                              const struct iovec *iov,
                                              unsigned long nr_segs,
-                                             loff_t pos)
+                                             loff_t pos, bool uio)
 {
        struct nfs_pageio_descriptor desc;
        ssize_t result = -EINVAL;
 
        for (seg = 0; seg < nr_segs; seg++) {
                const struct iovec *vec = &iov[seg];
-               result = nfs_direct_read_schedule_segment(&desc, vec, pos);
+               result = nfs_direct_read_schedule_segment(&desc, vec, pos, uio);
                if (result < 0)
                        break;
                requested_bytes += result;
 }
 
 static ssize_t nfs_direct_read(struct kiocb *iocb, const struct iovec *iov,
-                              unsigned long nr_segs, loff_t pos)
+                              unsigned long nr_segs, loff_t pos, bool uio)
 {
        ssize_t result = -ENOMEM;
        struct inode *inode = iocb->ki_filp->f_mapping->host;
        if (!is_sync_kiocb(iocb))
                dreq->iocb = iocb;
 
-       result = nfs_direct_read_schedule_iovec(dreq, iov, nr_segs, pos);
+       result = nfs_direct_read_schedule_iovec(dreq, iov, nr_segs, pos, uio);
        if (!result)
                result = nfs_direct_wait(dreq);
        NFS_I(inode)->read_io += result;
  */
 static ssize_t nfs_direct_write_schedule_segment(struct nfs_pageio_descriptor *desc,
                                                 const struct iovec *iov,
-                                                loff_t pos)
+                                                loff_t pos, bool uio)
 {
        struct nfs_direct_req *dreq = desc->pg_dreq;
        struct nfs_open_context *ctx = dreq->ctx;
                if (!pagevec)
                        break;
 
-               down_read(¤t->mm->mmap_sem);
-               result = get_user_pages(current, current->mm, user_addr,
-                                       npages, 0, 0, pagevec, NULL);
-               up_read(¤t->mm->mmap_sem);
-               if (result < 0)
-                       break;
+               if (uio) {
+                       down_read(¤t->mm->mmap_sem);
+                       result = get_user_pages(current, current->mm, user_addr,
+                                               npages, 0, 0, pagevec, NULL);
+                       up_read(¤t->mm->mmap_sem);
+                       if (result < 0)
+                               break;
+               } else {
+                       WARN_ON(npages != 1);
+                       result = get_kernel_page(user_addr, 0, pagevec);
+                       if (WARN_ON(result != 1))
+                               break;
+               }
 
                if ((unsigned)result < npages) {
                        bytes = result * PAGE_SIZE;
 static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq,
                                               const struct iovec *iov,
                                               unsigned long nr_segs,
-                                              loff_t pos)
+                                              loff_t pos, bool uio)
 {
        struct nfs_pageio_descriptor desc;
        struct inode *inode = dreq->inode;
 
        for (seg = 0; seg < nr_segs; seg++) {
                const struct iovec *vec = &iov[seg];
-               result = nfs_direct_write_schedule_segment(&desc, vec, pos);
+               result = nfs_direct_write_schedule_segment(&desc, vec, pos, uio);
                if (result < 0)
                        break;
                requested_bytes += result;
 
 static ssize_t nfs_direct_write(struct kiocb *iocb, const struct iovec *iov,
                                unsigned long nr_segs, loff_t pos,
-                               size_t count)
+                               size_t count, bool uio)
 {
        ssize_t result = -ENOMEM;
        struct inode *inode = iocb->ki_filp->f_mapping->host;
        if (!is_sync_kiocb(iocb))
                dreq->iocb = iocb;
 
-       result = nfs_direct_write_schedule_iovec(dreq, iov, nr_segs, pos);
+       result = nfs_direct_write_schedule_iovec(dreq, iov, nr_segs, pos, uio);
        if (!result)
                result = nfs_direct_wait(dreq);
 out_release:
  * cache.
  */
 ssize_t nfs_file_direct_read(struct kiocb *iocb, const struct iovec *iov,
-                               unsigned long nr_segs, loff_t pos)
+                               unsigned long nr_segs, loff_t pos, bool uio)
 {
        ssize_t retval = -EINVAL;
        struct file *file = iocb->ki_filp;
 
        task_io_account_read(count);
 
-       retval = nfs_direct_read(iocb, iov, nr_segs, pos);
+       retval = nfs_direct_read(iocb, iov, nr_segs, pos, uio);
        if (retval > 0)
                iocb->ki_pos = pos + retval;
 
  * is no atomic O_APPEND write facility in the NFS protocol.
  */
 ssize_t nfs_file_direct_write(struct kiocb *iocb, const struct iovec *iov,
-                               unsigned long nr_segs, loff_t pos)
+                               unsigned long nr_segs, loff_t pos, bool uio)
 {
        ssize_t retval = -EINVAL;
        struct file *file = iocb->ki_filp;
 
        task_io_account_write(count);
 
-       retval = nfs_direct_write(iocb, iov, nr_segs, pos, count);
+       retval = nfs_direct_write(iocb, iov, nr_segs, pos, count, uio);
        if (retval > 0) {
                struct inode *inode = mapping->host;
 
 
        ssize_t result;
 
        if (iocb->ki_filp->f_flags & O_DIRECT)
-               return nfs_file_direct_read(iocb, iov, nr_segs, pos);
+               return nfs_file_direct_read(iocb, iov, nr_segs, pos, true);
 
        dprintk("NFS: read(%s/%s, %lu@%lu)\n",
                dentry->d_parent->d_name.name, dentry->d_name.name,
        return nfs_wb_page(inode, page);
 }
 
+#ifdef CONFIG_NFS_SWAP
+static int nfs_swap_activate(struct swap_info_struct *sis, struct file *file,
+                                               sector_t *span)
+{
+       *span = sis->pages;
+       return xs_swapper(NFS_CLIENT(file->f_mapping->host)->cl_xprt, 1);
+}
+
+static void nfs_swap_deactivate(struct file *file)
+{
+       xs_swapper(NFS_CLIENT(file->f_mapping->host)->cl_xprt, 0);
+}
+#endif
+
 const struct address_space_operations nfs_file_aops = {
        .readpage = nfs_readpage,
        .readpages = nfs_readpages,
        .migratepage = nfs_migrate_page,
        .launder_page = nfs_launder_page,
        .error_remove_page = generic_error_remove_page,
+#ifdef CONFIG_NFS_SWAP
+       .swap_activate = nfs_swap_activate,
+       .swap_deactivate = nfs_swap_deactivate,
+#endif
 };
 
 /*
        size_t count = iov_length(iov, nr_segs);
 
        if (iocb->ki_filp->f_flags & O_DIRECT)
-               return nfs_file_direct_write(iocb, iov, nr_segs, pos);
+               return nfs_file_direct_write(iocb, iov, nr_segs, pos, true);
 
        dprintk("NFS: write(%s/%s, %lu@%Ld)\n",
                dentry->d_parent->d_name.name, dentry->d_name.name,