Commit 24c30470 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'nfs-for-3.1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs

* 'nfs-for-3.1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: (28 commits)
  pnfsblock: write_pagelist handle zero invalid extents
  pnfsblock: note written INVAL areas for layoutcommit
  pnfsblock: bl_write_pagelist
  pnfsblock: bl_read_pagelist
  pnfsblock: cleanup_layoutcommit
  pnfsblock: encode_layoutcommit
  pnfsblock: merge rw extents
  pnfsblock: add extent manipulation functions
  pnfsblock: bl_find_get_extent
  pnfsblock: xdr decode pnfs_block_layout4
  pnfsblock: call and parse getdevicelist
  pnfsblock: merge extents
  pnfsblock: lseg alloc and free
  pnfsblock: remove device operations
  pnfsblock: add device operations
  pnfsblock: basic extent code
  pnfsblock: use pageio_ops api
  pnfsblock: add blocklayout Kconfig option, Makefile, and stubs
  pnfs: cleanup_layoutcommit
  pnfs: ask for layout_blksize and save it in nfs_server
  ...
parents 6581058f 71cdd40f
...@@ -79,15 +79,21 @@ config NFS_V4_1 ...@@ -79,15 +79,21 @@ config NFS_V4_1
depends on NFS_FS && NFS_V4 && EXPERIMENTAL depends on NFS_FS && NFS_V4 && EXPERIMENTAL
select SUNRPC_BACKCHANNEL select SUNRPC_BACKCHANNEL
select PNFS_FILE_LAYOUT select PNFS_FILE_LAYOUT
select PNFS_BLOCK
select MD
select BLK_DEV_DM
help help
This option enables support for minor version 1 of the NFSv4 protocol This option enables support for minor version 1 of the NFSv4 protocol
(RFC 5661) in the kernel's NFS client. (RFC 5661 and RFC 5663) in the kernel's NFS client.
If unsure, say N. If unsure, say N.
config PNFS_FILE_LAYOUT config PNFS_FILE_LAYOUT
tristate tristate
config PNFS_BLOCK
tristate
config PNFS_OBJLAYOUT config PNFS_OBJLAYOUT
tristate "Provide support for the pNFS Objects Layout Driver for NFSv4.1 pNFS (EXPERIMENTAL)" tristate "Provide support for the pNFS Objects Layout Driver for NFSv4.1 pNFS (EXPERIMENTAL)"
depends on NFS_FS && NFS_V4_1 && SCSI_OSD_ULD depends on NFS_FS && NFS_V4_1 && SCSI_OSD_ULD
......
...@@ -23,3 +23,4 @@ obj-$(CONFIG_PNFS_FILE_LAYOUT) += nfs_layout_nfsv41_files.o ...@@ -23,3 +23,4 @@ obj-$(CONFIG_PNFS_FILE_LAYOUT) += nfs_layout_nfsv41_files.o
nfs_layout_nfsv41_files-y := nfs4filelayout.o nfs4filelayoutdev.o nfs_layout_nfsv41_files-y := nfs4filelayout.o nfs4filelayoutdev.o
obj-$(CONFIG_PNFS_OBJLAYOUT) += objlayout/ obj-$(CONFIG_PNFS_OBJLAYOUT) += objlayout/
obj-$(CONFIG_PNFS_BLOCK) += blocklayout/
#
# Makefile for the pNFS block layout driver kernel module
#
obj-$(CONFIG_PNFS_BLOCK) += blocklayoutdriver.o
blocklayoutdriver-objs := blocklayout.o extents.o blocklayoutdev.o blocklayoutdm.o
This diff is collapsed.
/*
* linux/fs/nfs/blocklayout/blocklayout.h
*
* Module for the NFSv4.1 pNFS block layout driver.
*
* Copyright (c) 2006 The Regents of the University of Michigan.
* All rights reserved.
*
* Andy Adamson <andros@citi.umich.edu>
* Fred Isaman <iisaman@umich.edu>
*
* permission is granted to use, copy, create derivative works and
* redistribute this software and such derivative works for any purpose,
* so long as the name of the university of michigan is not used in
* any advertising or publicity pertaining to the use or distribution
* of this software without specific, written prior authorization. if
* the above copyright notice or any other identification of the
* university of michigan is included in any copy of any portion of
* this software, then the disclaimer below must also be included.
*
* this software is provided as is, without representation from the
* university of michigan as to its fitness for any purpose, and without
* warranty by the university of michigan of any kind, either express
* or implied, including without limitation the implied warranties of
* merchantability and fitness for a particular purpose. the regents
* of the university of michigan shall not be liable for any damages,
* including special, indirect, incidental, or consequential damages,
* with respect to any claim arising out or in connection with the use
* of the software, even if it has been or is hereafter advised of the
* possibility of such damages.
*/
#ifndef FS_NFS_NFS4BLOCKLAYOUT_H
#define FS_NFS_NFS4BLOCKLAYOUT_H
#include <linux/device-mapper.h>
#include <linux/nfs_fs.h>
#include <linux/sunrpc/rpc_pipe_fs.h>
#include "../pnfs.h"
#define PAGE_CACHE_SECTORS (PAGE_CACHE_SIZE >> SECTOR_SHIFT)
#define PAGE_CACHE_SECTOR_SHIFT (PAGE_CACHE_SHIFT - SECTOR_SHIFT)
struct block_mount_id {
spinlock_t bm_lock; /* protects list */
struct list_head bm_devlist; /* holds pnfs_block_dev */
};
struct pnfs_block_dev {
struct list_head bm_node;
struct nfs4_deviceid bm_mdevid; /* associated devid */
struct block_device *bm_mdev; /* meta device itself */
};
enum exstate4 {
PNFS_BLOCK_READWRITE_DATA = 0,
PNFS_BLOCK_READ_DATA = 1,
PNFS_BLOCK_INVALID_DATA = 2, /* mapped, but data is invalid */
PNFS_BLOCK_NONE_DATA = 3 /* unmapped, it's a hole */
};
#define MY_MAX_TAGS (15) /* tag bitnums used must be less than this */
struct my_tree {
sector_t mtt_step_size; /* Internal sector alignment */
struct list_head mtt_stub; /* Should be a radix tree */
};
struct pnfs_inval_markings {
spinlock_t im_lock;
struct my_tree im_tree; /* Sectors that need LAYOUTCOMMIT */
sector_t im_block_size; /* Server blocksize in sectors */
};
struct pnfs_inval_tracking {
struct list_head it_link;
int it_sector;
int it_tags;
};
/* sector_t fields are all in 512-byte sectors */
struct pnfs_block_extent {
struct kref be_refcnt;
struct list_head be_node; /* link into lseg list */
struct nfs4_deviceid be_devid; /* FIXME: could use device cache instead */
struct block_device *be_mdev;
sector_t be_f_offset; /* the starting offset in the file */
sector_t be_length; /* the size of the extent */
sector_t be_v_offset; /* the starting offset in the volume */
enum exstate4 be_state; /* the state of this extent */
struct pnfs_inval_markings *be_inval; /* tracks INVAL->RW transition */
};
/* Shortened extent used by LAYOUTCOMMIT */
struct pnfs_block_short_extent {
struct list_head bse_node;
struct nfs4_deviceid bse_devid;
struct block_device *bse_mdev;
sector_t bse_f_offset; /* the starting offset in the file */
sector_t bse_length; /* the size of the extent */
};
static inline void
BL_INIT_INVAL_MARKS(struct pnfs_inval_markings *marks, sector_t blocksize)
{
spin_lock_init(&marks->im_lock);
INIT_LIST_HEAD(&marks->im_tree.mtt_stub);
marks->im_block_size = blocksize;
marks->im_tree.mtt_step_size = min((sector_t)PAGE_CACHE_SECTORS,
blocksize);
}
enum extentclass4 {
RW_EXTENT = 0, /* READWRTE and INVAL */
RO_EXTENT = 1, /* READ and NONE */
EXTENT_LISTS = 2,
};
static inline int bl_choose_list(enum exstate4 state)
{
if (state == PNFS_BLOCK_READ_DATA || state == PNFS_BLOCK_NONE_DATA)
return RO_EXTENT;
else
return RW_EXTENT;
}
struct pnfs_block_layout {
struct pnfs_layout_hdr bl_layout;
struct pnfs_inval_markings bl_inval; /* tracks INVAL->RW transition */
spinlock_t bl_ext_lock; /* Protects list manipulation */
struct list_head bl_extents[EXTENT_LISTS]; /* R and RW extents */
struct list_head bl_commit; /* Needs layout commit */
struct list_head bl_committing; /* Layout committing */
unsigned int bl_count; /* entries in bl_commit */
sector_t bl_blocksize; /* Server blocksize in sectors */
};
#define BLK_ID(lo) ((struct block_mount_id *)(NFS_SERVER(lo->plh_inode)->pnfs_ld_data))
static inline struct pnfs_block_layout *
BLK_LO2EXT(struct pnfs_layout_hdr *lo)
{
return container_of(lo, struct pnfs_block_layout, bl_layout);
}
static inline struct pnfs_block_layout *
BLK_LSEG2EXT(struct pnfs_layout_segment *lseg)
{
return BLK_LO2EXT(lseg->pls_layout);
}
struct bl_dev_msg {
int status;
uint32_t major, minor;
};
struct bl_msg_hdr {
u8 type;
u16 totallen; /* length of entire message, including hdr itself */
};
extern struct dentry *bl_device_pipe;
extern wait_queue_head_t bl_wq;
#define BL_DEVICE_UMOUNT 0x0 /* Umount--delete devices */
#define BL_DEVICE_MOUNT 0x1 /* Mount--create devices*/
#define BL_DEVICE_REQUEST_INIT 0x0 /* Start request */
#define BL_DEVICE_REQUEST_PROC 0x1 /* User level process succeeds */
#define BL_DEVICE_REQUEST_ERR 0x2 /* User level process fails */
/* blocklayoutdev.c */
ssize_t bl_pipe_upcall(struct file *, struct rpc_pipe_msg *,
char __user *, size_t);
ssize_t bl_pipe_downcall(struct file *, const char __user *, size_t);
void bl_pipe_destroy_msg(struct rpc_pipe_msg *);
struct block_device *nfs4_blkdev_get(dev_t dev);
int nfs4_blkdev_put(struct block_device *bdev);
struct pnfs_block_dev *nfs4_blk_decode_device(struct nfs_server *server,
struct pnfs_device *dev);
int nfs4_blk_process_layoutget(struct pnfs_layout_hdr *lo,
struct nfs4_layoutget_res *lgr, gfp_t gfp_flags);
/* blocklayoutdm.c */
void bl_free_block_dev(struct pnfs_block_dev *bdev);
/* extents.c */
struct pnfs_block_extent *
bl_find_get_extent(struct pnfs_block_layout *bl, sector_t isect,
struct pnfs_block_extent **cow_read);
int bl_mark_sectors_init(struct pnfs_inval_markings *marks,
sector_t offset, sector_t length,
sector_t **pages);
void bl_put_extent(struct pnfs_block_extent *be);
struct pnfs_block_extent *bl_alloc_extent(void);
int bl_is_sector_init(struct pnfs_inval_markings *marks, sector_t isect);
int encode_pnfs_block_layoutupdate(struct pnfs_block_layout *bl,
struct xdr_stream *xdr,
const struct nfs4_layoutcommit_args *arg);
void clean_pnfs_block_layoutupdate(struct pnfs_block_layout *bl,
const struct nfs4_layoutcommit_args *arg,
int status);
int bl_add_merge_extent(struct pnfs_block_layout *bl,
struct pnfs_block_extent *new);
int bl_mark_for_commit(struct pnfs_block_extent *be,
sector_t offset, sector_t length);
#endif /* FS_NFS_NFS4BLOCKLAYOUT_H */
This diff is collapsed.
/*
* linux/fs/nfs/blocklayout/blocklayoutdm.c
*
* Module for the NFSv4.1 pNFS block layout driver.
*
* Copyright (c) 2007 The Regents of the University of Michigan.
* All rights reserved.
*
* Fred Isaman <iisaman@umich.edu>
* Andy Adamson <andros@citi.umich.edu>
*
* permission is granted to use, copy, create derivative works and
* redistribute this software and such derivative works for any purpose,
* so long as the name of the university of michigan is not used in
* any advertising or publicity pertaining to the use or distribution
* of this software without specific, written prior authorization. if
* the above copyright notice or any other identification of the
* university of michigan is included in any copy of any portion of
* this software, then the disclaimer below must also be included.
*
* this software is provided as is, without representation from the
* university of michigan as to its fitness for any purpose, and without
* warranty by the university of michigan of any kind, either express
* or implied, including without limitation the implied warranties of
* merchantability and fitness for a particular purpose. the regents
* of the university of michigan shall not be liable for any damages,
* including special, indirect, incidental, or consequential damages,
* with respect to any claim arising out or in connection with the use
* of the software, even if it has been or is hereafter advised of the
* possibility of such damages.
*/
#include <linux/genhd.h> /* gendisk - used in a dprintk*/
#include <linux/sched.h>
#include <linux/hash.h>
#include "blocklayout.h"
#define NFSDBG_FACILITY NFSDBG_PNFS_LD
static void dev_remove(dev_t dev)
{
struct rpc_pipe_msg msg;
struct bl_dev_msg bl_umount_request;
struct bl_msg_hdr bl_msg = {
.type = BL_DEVICE_UMOUNT,
.totallen = sizeof(bl_umount_request),
};
uint8_t *dataptr;
DECLARE_WAITQUEUE(wq, current);
dprintk("Entering %s\n", __func__);
memset(&msg, 0, sizeof(msg));
msg.data = kzalloc(1 + sizeof(bl_umount_request), GFP_NOFS);
if (!msg.data)
goto out;
memset(&bl_umount_request, 0, sizeof(bl_umount_request));
bl_umount_request.major = MAJOR(dev);
bl_umount_request.minor = MINOR(dev);
memcpy(msg.data, &bl_msg, sizeof(bl_msg));
dataptr = (uint8_t *) msg.data;
memcpy(&dataptr[sizeof(bl_msg)], &bl_umount_request, sizeof(bl_umount_request));
msg.len = sizeof(bl_msg) + bl_msg.totallen;
add_wait_queue(&bl_wq, &wq);
if (rpc_queue_upcall(bl_device_pipe->d_inode, &msg) < 0) {
remove_wait_queue(&bl_wq, &wq);
goto out;
}
set_current_state(TASK_UNINTERRUPTIBLE);
schedule();
__set_current_state(TASK_RUNNING);
remove_wait_queue(&bl_wq, &wq);
out:
kfree(msg.data);
}
/*
* Release meta device
*/
static void nfs4_blk_metadev_release(struct pnfs_block_dev *bdev)
{
int rv;
dprintk("%s Releasing\n", __func__);
rv = nfs4_blkdev_put(bdev->bm_mdev);
if (rv)
printk(KERN_ERR "%s nfs4_blkdev_put returns %d\n",
__func__, rv);
dev_remove(bdev->bm_mdev->bd_dev);
}
void bl_free_block_dev(struct pnfs_block_dev *bdev)
{
if (bdev) {
if (bdev->bm_mdev) {
dprintk("%s Removing DM device: %d:%d\n",
__func__,
MAJOR(bdev->bm_mdev->bd_dev),
MINOR(bdev->bm_mdev->bd_dev));
nfs4_blk_metadev_release(bdev);
}
kfree(bdev);
}
}
This diff is collapsed.
...@@ -105,7 +105,7 @@ struct rpc_program nfs_program = { ...@@ -105,7 +105,7 @@ struct rpc_program nfs_program = {
.nrvers = ARRAY_SIZE(nfs_version), .nrvers = ARRAY_SIZE(nfs_version),
.version = nfs_version, .version = nfs_version,
.stats = &nfs_rpcstat, .stats = &nfs_rpcstat,
.pipe_dir_name = "/nfs", .pipe_dir_name = NFS_PIPE_DIRNAME,
}; };
struct rpc_stat nfs_rpcstat = { struct rpc_stat nfs_rpcstat = {
...@@ -904,7 +904,9 @@ static int nfs_init_server(struct nfs_server *server, ...@@ -904,7 +904,9 @@ static int nfs_init_server(struct nfs_server *server,
/* /*
* Load up the server record from information gained in an fsinfo record * Load up the server record from information gained in an fsinfo record
*/ */
static void nfs_server_set_fsinfo(struct nfs_server *server, struct nfs_fsinfo *fsinfo) static void nfs_server_set_fsinfo(struct nfs_server *server,
struct nfs_fh *mntfh,
struct nfs_fsinfo *fsinfo)
{ {
unsigned long max_rpc_payload; unsigned long max_rpc_payload;
...@@ -934,7 +936,8 @@ static void nfs_server_set_fsinfo(struct nfs_server *server, struct nfs_fsinfo * ...@@ -934,7 +936,8 @@ static void nfs_server_set_fsinfo(struct nfs_server *server, struct nfs_fsinfo *
if (server->wsize > NFS_MAX_FILE_IO_SIZE) if (server->wsize > NFS_MAX_FILE_IO_SIZE)
server->wsize = NFS_MAX_FILE_IO_SIZE; server->wsize = NFS_MAX_FILE_IO_SIZE;
server->wpages = (server->wsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; server->wpages = (server->wsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
set_pnfs_layoutdriver(server, fsinfo->layouttype); server->pnfs_blksize = fsinfo->blksize;
set_pnfs_layoutdriver(server, mntfh, fsinfo->layouttype);
server->wtmult = nfs_block_bits(fsinfo->wtmult, NULL); server->wtmult = nfs_block_bits(fsinfo->wtmult, NULL);
...@@ -980,7 +983,7 @@ static int nfs_probe_fsinfo(struct nfs_server *server, struct nfs_fh *mntfh, str ...@@ -980,7 +983,7 @@ static int nfs_probe_fsinfo(struct nfs_server *server, struct nfs_fh *mntfh, str
if (error < 0) if (error < 0)
goto out_error; goto out_error;
nfs_server_set_fsinfo(server, &fsinfo); nfs_server_set_fsinfo(server, mntfh, &fsinfo);
/* Get some general file system info */ /* Get some general file system info */
if (server->namelen == 0) { if (server->namelen == 0) {
......
...@@ -134,18 +134,19 @@ const struct inode_operations nfs4_dir_inode_operations = { ...@@ -134,18 +134,19 @@ const struct inode_operations nfs4_dir_inode_operations = {
#endif /* CONFIG_NFS_V4 */ #endif /* CONFIG_NFS_V4 */
static struct nfs_open_dir_context *alloc_nfs_open_dir_context(struct rpc_cred *cred) static struct nfs_open_dir_context *alloc_nfs_open_dir_context(struct inode *dir, struct rpc_cred *cred)
{ {
struct nfs_open_dir_context *ctx; struct nfs_open_dir_context *ctx;
ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
if (ctx != NULL) { if (ctx != NULL) {
ctx->duped = 0; ctx->duped = 0;
ctx->attr_gencount = NFS_I(dir)->attr_gencount;
ctx->dir_cookie = 0; ctx->dir_cookie = 0;
ctx->dup_cookie = 0; ctx->dup_cookie = 0;
ctx->cred = get_rpccred(cred); ctx->cred = get_rpccred(cred);
} else return ctx;
ctx = ERR_PTR(-ENOMEM); }
return ctx; return ERR_PTR(-ENOMEM);
} }
static void put_nfs_open_dir_context(struct nfs_open_dir_context *ctx) static void put_nfs_open_dir_context(struct nfs_open_dir_context *ctx)
...@@ -173,7 +174,7 @@ nfs_opendir(struct inode *inode, struct file *filp) ...@@ -173,7 +174,7 @@ nfs_opendir(struct inode *inode, struct file *filp)
cred = rpc_lookup_cred(); cred = rpc_lookup_cred();
if (IS_ERR(cred)) if (IS_ERR(cred))
return PTR_ERR(cred); return PTR_ERR(cred);
ctx = alloc_nfs_open_dir_context(cred); ctx = alloc_nfs_open_dir_context(inode, cred);
if (IS_ERR(ctx)) { if (IS_ERR(ctx)) {
res = PTR_ERR(ctx); res = PTR_ERR(ctx);
goto out; goto out;
...@@ -323,7 +324,6 @@ int nfs_readdir_search_for_pos(struct nfs_cache_array *array, nfs_readdir_descri ...@@ -323,7 +324,6 @@ int nfs_readdir_search_for_pos(struct nfs_cache_array *array, nfs_readdir_descri
{ {
loff_t diff = desc->file->f_pos - desc->current_index; loff_t diff = desc->file->f_pos - desc->current_index;
unsigned int index; unsigned int index;
struct nfs_open_dir_context *ctx = desc->file->private_data;
if (diff < 0) if (diff < 0)
goto out_eof; goto out_eof;
...@@ -336,7 +336,6 @@ int nfs_readdir_search_for_pos(struct nfs_cache_array *array, nfs_readdir_descri ...@@ -336,7 +336,6 @@ int nfs_readdir_search_for_pos(struct nfs_cache_array *array, nfs_readdir_descri
index = (unsigned int)diff; index = (unsigned int)diff;
*desc->dir_cookie = array->array[index].cookie; *desc->dir_cookie = array->array[index].cookie;
desc->cache_entry_index = index; desc->cache_entry_index = index;
ctx->duped = 0;
return 0; return 0;
out_eof: out_eof:
desc->eof = 1; desc->eof = 1;
...@@ -349,14 +348,34 @@ int nfs_readdir_search_for_cookie(struct nfs_cache_array *array, nfs_readdir_des ...@@ -349,14 +348,34 @@ int nfs_readdir_search_for_cookie(struct nfs_cache_array *array, nfs_readdir_des
int i; int i;
loff_t new_pos; loff_t new_pos;
int status = -EAGAIN; int status = -EAGAIN;
struct nfs_open_dir_context *ctx = desc->file->private_data;
for (i = 0; i < array->size; i++) { for (i = 0; i < array->size; i++) {
if (array->array[i].cookie == *desc->dir_cookie) { if (array->array[i].cookie == *desc->dir_cookie) {
struct nfs_inode *nfsi = NFS_I(desc->file->f_path.dentry->d_inode);
struct nfs_open_dir_context *ctx = desc->file->private_data;
new_pos = desc->current_index + i; new_pos = desc->current_index + i;
if (new_pos < desc->file->f_pos) { if (ctx->attr_gencount != nfsi->attr_gencount
|| (nfsi->cache_validity & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA))) {
ctx->duped = 0;
ctx->attr_gencount = nfsi->attr_gencount;
} else if (new_pos < desc->file->f_pos) {
if (ctx->duped > 0
&& ctx->dup_cookie == *desc->dir_cookie) {
if (printk_ratelimit()) {
pr_notice("NFS: directory %s/%s contains a readdir loop."
"Please contact your server vendor. "
"The file: %s has duplicate cookie %llu\n",
desc->file->f_dentry->d_parent->d_name.name,
desc->file->f_dentry->d_name.name,
array->array[i].string.name,
*desc->dir_cookie);
}
status = -ELOOP;
goto out;
}
ctx->dup_cookie = *desc->dir_cookie; ctx->dup_cookie = *desc->dir_cookie;
ctx->duped = 1; ctx->duped = -1;
} }
desc->file->f_pos = new_pos; desc->file->f_pos = new_pos;
desc->cache_entry_index = i; desc->cache_entry_index = i;
...@@ -368,6 +387,7 @@ int nfs_readdir_search_for_cookie(struct nfs_cache_array *array, nfs_readdir_des ...@@ -368,6 +387,7 @@ int nfs_readdir_search_for_cookie(struct nfs_cache_array *array, nfs_readdir_des
if (*desc->dir_cookie == array->last_cookie) if (*desc->dir_cookie == array->last_cookie)
desc->eof = 1; desc->eof = 1;
} }
out:
return status; return status;
} }
...@@ -740,19 +760,6 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent, ...@@ -740,19 +760,6 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent,
struct nfs_cache_array *array = NULL; struct nfs_cache_array *array = NULL;
struct nfs_open_dir_context *ctx = file->private_data; struct nfs_open_dir_context *ctx = file->private_data;
if (ctx->duped != 0 && ctx->dup_cookie == *desc->dir_cookie) {
if (printk_ratelimit()) {
pr_notice("NFS: directory %s/%s contains a readdir loop. "
"Please contact your server vendor. "
"Offending cookie: %llu\n",
file->f_dentry->d_parent->d_name.name,
file->f_dentry->d_name.name,
*desc->dir_cookie);
}
res = -ELOOP;
goto out;
}
array = nfs_readdir_get_array(desc->page); array = nfs_readdir_get_array(desc->page);
if (IS_ERR(array)) { if (IS_ERR(array)) {
res = PTR_ERR(array); res = PTR_ERR(array);
...@@ -774,6 +781,8 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent, ...@@ -774,6 +781,8 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent,
*desc->dir_cookie = array->array[i+1].cookie; *desc->dir_cookie = array->array[i+1].cookie;
else else
*desc->dir_cookie = array->last_cookie; *desc->dir_cookie = array->last_cookie;
if (ctx->duped != 0)
ctx->duped = 1;
} }
if (array->eof_index >= 0) if (array->eof_index >= 0)
desc->eof = 1; desc->eof = 1;
...@@ -805,6 +814,7 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent, ...@@ -805,6 +814,7 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent,
struct page *page = NULL; struct page *page = NULL;
int status; int status;
struct inode *inode = desc->file->f_path.dentry->d_inode; struct inode *inode = desc->file->f_path.dentry->d_inode;
struct nfs_open_dir_context *ctx = desc->file->private_data;
dfprintk(DIRCACHE, "NFS: uncached_readdir() searching for cookie %Lu\n", dfprintk(DIRCACHE, "NFS: uncached_readdir() searching for cookie %Lu\n",
(unsigned long long)*desc->dir_cookie); (unsigned long long)*desc->dir_cookie);
...@@ -818,6 +828,7 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent, ...@@ -818,6 +828,7 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent,
desc->page_index = 0; desc->page_index = 0;
desc->last_cookie = *desc->dir_cookie; desc->last_cookie = *desc->dir_cookie;
desc->page = page; desc->page = page;
ctx->duped = 0;
status = nfs_readdir_xdr_to_array(desc, page, inode); status = nfs_readdir_xdr_to_array(desc, page, inode);
if (status < 0) if (status < 0)
......
...@@ -318,7 +318,7 @@ extern const struct nfs4_minor_version_ops *nfs_v4_minor_ops[]; ...@@ -318,7 +318,7 @@ extern const struct nfs4_minor_version_ops *nfs_v4_minor_ops[];
extern const u32 nfs4_fattr_bitmap[2]; extern const u32 nfs4_fattr_bitmap[2];
extern const u32 nfs4_statfs_bitmap[2]; extern const u32 nfs4_statfs_bitmap[2];
extern const u32 nfs4_pathconf_bitmap[2]; extern const u32 nfs4_pathconf_bitmap[2];
extern const u32 nfs4_fsinfo_bitmap[2]; extern const u32 nfs4_fsinfo_bitmap[3];
extern const u32 nfs4_fs_locations_bitmap[2]; extern const u32 nfs4_fs_locations_bitmap[2];
/* nfs4renewd.c */ /* nfs4renewd.c */
......
...@@ -170,7 +170,7 @@ filelayout_set_layoutcommit(struct nfs_write_data *wdata) ...@@ -170,7 +170,7 @@ filelayout_set_layoutcommit(struct nfs_write_data *wdata)
pnfs_set_layoutcommit(wdata); pnfs_set_layoutcommit(wdata);
dprintk("%s ionde %lu pls_end_pos %lu\n", __func__, wdata->inode->i_ino, dprintk("%s ionde %lu pls_end_pos %lu\n", __func__, wdata->inode->i_ino,
(unsigned long) wdata->lseg->pls_end_pos); (unsigned long) NFS_I(wdata->inode)->layout->plh_lwb);
} }
/* /*
......
...@@ -140,12 +140,13 @@ const u32 nfs4_pathconf_bitmap[2] = { ...@@ -140,12 +140,13 @@ const u32 nfs4_pathconf_bitmap[2] = {
0 0
}; };
const u32 nfs4_fsinfo_bitmap[2] = { FATTR4_WORD0_MAXFILESIZE const u32 nfs4_fsinfo_bitmap[3] = { FATTR4_WORD0_MAXFILESIZE
| FATTR4_WORD0_MAXREAD | FATTR4_WORD0_MAXREAD
| FATTR4_WORD0_MAXWRITE | FATTR4_WORD0_MAXWRITE
| FATTR4_WORD0_LEASE_TIME, | FATTR4_WORD0_LEASE_TIME,
FATTR4_WORD1_TIME_DELTA FATTR4_WORD1_TIME_DELTA
| FATTR4_WORD1_FS_LAYOUT_TYPES | FATTR4_WORD1_FS_LAYOUT_TYPES,
FATTR4_WORD2_LAYOUT_BLKSIZE
}; };
const u32 nfs4_fs_locations_bitmap[2] = { const u32 nfs4_fs_locations_bitmap[2] = {
...@@ -5834,6 +5835,54 @@ int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp) ...@@ -5834,6 +5835,54 @@ int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp)
return status; return status;
} }
/*
* Retrieve the list of Data Server devices from the MDS.
*/
static int _nfs4_getdevicelist(struct nfs_server *server,
const struct nfs_fh *fh,
struct pnfs_devicelist *devlist)
{
struct nfs4_getdevicelist_args args = {
.fh = fh,
.layoutclass = server->pnfs_curr_ld->id,
};
struct nfs4_getdevicelist_res res = {
.devlist = devlist,
};
struct rpc_message msg = {
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETDEVICELIST],
.rpc_argp = &args,
.rpc_resp = &res,
};
int status;
dprintk("--> %s\n", __func__);
status = nfs4_call_sync(server->client, server, &msg, &args.seq_args,
&res.seq_res, 0);
dprintk("<-- %s status=%d\n", __func__, status);
return status;
}
int nfs4_proc_getdevicelist(struct nfs_server *server,
const struct nfs_fh *fh,
struct pnfs_devicelist *devlist)
{
struct nfs4_exception exception = { };
int err;
do {
err = nfs4_handle_exception(server,
_nfs4_getdevicelist(server, fh, devlist),
&exception);
} while (exception.retry);
dprintk("%s: err=%d, num_devs=%u\n", __func__,
err, devlist->num_devs);
return err;
}
EXPORT_SYMBOL_GPL(nfs4_proc_getdevicelist);
static int static int
_nfs4_proc_getdeviceinfo(struct nfs_server *server, struct pnfs_device *pdev) _nfs4_proc_getdeviceinfo(struct nfs_server *server, struct pnfs_device *pdev)
{ {
...@@ -5912,9 +5961,16 @@ nfs4_layoutcommit_done(struct rpc_task *task, void *calldata) ...@@ -5912,9 +5961,16 @@ nfs4_layoutcommit_done(struct rpc_task *task, void *calldata)
static void nfs4_layoutcommit_release(void *calldata) static void nfs4_layoutcommit_release(void *calldata)
{ {
struct nfs4_layoutcommit_data *data = calldata; struct nfs4_layoutcommit_data *data = calldata;
struct pnfs_layout_segment *lseg, *tmp;
pnfs_cleanup_layoutcommit(data);
/* Matched by references in pnfs_set_layoutcommit */ /* Matched by references in pnfs_set_layoutcommit */
put_lseg(data->lseg); list_for_each_entry_safe(lseg, tmp, &data->lseg_list, pls_lc_list) {
list_del_init(&lseg->pls_lc_list);
if (test_and_clear_bit(NFS_LSEG_LAYOUTCOMMIT,
&lseg->pls_flags))
put_lseg(lseg);
}
put_rpccred(data->cred); put_rpccred(data->cred);
kfree(data); kfree(data);
} }
......
This diff is collapsed.
...@@ -76,8 +76,11 @@ find_pnfs_driver(u32 id) ...@@ -76,8 +76,11 @@ find_pnfs_driver(u32 id)
void void
unset_pnfs_layoutdriver(struct nfs_server *nfss) unset_pnfs_layoutdriver(struct nfs_server *nfss)
{ {
if (nfss->pnfs_curr_ld) if (nfss->pnfs_curr_ld) {
if (nfss->pnfs_curr_ld->clear_layoutdriver)
nfss->pnfs_curr_ld->clear_layoutdriver(nfss);
module_put(nfss->pnfs_curr_ld->owner); module_put(nfss->pnfs_curr_ld->owner);
}
nfss->pnfs_curr_ld = NULL; nfss->pnfs_curr_ld = NULL;
} }
...@@ -88,7 +91,8 @@ unset_pnfs_layoutdriver(struct nfs_server *nfss) ...@@ -88,7 +91,8 @@ unset_pnfs_layoutdriver(struct nfs_server *nfss)
* @id layout type. Zero (illegal layout type) indicates pNFS not in use. * @id layout type. Zero (illegal layout type) indicates pNFS not in use.
*/ */
void void
set_pnfs_layoutdriver(struct nfs_server *server, u32 id) set_pnfs_layoutdriver(struct nfs_server *server, const struct nfs_fh *mntfh,
u32 id)
{ {
struct pnfs_layoutdriver_type *ld_type = NULL; struct pnfs_layoutdriver_type *ld_type = NULL;
...@@ -115,6 +119,13 @@ set_pnfs_layoutdriver(struct nfs_server *server, u32 id) ...@@ -115,6 +119,13 @@ set_pnfs_layoutdriver(struct nfs_server *server, u32 id)
goto out_no_driver; goto out_no_driver;
} }
server->pnfs_curr_ld = ld_type; server->pnfs_curr_ld = ld_type;
if (ld_type->set_layoutdriver
&& ld_type->set_layoutdriver(server, mntfh)) {
printk(KERN_ERR "%s: Error initializing pNFS layout driver %u.\n",
__func__, id);
module_put(ld_type->owner);
goto out_no_driver;
}
dprintk("%s: pNFS module for %u set\n", __func__, id); dprintk("%s: pNFS module for %u set\n", __func__, id);
return; return;
...@@ -190,6 +201,7 @@ static void ...@@ -190,6 +201,7 @@ static void
pnfs_free_layout_hdr(struct pnfs_layout_hdr *lo) pnfs_free_layout_hdr(struct pnfs_layout_hdr *lo)
{ {
struct pnfs_layoutdriver_type *ld = NFS_SERVER(lo->plh_inode)->pnfs_curr_ld; struct pnfs_layoutdriver_type *ld = NFS_SERVER(lo->plh_inode)->pnfs_curr_ld;
put_rpccred(lo->plh_lc_cred);
return ld->alloc_layout_hdr ? ld->free_layout_hdr(lo) : kfree(lo); return ld->alloc_layout_hdr ? ld->free_layout_hdr(lo) : kfree(lo);
} }
...@@ -224,6 +236,7 @@ static void ...@@ -224,6 +236,7 @@ static void
init_lseg(struct pnfs_layout_hdr *lo, struct pnfs_layout_segment *lseg) init_lseg(struct pnfs_layout_hdr *lo, struct pnfs_layout_segment *lseg)
{ {
INIT_LIST_HEAD(&lseg->pls_list); INIT_LIST_HEAD(&lseg->pls_list);
INIT_LIST_HEAD(&lseg->pls_lc_list);
atomic_set(&lseg->pls_refcount, 1); atomic_set(&lseg->pls_refcount, 1);
smp_mb(); smp_mb();
set_bit(NFS_LSEG_VALID, &lseg->pls_flags); set_bit(NFS_LSEG_VALID, &lseg->pls_flags);
...@@ -816,7 +829,9 @@ pnfs_insert_layout(struct pnfs_layout_hdr *lo, ...@@ -816,7 +829,9 @@ pnfs_insert_layout(struct pnfs_layout_hdr *lo,
} }
static struct pnfs_layout_hdr * static struct pnfs_layout_hdr *
alloc_init_layout_hdr(struct inode *ino, gfp_t gfp_flags) alloc_init_layout_hdr(struct inode *ino,
struct nfs_open_context *ctx,
gfp_t gfp_flags)
{ {
struct pnfs_layout_hdr *lo; struct pnfs_layout_hdr *lo;
...@@ -828,11 +843,14 @@ alloc_init_layout_hdr(struct inode *ino, gfp_t gfp_flags) ...@@ -828,11 +843,14 @@ alloc_init_layout_hdr(struct inode *ino, gfp_t gfp_flags)
INIT_LIST_HEAD(&lo->plh_segs); INIT_LIST_HEAD(&lo->plh_segs);
INIT_LIST_HEAD(&lo->plh_bulk_recall); INIT_LIST_HEAD(&lo->plh_bulk_recall);
lo->plh_inode = ino; lo->plh_inode = ino;
lo->plh_lc_cred = get_rpccred(ctx->state->owner->so_cred);
return lo; return lo;
} }
static struct pnfs_layout_hdr * static struct pnfs_layout_hdr *
pnfs_find_alloc_layout(struct inode *ino, gfp_t gfp_flags) pnfs_find_alloc_layout(struct inode *ino,
struct nfs_open_context *ctx,
gfp_t gfp_flags)
{ {
struct nfs_inode *nfsi = NFS_I(ino); struct nfs_inode *nfsi = NFS_I(ino);
struct pnfs_layout_hdr *new = NULL; struct pnfs_layout_hdr *new = NULL;
...@@ -847,7 +865,7 @@ pnfs_find_alloc_layout(struct inode *ino, gfp_t gfp_flags) ...@@ -847,7 +865,7 @@ pnfs_find_alloc_layout(struct inode *ino, gfp_t gfp_flags)
return nfsi->layout; return nfsi->layout;
} }
spin_unlock(&ino->i_lock); spin_unlock(&ino->i_lock);
new = alloc_init_layout_hdr(ino, gfp_flags); new = alloc_init_layout_hdr(ino, ctx, gfp_flags);
spin_lock(&ino->i_lock); spin_lock(&ino->i_lock);
if (likely(nfsi->layout == NULL)) /* Won the race? */ if (likely(nfsi->layout == NULL)) /* Won the race? */
...@@ -940,7 +958,7 @@ pnfs_update_layout(struct inode *ino, ...@@ -940,7 +958,7 @@ pnfs_update_layout(struct inode *ino,
if (!pnfs_enabled_sb(NFS_SERVER(ino))) if (!pnfs_enabled_sb(NFS_SERVER(ino)))
return NULL; return NULL;
spin_lock(&ino->i_lock); spin_lock(&ino->i_lock);
lo = pnfs_find_alloc_layout(ino, gfp_flags); lo = pnfs_find_alloc_layout(ino, ctx, gfp_flags);
if (lo == NULL) { if (lo == NULL) {
dprintk("%s ERROR: can't get pnfs_layout_hdr\n", __func__); dprintk("%s ERROR: can't get pnfs_layout_hdr\n", __func__);
goto out_unlock; goto out_unlock;
...@@ -1350,16 +1368,17 @@ pnfs_generic_pg_readpages(struct nfs_pageio_descriptor *desc) ...@@ -1350,16 +1368,17 @@ pnfs_generic_pg_readpages(struct nfs_pageio_descriptor *desc)
EXPORT_SYMBOL_GPL(pnfs_generic_pg_readpages); EXPORT_SYMBOL_GPL(pnfs_generic_pg_readpages);
/* /*
* Currently there is only one (whole file) write lseg. * There can be multiple RW segments.
*/ */
static struct pnfs_layout_segment *pnfs_list_write_lseg(struct inode *inode) static void pnfs_list_write_lseg(struct inode *inode, struct list_head *listp)
{ {
struct pnfs_layout_segment *lseg, *rv = NULL; struct pnfs_layout_segment *lseg;
list_for_each_entry(lseg, &NFS_I(inode)->layout->plh_segs, pls_list) list_for_each_entry(lseg, &NFS_I(inode)->layout->plh_segs, pls_list) {
if (lseg->pls_range.iomode == IOMODE_RW) if (lseg->pls_range.iomode == IOMODE_RW &&
rv = lseg; test_bit(NFS_LSEG_LAYOUTCOMMIT, &lseg->pls_flags))
return rv; list_add(&lseg->pls_lc_list, listp);
}
} }
void void
...@@ -1371,17 +1390,19 @@ pnfs_set_layoutcommit(struct nfs_write_data *wdata) ...@@ -1371,17 +1390,19 @@ pnfs_set_layoutcommit(struct nfs_write_data *wdata)
spin_lock(&nfsi->vfs_inode.i_lock); spin_lock(&nfsi->vfs_inode.i_lock);
if (!test_and_set_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)) { if (!test_and_set_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)) {
/* references matched in nfs4_layoutcommit_release */
get_lseg(wdata->lseg);
wdata->lseg->pls_lc_cred =
get_rpccred(wdata->args.context->state->owner->so_cred);
mark_as_dirty = true; mark_as_dirty = true;
dprintk("%s: Set layoutcommit for inode %lu ", dprintk("%s: Set layoutcommit for inode %lu ",
__func__, wdata->inode->i_ino); __func__, wdata->inode->i_ino);
} }
if (end_pos > wdata->lseg->pls_end_pos) if (!test_and_set_bit(NFS_LSEG_LAYOUTCOMMIT, &wdata->lseg->pls_flags)) {
wdata->lseg->pls_end_pos = end_pos; /* references matched in nfs4_layoutcommit_release */
get_lseg(wdata->lseg);
}
if (end_pos > nfsi->layout->plh_lwb)
nfsi->layout->plh_lwb = end_pos;
spin_unlock(&nfsi->vfs_inode.i_lock); spin_unlock(&nfsi->vfs_inode.i_lock);
dprintk("%s: lseg %p end_pos %llu\n",
__func__, wdata->lseg, nfsi->layout->plh_lwb);
/* if pnfs_layoutcommit_inode() runs between inode locks, the next one /* if pnfs_layoutcommit_inode() runs between inode locks, the next one
* will be a noop because NFS_INO_LAYOUTCOMMIT will not be set */ * will be a noop because NFS_INO_LAYOUTCOMMIT will not be set */
...@@ -1390,6 +1411,14 @@ pnfs_set_layoutcommit(struct nfs_write_data *wdata) ...@@ -1390,6 +1411,14 @@ pnfs_set_layoutcommit(struct nfs_write_data *wdata)
} }
EXPORT_SYMBOL_GPL(pnfs_set_layoutcommit); EXPORT_SYMBOL_GPL(pnfs_set_layoutcommit);
void pnfs_cleanup_layoutcommit(struct nfs4_layoutcommit_data *data)
{
struct nfs_server *nfss = NFS_SERVER(data->args.inode);
if (nfss->pnfs_curr_ld->cleanup_layoutcommit)
nfss->pnfs_curr_ld->cleanup_layoutcommit(data);
}
/* /*
* For the LAYOUT4_NFSV4_1_FILES layout type, NFS_DATA_SYNC WRITEs and * For the LAYOUT4_NFSV4_1_FILES layout type, NFS_DATA_SYNC WRITEs and
* NFS_UNSTABLE WRITEs with a COMMIT to data servers must store enough * NFS_UNSTABLE WRITEs with a COMMIT to data servers must store enough
...@@ -1403,8 +1432,6 @@ pnfs_layoutcommit_inode(struct inode *inode, bool sync) ...@@ -1403,8 +1432,6 @@ pnfs_layoutcommit_inode(struct inode *inode, bool sync)
{ {
struct nfs4_layoutcommit_data *data; struct nfs4_layoutcommit_data *data;
struct nfs_inode *nfsi = NFS_I(inode); struct nfs_inode *nfsi = NFS_I(inode);
struct pnfs_layout_segment *lseg;
struct rpc_cred *cred;
loff_t end_pos; loff_t end_pos;
int status = 0; int status = 0;
...@@ -1421,30 +1448,25 @@ pnfs_layoutcommit_inode(struct inode *inode, bool sync) ...@@ -1421,30 +1448,25 @@ pnfs_layoutcommit_inode(struct inode *inode, bool sync)
goto out; goto out;
} }
INIT_LIST_HEAD(&data->lseg_list);
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
if (!test_and_clear_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)) { if (!test_and_clear_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)) {
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
kfree(data); kfree(data);
goto out; goto out;
} }
/*
* Currently only one (whole file) write lseg which is referenced
* in pnfs_set_layoutcommit and will be found.
*/
lseg = pnfs_list_write_lseg(inode);
end_pos = lseg->pls_end_pos; pnfs_list_write_lseg(inode, &data->lseg_list);
cred = lseg->pls_lc_cred;
lseg->pls_end_pos = 0; end_pos = nfsi->layout->plh_lwb;
lseg->pls_lc_cred = NULL; nfsi->layout->plh_lwb = 0;
memcpy(&data->args.stateid.data, nfsi->layout->plh_stateid.data, memcpy(&data->args.stateid.data, nfsi->layout->plh_stateid.data,
sizeof(nfsi->layout->plh_stateid.data)); sizeof(nfsi->layout->plh_stateid.data));
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
data->args.inode = inode; data->args.inode = inode;
data->lseg = lseg; data->cred = get_rpccred(nfsi->layout->plh_lc_cred);
data->cred = cred;
nfs_fattr_init(&data->fattr); nfs_fattr_init(&data->fattr);
data->args.bitmask = NFS_SERVER(inode)->cache_consistency_bitmask; data->args.bitmask = NFS_SERVER(inode)->cache_consistency_bitmask;
data->res.fattr = &data->fattr; data->res.fattr = &data->fattr;
......
...@@ -36,16 +36,16 @@ ...@@ -36,16 +36,16 @@
enum { enum {
NFS_LSEG_VALID = 0, /* cleared when lseg is recalled/returned */ NFS_LSEG_VALID = 0, /* cleared when lseg is recalled/returned */
NFS_LSEG_ROC, /* roc bit received from server */ NFS_LSEG_ROC, /* roc bit received from server */
NFS_LSEG_LAYOUTCOMMIT, /* layoutcommit bit set for layoutcommit */
}; };
struct pnfs_layout_segment { struct pnfs_layout_segment {
struct list_head pls_list; struct list_head pls_list;
struct list_head pls_lc_list;
struct pnfs_layout_range pls_range; struct pnfs_layout_range pls_range;
atomic_t pls_refcount; atomic_t pls_refcount;
unsigned long pls_flags; unsigned long pls_flags;
struct pnfs_layout_hdr *pls_layout; struct pnfs_layout_hdr *pls_layout;
struct rpc_cred *pls_lc_cred; /* LAYOUTCOMMIT credential */
loff_t pls_end_pos; /* LAYOUTCOMMIT write end */
}; };
enum pnfs_try_status { enum pnfs_try_status {
...@@ -80,6 +80,9 @@ struct pnfs_layoutdriver_type { ...@@ -80,6 +80,9 @@ struct pnfs_layoutdriver_type {
struct module *owner; struct module *owner;
unsigned flags; unsigned flags;
int (*set_layoutdriver) (struct nfs_server *, const struct nfs_fh *);
int (*clear_layoutdriver) (struct nfs_server *);
struct pnfs_layout_hdr * (*alloc_layout_hdr) (struct inode *inode, gfp_t gfp_flags); struct pnfs_layout_hdr * (*alloc_layout_hdr) (struct inode *inode, gfp_t gfp_flags);
void (*free_layout_hdr) (struct pnfs_layout_hdr *); void (*free_layout_hdr) (struct pnfs_layout_hdr *);
...@@ -110,6 +113,8 @@ struct pnfs_layoutdriver_type { ...@@ -110,6 +113,8 @@ struct pnfs_layoutdriver_type {
struct xdr_stream *xdr, struct xdr_stream *xdr,
const struct nfs4_layoutreturn_args *args); const struct nfs4_layoutreturn_args *args);
void (*cleanup_layoutcommit) (struct nfs4_layoutcommit_data *data);
void (*encode_layoutcommit) (struct pnfs_layout_hdr *layoutid, void (*encode_layoutcommit) (struct pnfs_layout_hdr *layoutid,
struct xdr_stream *xdr, struct xdr_stream *xdr,
const struct nfs4_layoutcommit_args *args); const struct nfs4_layoutcommit_args *args);
...@@ -125,6 +130,8 @@ struct pnfs_layout_hdr { ...@@ -125,6 +130,8 @@ struct pnfs_layout_hdr {
unsigned long plh_block_lgets; /* block LAYOUTGET if >0 */ unsigned long plh_block_lgets; /* block LAYOUTGET if >0 */
u32 plh_barrier; /* ignore lower seqids */ u32 plh_barrier; /* ignore lower seqids */
unsigned long plh_flags; unsigned long plh_flags;
loff_t plh_lwb; /* last write byte for layoutcommit */
struct rpc_cred *plh_lc_cred; /* layoutcommit cred */
struct inode *plh_inode; struct inode *plh_inode;
}; };
...@@ -137,10 +144,21 @@ struct pnfs_device { ...@@ -137,10 +144,21 @@ struct pnfs_device {
unsigned int pglen; unsigned int pglen;
}; };
#define NFS4_PNFS_GETDEVLIST_MAXNUM 16
struct pnfs_devicelist {
unsigned int eof;
unsigned int num_devs;
struct nfs4_deviceid dev_id[NFS4_PNFS_GETDEVLIST_MAXNUM];
};
extern int pnfs_register_layoutdriver(struct pnfs_layoutdriver_type *); extern int pnfs_register_layoutdriver(struct pnfs_layoutdriver_type *);
extern void pnfs_unregister_layoutdriver(struct pnfs_layoutdriver_type *); extern void pnfs_unregister_layoutdriver(struct pnfs_layoutdriver_type *);
/* nfs4proc.c */ /* nfs4proc.c */
extern int nfs4_proc_getdevicelist(struct nfs_server *server,
const struct nfs_fh *fh,
struct pnfs_devicelist *devlist);
extern int nfs4_proc_getdeviceinfo(struct nfs_server *server, extern int nfs4_proc_getdeviceinfo(struct nfs_server *server,
struct pnfs_device *dev); struct pnfs_device *dev);
extern int nfs4_proc_layoutget(struct nfs4_layoutget *lgp); extern int nfs4_proc_layoutget(struct nfs4_layoutget *lgp);
...@@ -153,7 +171,7 @@ void put_lseg(struct pnfs_layout_segment *lseg); ...@@ -153,7 +171,7 @@ void put_lseg(struct pnfs_layout_segment *lseg);
bool pnfs_pageio_init_read(struct nfs_pageio_descriptor *, struct inode *); bool pnfs_pageio_init_read(struct nfs_pageio_descriptor *, struct inode *);
bool pnfs_pageio_init_write(struct nfs_pageio_descriptor *, struct inode *, int); bool pnfs_pageio_init_write(struct nfs_pageio_descriptor *, struct inode *, int);
void set_pnfs_layoutdriver(struct nfs_server *, u32 id); void set_pnfs_layoutdriver(struct nfs_server *, const struct nfs_fh *, u32);
void unset_pnfs_layoutdriver(struct nfs_server *); void unset_pnfs_layoutdriver(struct nfs_server *);
void pnfs_generic_pg_init_read(struct nfs_pageio_descriptor *, struct nfs_page *); void pnfs_generic_pg_init_read(struct nfs_pageio_descriptor *, struct nfs_page *);
int pnfs_generic_pg_readpages(struct nfs_pageio_descriptor *desc); int pnfs_generic_pg_readpages(struct nfs_pageio_descriptor *desc);
...@@ -179,6 +197,7 @@ void pnfs_roc_release(struct inode *ino); ...@@ -179,6 +197,7 @@ void pnfs_roc_release(struct inode *ino);
void pnfs_roc_set_barrier(struct inode *ino, u32 barrier); void pnfs_roc_set_barrier(struct inode *ino, u32 barrier);
bool pnfs_roc_drain(struct inode *ino, u32 *barrier); bool pnfs_roc_drain(struct inode *ino, u32 *barrier);
void pnfs_set_layoutcommit(struct nfs_write_data *wdata); void pnfs_set_layoutcommit(struct nfs_write_data *wdata);
void pnfs_cleanup_layoutcommit(struct nfs4_layoutcommit_data *data);
int pnfs_layoutcommit_inode(struct inode *inode, bool sync); int pnfs_layoutcommit_inode(struct inode *inode, bool sync);
int _pnfs_return_layout(struct inode *); int _pnfs_return_layout(struct inode *);
int pnfs_ld_write_done(struct nfs_write_data *); int pnfs_ld_write_done(struct nfs_write_data *);
...@@ -360,7 +379,8 @@ pnfs_roc_drain(struct inode *ino, u32 *barrier) ...@@ -360,7 +379,8 @@ pnfs_roc_drain(struct inode *ino, u32 *barrier)
return false; return false;
} }
static inline void set_pnfs_layoutdriver(struct nfs_server *s, u32 id) static inline void set_pnfs_layoutdriver(struct nfs_server *s,
const struct nfs_fh *mntfh, u32 id);
{ {
} }
......
...@@ -29,6 +29,8 @@ ...@@ -29,6 +29,8 @@
#define NFS_MNT_VERSION 1 #define NFS_MNT_VERSION 1
#define NFS_MNT3_VERSION 3 #define NFS_MNT3_VERSION 3
#define NFS_PIPE_DIRNAME "/nfs"
/* /*
* NFS stats. The good thing with these values is that NFSv3 errors are * NFS stats. The good thing with these values is that NFSv3 errors are
* a superset of NFSv2 errors (with the exception of NFSERR_WFLUSH which * a superset of NFSv2 errors (with the exception of NFSERR_WFLUSH which
......
...@@ -566,6 +566,7 @@ enum { ...@@ -566,6 +566,7 @@ enum {
NFSPROC4_CLNT_SECINFO_NO_NAME, NFSPROC4_CLNT_SECINFO_NO_NAME,
NFSPROC4_CLNT_TEST_STATEID, NFSPROC4_CLNT_TEST_STATEID,
NFSPROC4_CLNT_FREE_STATEID, NFSPROC4_CLNT_FREE_STATEID,
NFSPROC4_CLNT_GETDEVICELIST,
}; };
/* nfs41 types */ /* nfs41 types */
......
...@@ -99,9 +99,10 @@ struct nfs_open_context { ...@@ -99,9 +99,10 @@ struct nfs_open_context {
struct nfs_open_dir_context { struct nfs_open_dir_context {
struct rpc_cred *cred; struct rpc_cred *cred;
unsigned long attr_gencount;
__u64 dir_cookie; __u64 dir_cookie;
__u64 dup_cookie; __u64 dup_cookie;
int duped; signed char duped;
}; };
/* /*
......
...@@ -132,7 +132,7 @@ struct nfs_server { ...@@ -132,7 +132,7 @@ struct nfs_server {
#endif #endif
#ifdef CONFIG_NFS_V4 #ifdef CONFIG_NFS_V4
u32 attr_bitmask[2];/* V4 bitmask representing the set u32 attr_bitmask[3];/* V4 bitmask representing the set
of attributes supported on this of attributes supported on this
filesystem */ filesystem */
u32 cache_consistency_bitmask[2]; u32 cache_consistency_bitmask[2];
...@@ -145,6 +145,8 @@ struct nfs_server { ...@@ -145,6 +145,8 @@ struct nfs_server {
filesystem */ filesystem */
struct pnfs_layoutdriver_type *pnfs_curr_ld; /* Active layout driver */ struct pnfs_layoutdriver_type *pnfs_curr_ld; /* Active layout driver */
struct rpc_wait_queue roc_rpcwaitq; struct rpc_wait_queue roc_rpcwaitq;
u32 pnfs_blksize; /* layout_blksize attr */
void *pnfs_ld_data; /* per mount point data */
/* the following fields are protected by nfs_client->cl_lock */ /* the following fields are protected by nfs_client->cl_lock */
struct rb_root state_owners; struct rb_root state_owners;
......
...@@ -122,6 +122,7 @@ struct nfs_fsinfo { ...@@ -122,6 +122,7 @@ struct nfs_fsinfo {
struct timespec time_delta; /* server time granularity */ struct timespec time_delta; /* server time granularity */
__u32 lease_time; /* in seconds */ __u32 lease_time; /* in seconds */
__u32 layouttype; /* supported pnfs layout driver */ __u32 layouttype; /* supported pnfs layout driver */
__u32 blksize; /* preferred pnfs io block size */
}; };
struct nfs_fsstat { struct nfs_fsstat {
...@@ -235,6 +236,17 @@ struct nfs4_layoutget { ...@@ -235,6 +236,17 @@ struct nfs4_layoutget {
gfp_t gfp_flags; gfp_t gfp_flags;
}; };
struct nfs4_getdevicelist_args {
const struct nfs_fh *fh;
u32 layoutclass;
struct nfs4_sequence_args seq_args;
};
struct nfs4_getdevicelist_res {
struct pnfs_devicelist *devlist;
struct nfs4_sequence_res seq_res;
};
struct nfs4_getdeviceinfo_args { struct nfs4_getdeviceinfo_args {
struct pnfs_device *pdev; struct pnfs_device *pdev;
struct nfs4_sequence_args seq_args; struct nfs4_sequence_args seq_args;
...@@ -257,12 +269,13 @@ struct nfs4_layoutcommit_res { ...@@ -257,12 +269,13 @@ struct nfs4_layoutcommit_res {
struct nfs_fattr *fattr; struct nfs_fattr *fattr;
const struct nfs_server *server; const struct nfs_server *server;
struct nfs4_sequence_res seq_res; struct nfs4_sequence_res seq_res;
int status;
}; };
struct nfs4_layoutcommit_data { struct nfs4_layoutcommit_data {
struct rpc_task task; struct rpc_task task;
struct nfs_fattr fattr; struct nfs_fattr fattr;
struct pnfs_layout_segment *lseg; struct list_head lseg_list;
struct rpc_cred *cred; struct rpc_cred *cred;
struct nfs4_layoutcommit_args args; struct nfs4_layoutcommit_args args;
struct nfs4_layoutcommit_res res; struct nfs4_layoutcommit_res res;
...@@ -943,7 +956,7 @@ struct nfs4_server_caps_arg { ...@@ -943,7 +956,7 @@ struct nfs4_server_caps_arg {
}; };
struct nfs4_server_caps_res { struct nfs4_server_caps_res {
u32 attr_bitmask[2]; u32 attr_bitmask[3];
u32 acl_bitmask; u32 acl_bitmask;
u32 has_links; u32 has_links;
u32 has_symlinks; u32 has_symlinks;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment