You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge tag 'nfs-for-3.18-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
Pull NFS client updates from Trond Myklebust:
"Highlights include:
Stable fixes:
- fix an NFSv4.1 state renewal regression
- fix open/lock state recovery error handling
- fix lock recovery when CREATE_SESSION/SETCLIENTID_CONFIRM fails
- fix statd when reconnection fails
- don't wake tasks during connection abort
- don't start reboot recovery if lease check fails
- fix duplicate proc entries
Features:
- pNFS block driver fixes and clean ups from Christoph
- More code cleanups from Anna
- Improve mmap() writeback performance
- Replace use of PF_TRANS with a more generic mechanism for avoiding
deadlocks in nfs_release_page"
* tag 'nfs-for-3.18-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: (66 commits)
NFSv4.1: Fix an NFSv4.1 state renewal regression
NFSv4: fix open/lock state recovery error handling
NFSv4: Fix lock recovery when CREATE_SESSION/SETCLIENTID_CONFIRM fails
NFS: Fabricate fscache server index key correctly
SUNRPC: Add missing support for RPC_CLNT_CREATE_NO_RETRANS_TIMEOUT
NFSv3: Fix missing includes of nfs3_fs.h
NFS/SUNRPC: Remove other deadlock-avoidance mechanisms in nfs_release_page()
NFS: avoid waiting at all in nfs_release_page when congested.
NFS: avoid deadlocks with loop-back mounted NFS filesystems.
MM: export page_wakeup functions
SCHED: add some "wait..on_bit...timeout()" interfaces.
NFS: don't use STABLE writes during writeback.
NFSv4: use exponential retry on NFS4ERR_DELAY for async requests.
rpc: Add -EPERM processing for xs_udp_send_request()
rpc: return sent and err from xs_sendpages()
lockd: Try to reconnect if statd has moved
SUNRPC: Don't wake tasks during connection abort
Fixing lease renewal
nfs: fix duplicate proc entries
pnfs/blocklayout: Fix a 64-bit division/remainder issue in bl_map_stripe
...
This commit is contained in:
@@ -159,6 +159,12 @@ static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res,
|
|||||||
|
|
||||||
msg.rpc_proc = &clnt->cl_procinfo[proc];
|
msg.rpc_proc = &clnt->cl_procinfo[proc];
|
||||||
status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFTCONN);
|
status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFTCONN);
|
||||||
|
if (status == -ECONNREFUSED) {
|
||||||
|
dprintk("lockd: NSM upcall RPC failed, status=%d, forcing rebind\n",
|
||||||
|
status);
|
||||||
|
rpc_force_rebind(clnt);
|
||||||
|
status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFTCONN);
|
||||||
|
}
|
||||||
if (status < 0)
|
if (status < 0)
|
||||||
dprintk("lockd: NSM upcall RPC failed, status=%d\n",
|
dprintk("lockd: NSM upcall RPC failed, status=%d\n",
|
||||||
status);
|
status);
|
||||||
|
|||||||
@@ -2,4 +2,5 @@
|
|||||||
# Makefile for the pNFS block layout driver kernel module
|
# Makefile for the pNFS block layout driver kernel module
|
||||||
#
|
#
|
||||||
obj-$(CONFIG_PNFS_BLOCK) += blocklayoutdriver.o
|
obj-$(CONFIG_PNFS_BLOCK) += blocklayoutdriver.o
|
||||||
blocklayoutdriver-objs := blocklayout.o extents.o blocklayoutdev.o blocklayoutdm.o
|
|
||||||
|
blocklayoutdriver-y += blocklayout.o dev.o extent_tree.o rpc_pipefs.o
|
||||||
|
|||||||
+438
-970
File diff suppressed because it is too large
Load Diff
+101
-108
@@ -44,16 +44,77 @@
|
|||||||
#define PAGE_CACHE_SECTOR_SHIFT (PAGE_CACHE_SHIFT - SECTOR_SHIFT)
|
#define PAGE_CACHE_SECTOR_SHIFT (PAGE_CACHE_SHIFT - SECTOR_SHIFT)
|
||||||
#define SECTOR_SIZE (1 << SECTOR_SHIFT)
|
#define SECTOR_SIZE (1 << SECTOR_SHIFT)
|
||||||
|
|
||||||
struct block_mount_id {
|
struct pnfs_block_dev;
|
||||||
spinlock_t bm_lock; /* protects list */
|
|
||||||
struct list_head bm_devlist; /* holds pnfs_block_dev */
|
enum pnfs_block_volume_type {
|
||||||
|
PNFS_BLOCK_VOLUME_SIMPLE = 0,
|
||||||
|
PNFS_BLOCK_VOLUME_SLICE = 1,
|
||||||
|
PNFS_BLOCK_VOLUME_CONCAT = 2,
|
||||||
|
PNFS_BLOCK_VOLUME_STRIPE = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define PNFS_BLOCK_MAX_UUIDS 4
|
||||||
|
#define PNFS_BLOCK_MAX_DEVICES 64
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Random upper cap for the uuid length to avoid unbounded allocation.
|
||||||
|
* Not actually limited by the protocol.
|
||||||
|
*/
|
||||||
|
#define PNFS_BLOCK_UUID_LEN 128
|
||||||
|
|
||||||
|
|
||||||
|
struct pnfs_block_volume {
|
||||||
|
enum pnfs_block_volume_type type;
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
int len;
|
||||||
|
int nr_sigs;
|
||||||
|
struct {
|
||||||
|
u64 offset;
|
||||||
|
u32 sig_len;
|
||||||
|
u8 sig[PNFS_BLOCK_UUID_LEN];
|
||||||
|
} sigs[PNFS_BLOCK_MAX_UUIDS];
|
||||||
|
} simple;
|
||||||
|
struct {
|
||||||
|
u64 start;
|
||||||
|
u64 len;
|
||||||
|
u32 volume;
|
||||||
|
} slice;
|
||||||
|
struct {
|
||||||
|
u32 volumes_count;
|
||||||
|
u32 volumes[PNFS_BLOCK_MAX_DEVICES];
|
||||||
|
} concat;
|
||||||
|
struct {
|
||||||
|
u64 chunk_size;
|
||||||
|
u32 volumes_count;
|
||||||
|
u32 volumes[PNFS_BLOCK_MAX_DEVICES];
|
||||||
|
} stripe;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct pnfs_block_dev_map {
|
||||||
|
sector_t start;
|
||||||
|
sector_t len;
|
||||||
|
|
||||||
|
sector_t disk_offset;
|
||||||
|
struct block_device *bdev;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct pnfs_block_dev {
|
struct pnfs_block_dev {
|
||||||
struct list_head bm_node;
|
struct nfs4_deviceid_node node;
|
||||||
struct nfs4_deviceid bm_mdevid; /* associated devid */
|
|
||||||
struct block_device *bm_mdev; /* meta device itself */
|
u64 start;
|
||||||
struct net *net;
|
u64 len;
|
||||||
|
|
||||||
|
u32 nr_children;
|
||||||
|
struct pnfs_block_dev *children;
|
||||||
|
u64 chunk_size;
|
||||||
|
|
||||||
|
struct block_device *bdev;
|
||||||
|
u64 disk_offset;
|
||||||
|
|
||||||
|
bool (*map)(struct pnfs_block_dev *dev, u64 offset,
|
||||||
|
struct pnfs_block_dev_map *map);
|
||||||
};
|
};
|
||||||
|
|
||||||
enum exstate4 {
|
enum exstate4 {
|
||||||
@@ -63,86 +124,32 @@ enum exstate4 {
|
|||||||
PNFS_BLOCK_NONE_DATA = 3 /* unmapped, it's a hole */
|
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 list_head im_extents; /* Short extents for INVAL->RW conversion */
|
|
||||||
};
|
|
||||||
|
|
||||||
struct pnfs_inval_tracking {
|
|
||||||
struct list_head it_link;
|
|
||||||
int it_sector;
|
|
||||||
int it_tags;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* sector_t fields are all in 512-byte sectors */
|
/* sector_t fields are all in 512-byte sectors */
|
||||||
struct pnfs_block_extent {
|
struct pnfs_block_extent {
|
||||||
struct kref be_refcnt;
|
union {
|
||||||
struct list_head be_node; /* link into lseg list */
|
struct rb_node be_node;
|
||||||
struct nfs4_deviceid be_devid; /* FIXME: could use device cache instead */
|
struct list_head be_list;
|
||||||
struct block_device *be_mdev;
|
};
|
||||||
|
struct nfs4_deviceid_node *be_device;
|
||||||
sector_t be_f_offset; /* the starting offset in the file */
|
sector_t be_f_offset; /* the starting offset in the file */
|
||||||
sector_t be_length; /* the size of the extent */
|
sector_t be_length; /* the size of the extent */
|
||||||
sector_t be_v_offset; /* the starting offset in the volume */
|
sector_t be_v_offset; /* the starting offset in the volume */
|
||||||
enum exstate4 be_state; /* the state of this extent */
|
enum exstate4 be_state; /* the state of this extent */
|
||||||
struct pnfs_inval_markings *be_inval; /* tracks INVAL->RW transition */
|
#define EXTENT_WRITTEN 1
|
||||||
|
#define EXTENT_COMMITTING 2
|
||||||
|
unsigned int be_tag;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Shortened extent used by LAYOUTCOMMIT */
|
/* on the wire size of the extent */
|
||||||
struct pnfs_block_short_extent {
|
#define BL_EXTENT_SIZE (7 * sizeof(__be32) + NFS4_DEVICEID4_SIZE)
|
||||||
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);
|
|
||||||
INIT_LIST_HEAD(&marks->im_extents);
|
|
||||||
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_block_layout {
|
||||||
struct pnfs_layout_hdr bl_layout;
|
struct pnfs_layout_hdr bl_layout;
|
||||||
struct pnfs_inval_markings bl_inval; /* tracks INVAL->RW transition */
|
struct rb_root bl_ext_rw;
|
||||||
|
struct rb_root bl_ext_ro;
|
||||||
spinlock_t bl_ext_lock; /* Protects list manipulation */
|
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 *
|
static inline struct pnfs_block_layout *
|
||||||
BLK_LO2EXT(struct pnfs_layout_hdr *lo)
|
BLK_LO2EXT(struct pnfs_layout_hdr *lo)
|
||||||
{
|
{
|
||||||
@@ -171,41 +178,27 @@ struct bl_msg_hdr {
|
|||||||
#define BL_DEVICE_REQUEST_PROC 0x1 /* User level process succeeds */
|
#define BL_DEVICE_REQUEST_PROC 0x1 /* User level process succeeds */
|
||||||
#define BL_DEVICE_REQUEST_ERR 0x2 /* User level process fails */
|
#define BL_DEVICE_REQUEST_ERR 0x2 /* User level process fails */
|
||||||
|
|
||||||
/* blocklayoutdev.c */
|
/* dev.c */
|
||||||
ssize_t bl_pipe_downcall(struct file *, const char __user *, size_t);
|
struct nfs4_deviceid_node *bl_alloc_deviceid_node(struct nfs_server *server,
|
||||||
void bl_pipe_destroy_msg(struct rpc_pipe_msg *);
|
struct pnfs_device *pdev, gfp_t gfp_mask);
|
||||||
void nfs4_blkdev_put(struct block_device *bdev);
|
void bl_free_deviceid_node(struct nfs4_deviceid_node *d);
|
||||||
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 */
|
/* extent_tree.c */
|
||||||
void bl_free_block_dev(struct pnfs_block_dev *bdev);
|
int ext_tree_insert(struct pnfs_block_layout *bl,
|
||||||
|
struct pnfs_block_extent *new);
|
||||||
|
int ext_tree_remove(struct pnfs_block_layout *bl, bool rw, sector_t start,
|
||||||
|
sector_t end);
|
||||||
|
int ext_tree_mark_written(struct pnfs_block_layout *bl, sector_t start,
|
||||||
|
sector_t len);
|
||||||
|
bool ext_tree_lookup(struct pnfs_block_layout *bl, sector_t isect,
|
||||||
|
struct pnfs_block_extent *ret, bool rw);
|
||||||
|
int ext_tree_prepare_commit(struct nfs4_layoutcommit_args *arg);
|
||||||
|
void ext_tree_mark_committed(struct nfs4_layoutcommit_args *arg, int status);
|
||||||
|
|
||||||
/* extents.c */
|
/* rpc_pipefs.c */
|
||||||
struct pnfs_block_extent *
|
dev_t bl_resolve_deviceid(struct nfs_server *server,
|
||||||
bl_find_get_extent(struct pnfs_block_layout *bl, sector_t isect,
|
struct pnfs_block_volume *b, gfp_t gfp_mask);
|
||||||
struct pnfs_block_extent **cow_read);
|
int __init bl_init_pipefs(void);
|
||||||
int bl_mark_sectors_init(struct pnfs_inval_markings *marks,
|
void __exit bl_cleanup_pipefs(void);
|
||||||
sector_t offset, sector_t length);
|
|
||||||
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,
|
|
||||||
struct pnfs_block_short_extent *new);
|
|
||||||
int bl_push_one_short_extent(struct pnfs_inval_markings *marks);
|
|
||||||
struct pnfs_block_short_extent *
|
|
||||||
bl_pop_one_short_extent(struct pnfs_inval_markings *marks);
|
|
||||||
void bl_free_short_extents(struct pnfs_inval_markings *marks, int num_to_free);
|
|
||||||
|
|
||||||
#endif /* FS_NFS_NFS4BLOCKLAYOUT_H */
|
#endif /* FS_NFS_NFS4BLOCKLAYOUT_H */
|
||||||
|
|||||||
@@ -1,384 +0,0 @@
|
|||||||
/*
|
|
||||||
* linux/fs/nfs/blocklayout/blocklayoutdev.c
|
|
||||||
*
|
|
||||||
* Device operations for the pnfs nfs4 file 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.
|
|
||||||
*/
|
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/buffer_head.h> /* __bread */
|
|
||||||
|
|
||||||
#include <linux/genhd.h>
|
|
||||||
#include <linux/blkdev.h>
|
|
||||||
#include <linux/hash.h>
|
|
||||||
|
|
||||||
#include "blocklayout.h"
|
|
||||||
|
|
||||||
#define NFSDBG_FACILITY NFSDBG_PNFS_LD
|
|
||||||
|
|
||||||
static int decode_sector_number(__be32 **rp, sector_t *sp)
|
|
||||||
{
|
|
||||||
uint64_t s;
|
|
||||||
|
|
||||||
*rp = xdr_decode_hyper(*rp, &s);
|
|
||||||
if (s & 0x1ff) {
|
|
||||||
printk(KERN_WARNING "NFS: %s: sector not aligned\n", __func__);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
*sp = s >> SECTOR_SHIFT;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Release the block device
|
|
||||||
*/
|
|
||||||
void nfs4_blkdev_put(struct block_device *bdev)
|
|
||||||
{
|
|
||||||
dprintk("%s for device %d:%d\n", __func__, MAJOR(bdev->bd_dev),
|
|
||||||
MINOR(bdev->bd_dev));
|
|
||||||
blkdev_put(bdev, FMODE_READ);
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t bl_pipe_downcall(struct file *filp, const char __user *src,
|
|
||||||
size_t mlen)
|
|
||||||
{
|
|
||||||
struct nfs_net *nn = net_generic(filp->f_dentry->d_sb->s_fs_info,
|
|
||||||
nfs_net_id);
|
|
||||||
|
|
||||||
if (mlen != sizeof (struct bl_dev_msg))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (copy_from_user(&nn->bl_mount_reply, src, mlen) != 0)
|
|
||||||
return -EFAULT;
|
|
||||||
|
|
||||||
wake_up(&nn->bl_wq);
|
|
||||||
|
|
||||||
return mlen;
|
|
||||||
}
|
|
||||||
|
|
||||||
void bl_pipe_destroy_msg(struct rpc_pipe_msg *msg)
|
|
||||||
{
|
|
||||||
struct bl_pipe_msg *bl_pipe_msg = container_of(msg, struct bl_pipe_msg, msg);
|
|
||||||
|
|
||||||
if (msg->errno >= 0)
|
|
||||||
return;
|
|
||||||
wake_up(bl_pipe_msg->bl_wq);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Decodes pnfs_block_deviceaddr4 which is XDR encoded in dev->dev_addr_buf.
|
|
||||||
*/
|
|
||||||
struct pnfs_block_dev *
|
|
||||||
nfs4_blk_decode_device(struct nfs_server *server,
|
|
||||||
struct pnfs_device *dev)
|
|
||||||
{
|
|
||||||
struct pnfs_block_dev *rv;
|
|
||||||
struct block_device *bd = NULL;
|
|
||||||
struct bl_pipe_msg bl_pipe_msg;
|
|
||||||
struct rpc_pipe_msg *msg = &bl_pipe_msg.msg;
|
|
||||||
struct bl_msg_hdr bl_msg = {
|
|
||||||
.type = BL_DEVICE_MOUNT,
|
|
||||||
.totallen = dev->mincount,
|
|
||||||
};
|
|
||||||
uint8_t *dataptr;
|
|
||||||
DECLARE_WAITQUEUE(wq, current);
|
|
||||||
int offset, len, i, rc;
|
|
||||||
struct net *net = server->nfs_client->cl_net;
|
|
||||||
struct nfs_net *nn = net_generic(net, nfs_net_id);
|
|
||||||
struct bl_dev_msg *reply = &nn->bl_mount_reply;
|
|
||||||
|
|
||||||
dprintk("%s CREATING PIPEFS MESSAGE\n", __func__);
|
|
||||||
dprintk("%s: deviceid: %s, mincount: %d\n", __func__, dev->dev_id.data,
|
|
||||||
dev->mincount);
|
|
||||||
|
|
||||||
bl_pipe_msg.bl_wq = &nn->bl_wq;
|
|
||||||
memset(msg, 0, sizeof(*msg));
|
|
||||||
msg->data = kzalloc(sizeof(bl_msg) + dev->mincount, GFP_NOFS);
|
|
||||||
if (!msg->data) {
|
|
||||||
rv = ERR_PTR(-ENOMEM);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(msg->data, &bl_msg, sizeof(bl_msg));
|
|
||||||
dataptr = (uint8_t *) msg->data;
|
|
||||||
len = dev->mincount;
|
|
||||||
offset = sizeof(bl_msg);
|
|
||||||
for (i = 0; len > 0; i++) {
|
|
||||||
memcpy(&dataptr[offset], page_address(dev->pages[i]),
|
|
||||||
len < PAGE_CACHE_SIZE ? len : PAGE_CACHE_SIZE);
|
|
||||||
len -= PAGE_CACHE_SIZE;
|
|
||||||
offset += PAGE_CACHE_SIZE;
|
|
||||||
}
|
|
||||||
msg->len = sizeof(bl_msg) + dev->mincount;
|
|
||||||
|
|
||||||
dprintk("%s CALLING USERSPACE DAEMON\n", __func__);
|
|
||||||
add_wait_queue(&nn->bl_wq, &wq);
|
|
||||||
rc = rpc_queue_upcall(nn->bl_device_pipe, msg);
|
|
||||||
if (rc < 0) {
|
|
||||||
remove_wait_queue(&nn->bl_wq, &wq);
|
|
||||||
rv = ERR_PTR(rc);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
set_current_state(TASK_UNINTERRUPTIBLE);
|
|
||||||
schedule();
|
|
||||||
__set_current_state(TASK_RUNNING);
|
|
||||||
remove_wait_queue(&nn->bl_wq, &wq);
|
|
||||||
|
|
||||||
if (reply->status != BL_DEVICE_REQUEST_PROC) {
|
|
||||||
dprintk("%s failed to open device: %d\n",
|
|
||||||
__func__, reply->status);
|
|
||||||
rv = ERR_PTR(-EINVAL);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
bd = blkdev_get_by_dev(MKDEV(reply->major, reply->minor),
|
|
||||||
FMODE_READ, NULL);
|
|
||||||
if (IS_ERR(bd)) {
|
|
||||||
dprintk("%s failed to open device : %ld\n", __func__,
|
|
||||||
PTR_ERR(bd));
|
|
||||||
rv = ERR_CAST(bd);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
rv = kzalloc(sizeof(*rv), GFP_NOFS);
|
|
||||||
if (!rv) {
|
|
||||||
rv = ERR_PTR(-ENOMEM);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
rv->bm_mdev = bd;
|
|
||||||
memcpy(&rv->bm_mdevid, &dev->dev_id, sizeof(struct nfs4_deviceid));
|
|
||||||
rv->net = net;
|
|
||||||
dprintk("%s Created device %s with bd_block_size %u\n",
|
|
||||||
__func__,
|
|
||||||
bd->bd_disk->disk_name,
|
|
||||||
bd->bd_block_size);
|
|
||||||
|
|
||||||
out:
|
|
||||||
kfree(msg->data);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Map deviceid returned by the server to constructed block_device */
|
|
||||||
static struct block_device *translate_devid(struct pnfs_layout_hdr *lo,
|
|
||||||
struct nfs4_deviceid *id)
|
|
||||||
{
|
|
||||||
struct block_device *rv = NULL;
|
|
||||||
struct block_mount_id *mid;
|
|
||||||
struct pnfs_block_dev *dev;
|
|
||||||
|
|
||||||
dprintk("%s enter, lo=%p, id=%p\n", __func__, lo, id);
|
|
||||||
mid = BLK_ID(lo);
|
|
||||||
spin_lock(&mid->bm_lock);
|
|
||||||
list_for_each_entry(dev, &mid->bm_devlist, bm_node) {
|
|
||||||
if (memcmp(id->data, dev->bm_mdevid.data,
|
|
||||||
NFS4_DEVICEID4_SIZE) == 0) {
|
|
||||||
rv = dev->bm_mdev;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
out:
|
|
||||||
spin_unlock(&mid->bm_lock);
|
|
||||||
dprintk("%s returning %p\n", __func__, rv);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Tracks info needed to ensure extents in layout obey constraints of spec */
|
|
||||||
struct layout_verification {
|
|
||||||
u32 mode; /* R or RW */
|
|
||||||
u64 start; /* Expected start of next non-COW extent */
|
|
||||||
u64 inval; /* Start of INVAL coverage */
|
|
||||||
u64 cowread; /* End of COW read coverage */
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Verify the extent meets the layout requirements of the pnfs-block draft,
|
|
||||||
* section 2.3.1.
|
|
||||||
*/
|
|
||||||
static int verify_extent(struct pnfs_block_extent *be,
|
|
||||||
struct layout_verification *lv)
|
|
||||||
{
|
|
||||||
if (lv->mode == IOMODE_READ) {
|
|
||||||
if (be->be_state == PNFS_BLOCK_READWRITE_DATA ||
|
|
||||||
be->be_state == PNFS_BLOCK_INVALID_DATA)
|
|
||||||
return -EIO;
|
|
||||||
if (be->be_f_offset != lv->start)
|
|
||||||
return -EIO;
|
|
||||||
lv->start += be->be_length;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/* lv->mode == IOMODE_RW */
|
|
||||||
if (be->be_state == PNFS_BLOCK_READWRITE_DATA) {
|
|
||||||
if (be->be_f_offset != lv->start)
|
|
||||||
return -EIO;
|
|
||||||
if (lv->cowread > lv->start)
|
|
||||||
return -EIO;
|
|
||||||
lv->start += be->be_length;
|
|
||||||
lv->inval = lv->start;
|
|
||||||
return 0;
|
|
||||||
} else if (be->be_state == PNFS_BLOCK_INVALID_DATA) {
|
|
||||||
if (be->be_f_offset != lv->start)
|
|
||||||
return -EIO;
|
|
||||||
lv->start += be->be_length;
|
|
||||||
return 0;
|
|
||||||
} else if (be->be_state == PNFS_BLOCK_READ_DATA) {
|
|
||||||
if (be->be_f_offset > lv->start)
|
|
||||||
return -EIO;
|
|
||||||
if (be->be_f_offset < lv->inval)
|
|
||||||
return -EIO;
|
|
||||||
if (be->be_f_offset < lv->cowread)
|
|
||||||
return -EIO;
|
|
||||||
/* It looks like you might want to min this with lv->start,
|
|
||||||
* but you really don't.
|
|
||||||
*/
|
|
||||||
lv->inval = lv->inval + be->be_length;
|
|
||||||
lv->cowread = be->be_f_offset + be->be_length;
|
|
||||||
return 0;
|
|
||||||
} else
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* XDR decode pnfs_block_layout4 structure */
|
|
||||||
int
|
|
||||||
nfs4_blk_process_layoutget(struct pnfs_layout_hdr *lo,
|
|
||||||
struct nfs4_layoutget_res *lgr, gfp_t gfp_flags)
|
|
||||||
{
|
|
||||||
struct pnfs_block_layout *bl = BLK_LO2EXT(lo);
|
|
||||||
int i, status = -EIO;
|
|
||||||
uint32_t count;
|
|
||||||
struct pnfs_block_extent *be = NULL, *save;
|
|
||||||
struct xdr_stream stream;
|
|
||||||
struct xdr_buf buf;
|
|
||||||
struct page *scratch;
|
|
||||||
__be32 *p;
|
|
||||||
struct layout_verification lv = {
|
|
||||||
.mode = lgr->range.iomode,
|
|
||||||
.start = lgr->range.offset >> SECTOR_SHIFT,
|
|
||||||
.inval = lgr->range.offset >> SECTOR_SHIFT,
|
|
||||||
.cowread = lgr->range.offset >> SECTOR_SHIFT,
|
|
||||||
};
|
|
||||||
LIST_HEAD(extents);
|
|
||||||
|
|
||||||
dprintk("---> %s\n", __func__);
|
|
||||||
|
|
||||||
scratch = alloc_page(gfp_flags);
|
|
||||||
if (!scratch)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
xdr_init_decode_pages(&stream, &buf, lgr->layoutp->pages, lgr->layoutp->len);
|
|
||||||
xdr_set_scratch_buffer(&stream, page_address(scratch), PAGE_SIZE);
|
|
||||||
|
|
||||||
p = xdr_inline_decode(&stream, 4);
|
|
||||||
if (unlikely(!p))
|
|
||||||
goto out_err;
|
|
||||||
|
|
||||||
count = be32_to_cpup(p++);
|
|
||||||
|
|
||||||
dprintk("%s enter, number of extents %i\n", __func__, count);
|
|
||||||
p = xdr_inline_decode(&stream, (28 + NFS4_DEVICEID4_SIZE) * count);
|
|
||||||
if (unlikely(!p))
|
|
||||||
goto out_err;
|
|
||||||
|
|
||||||
/* Decode individual extents, putting them in temporary
|
|
||||||
* staging area until whole layout is decoded to make error
|
|
||||||
* recovery easier.
|
|
||||||
*/
|
|
||||||
for (i = 0; i < count; i++) {
|
|
||||||
be = bl_alloc_extent();
|
|
||||||
if (!be) {
|
|
||||||
status = -ENOMEM;
|
|
||||||
goto out_err;
|
|
||||||
}
|
|
||||||
memcpy(&be->be_devid, p, NFS4_DEVICEID4_SIZE);
|
|
||||||
p += XDR_QUADLEN(NFS4_DEVICEID4_SIZE);
|
|
||||||
be->be_mdev = translate_devid(lo, &be->be_devid);
|
|
||||||
if (!be->be_mdev)
|
|
||||||
goto out_err;
|
|
||||||
|
|
||||||
/* The next three values are read in as bytes,
|
|
||||||
* but stored as 512-byte sector lengths
|
|
||||||
*/
|
|
||||||
if (decode_sector_number(&p, &be->be_f_offset) < 0)
|
|
||||||
goto out_err;
|
|
||||||
if (decode_sector_number(&p, &be->be_length) < 0)
|
|
||||||
goto out_err;
|
|
||||||
if (decode_sector_number(&p, &be->be_v_offset) < 0)
|
|
||||||
goto out_err;
|
|
||||||
be->be_state = be32_to_cpup(p++);
|
|
||||||
if (be->be_state == PNFS_BLOCK_INVALID_DATA)
|
|
||||||
be->be_inval = &bl->bl_inval;
|
|
||||||
if (verify_extent(be, &lv)) {
|
|
||||||
dprintk("%s verify failed\n", __func__);
|
|
||||||
goto out_err;
|
|
||||||
}
|
|
||||||
list_add_tail(&be->be_node, &extents);
|
|
||||||
}
|
|
||||||
if (lgr->range.offset + lgr->range.length !=
|
|
||||||
lv.start << SECTOR_SHIFT) {
|
|
||||||
dprintk("%s Final length mismatch\n", __func__);
|
|
||||||
be = NULL;
|
|
||||||
goto out_err;
|
|
||||||
}
|
|
||||||
if (lv.start < lv.cowread) {
|
|
||||||
dprintk("%s Final uncovered COW extent\n", __func__);
|
|
||||||
be = NULL;
|
|
||||||
goto out_err;
|
|
||||||
}
|
|
||||||
/* Extents decoded properly, now try to merge them in to
|
|
||||||
* existing layout extents.
|
|
||||||
*/
|
|
||||||
spin_lock(&bl->bl_ext_lock);
|
|
||||||
list_for_each_entry_safe(be, save, &extents, be_node) {
|
|
||||||
list_del(&be->be_node);
|
|
||||||
status = bl_add_merge_extent(bl, be);
|
|
||||||
if (status) {
|
|
||||||
spin_unlock(&bl->bl_ext_lock);
|
|
||||||
/* This is a fairly catastrophic error, as the
|
|
||||||
* entire layout extent lists are now corrupted.
|
|
||||||
* We should have some way to distinguish this.
|
|
||||||
*/
|
|
||||||
be = NULL;
|
|
||||||
goto out_err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
spin_unlock(&bl->bl_ext_lock);
|
|
||||||
status = 0;
|
|
||||||
out:
|
|
||||||
__free_page(scratch);
|
|
||||||
dprintk("%s returns %i\n", __func__, status);
|
|
||||||
return status;
|
|
||||||
|
|
||||||
out_err:
|
|
||||||
bl_put_extent(be);
|
|
||||||
while (!list_empty(&extents)) {
|
|
||||||
be = list_first_entry(&extents, struct pnfs_block_extent,
|
|
||||||
be_node);
|
|
||||||
list_del(&be->be_node);
|
|
||||||
bl_put_extent(be);
|
|
||||||
}
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
@@ -1,108 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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(struct net *net, dev_t dev)
|
|
||||||
{
|
|
||||||
struct bl_pipe_msg bl_pipe_msg;
|
|
||||||
struct rpc_pipe_msg *msg = &bl_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);
|
|
||||||
struct nfs_net *nn = net_generic(net, nfs_net_id);
|
|
||||||
|
|
||||||
dprintk("Entering %s\n", __func__);
|
|
||||||
|
|
||||||
bl_pipe_msg.bl_wq = &nn->bl_wq;
|
|
||||||
memset(msg, 0, sizeof(*msg));
|
|
||||||
msg->len = sizeof(bl_msg) + bl_msg.totallen;
|
|
||||||
msg->data = kzalloc(msg->len, 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));
|
|
||||||
|
|
||||||
add_wait_queue(&nn->bl_wq, &wq);
|
|
||||||
if (rpc_queue_upcall(nn->bl_device_pipe, msg) < 0) {
|
|
||||||
remove_wait_queue(&nn->bl_wq, &wq);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
set_current_state(TASK_UNINTERRUPTIBLE);
|
|
||||||
schedule();
|
|
||||||
__set_current_state(TASK_RUNNING);
|
|
||||||
remove_wait_queue(&nn->bl_wq, &wq);
|
|
||||||
|
|
||||||
out:
|
|
||||||
kfree(msg->data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Release meta device
|
|
||||||
*/
|
|
||||||
static void nfs4_blk_metadev_release(struct pnfs_block_dev *bdev)
|
|
||||||
{
|
|
||||||
dprintk("%s Releasing\n", __func__);
|
|
||||||
nfs4_blkdev_put(bdev->bm_mdev);
|
|
||||||
dev_remove(bdev->net, 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,363 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2014 Christoph Hellwig.
|
||||||
|
*/
|
||||||
|
#include <linux/sunrpc/svc.h>
|
||||||
|
#include <linux/blkdev.h>
|
||||||
|
#include <linux/nfs4.h>
|
||||||
|
#include <linux/nfs_fs.h>
|
||||||
|
#include <linux/nfs_xdr.h>
|
||||||
|
|
||||||
|
#include "blocklayout.h"
|
||||||
|
|
||||||
|
#define NFSDBG_FACILITY NFSDBG_PNFS_LD
|
||||||
|
|
||||||
|
static void
|
||||||
|
bl_free_device(struct pnfs_block_dev *dev)
|
||||||
|
{
|
||||||
|
if (dev->nr_children) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < dev->nr_children; i++)
|
||||||
|
bl_free_device(&dev->children[i]);
|
||||||
|
kfree(dev->children);
|
||||||
|
} else {
|
||||||
|
if (dev->bdev)
|
||||||
|
blkdev_put(dev->bdev, FMODE_READ);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
bl_free_deviceid_node(struct nfs4_deviceid_node *d)
|
||||||
|
{
|
||||||
|
struct pnfs_block_dev *dev =
|
||||||
|
container_of(d, struct pnfs_block_dev, node);
|
||||||
|
|
||||||
|
bl_free_device(dev);
|
||||||
|
kfree(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
nfs4_block_decode_volume(struct xdr_stream *xdr, struct pnfs_block_volume *b)
|
||||||
|
{
|
||||||
|
__be32 *p;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
p = xdr_inline_decode(xdr, 4);
|
||||||
|
if (!p)
|
||||||
|
return -EIO;
|
||||||
|
b->type = be32_to_cpup(p++);
|
||||||
|
|
||||||
|
switch (b->type) {
|
||||||
|
case PNFS_BLOCK_VOLUME_SIMPLE:
|
||||||
|
p = xdr_inline_decode(xdr, 4);
|
||||||
|
if (!p)
|
||||||
|
return -EIO;
|
||||||
|
b->simple.nr_sigs = be32_to_cpup(p++);
|
||||||
|
if (!b->simple.nr_sigs) {
|
||||||
|
dprintk("no signature\n");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
b->simple.len = 4 + 4;
|
||||||
|
for (i = 0; i < b->simple.nr_sigs; i++) {
|
||||||
|
p = xdr_inline_decode(xdr, 8 + 4);
|
||||||
|
if (!p)
|
||||||
|
return -EIO;
|
||||||
|
p = xdr_decode_hyper(p, &b->simple.sigs[i].offset);
|
||||||
|
b->simple.sigs[i].sig_len = be32_to_cpup(p++);
|
||||||
|
|
||||||
|
p = xdr_inline_decode(xdr, b->simple.sigs[i].sig_len);
|
||||||
|
if (!p)
|
||||||
|
return -EIO;
|
||||||
|
memcpy(&b->simple.sigs[i].sig, p,
|
||||||
|
b->simple.sigs[i].sig_len);
|
||||||
|
|
||||||
|
b->simple.len += 8 + 4 + b->simple.sigs[i].sig_len;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PNFS_BLOCK_VOLUME_SLICE:
|
||||||
|
p = xdr_inline_decode(xdr, 8 + 8 + 4);
|
||||||
|
if (!p)
|
||||||
|
return -EIO;
|
||||||
|
p = xdr_decode_hyper(p, &b->slice.start);
|
||||||
|
p = xdr_decode_hyper(p, &b->slice.len);
|
||||||
|
b->slice.volume = be32_to_cpup(p++);
|
||||||
|
break;
|
||||||
|
case PNFS_BLOCK_VOLUME_CONCAT:
|
||||||
|
p = xdr_inline_decode(xdr, 4);
|
||||||
|
if (!p)
|
||||||
|
return -EIO;
|
||||||
|
b->concat.volumes_count = be32_to_cpup(p++);
|
||||||
|
|
||||||
|
p = xdr_inline_decode(xdr, b->concat.volumes_count * 4);
|
||||||
|
if (!p)
|
||||||
|
return -EIO;
|
||||||
|
for (i = 0; i < b->concat.volumes_count; i++)
|
||||||
|
b->concat.volumes[i] = be32_to_cpup(p++);
|
||||||
|
break;
|
||||||
|
case PNFS_BLOCK_VOLUME_STRIPE:
|
||||||
|
p = xdr_inline_decode(xdr, 8 + 4);
|
||||||
|
if (!p)
|
||||||
|
return -EIO;
|
||||||
|
p = xdr_decode_hyper(p, &b->stripe.chunk_size);
|
||||||
|
b->stripe.volumes_count = be32_to_cpup(p++);
|
||||||
|
|
||||||
|
p = xdr_inline_decode(xdr, b->stripe.volumes_count * 4);
|
||||||
|
if (!p)
|
||||||
|
return -EIO;
|
||||||
|
for (i = 0; i < b->stripe.volumes_count; i++)
|
||||||
|
b->stripe.volumes[i] = be32_to_cpup(p++);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
dprintk("unknown volume type!\n");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool bl_map_simple(struct pnfs_block_dev *dev, u64 offset,
|
||||||
|
struct pnfs_block_dev_map *map)
|
||||||
|
{
|
||||||
|
map->start = dev->start;
|
||||||
|
map->len = dev->len;
|
||||||
|
map->disk_offset = dev->disk_offset;
|
||||||
|
map->bdev = dev->bdev;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool bl_map_concat(struct pnfs_block_dev *dev, u64 offset,
|
||||||
|
struct pnfs_block_dev_map *map)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < dev->nr_children; i++) {
|
||||||
|
struct pnfs_block_dev *child = &dev->children[i];
|
||||||
|
|
||||||
|
if (child->start > offset ||
|
||||||
|
child->start + child->len <= offset)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
child->map(child, offset - child->start, map);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
dprintk("%s: ran off loop!\n", __func__);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool bl_map_stripe(struct pnfs_block_dev *dev, u64 offset,
|
||||||
|
struct pnfs_block_dev_map *map)
|
||||||
|
{
|
||||||
|
struct pnfs_block_dev *child;
|
||||||
|
u64 chunk;
|
||||||
|
u32 chunk_idx;
|
||||||
|
u64 disk_offset;
|
||||||
|
|
||||||
|
chunk = div_u64(offset, dev->chunk_size);
|
||||||
|
div_u64_rem(chunk, dev->nr_children, &chunk_idx);
|
||||||
|
|
||||||
|
if (chunk_idx > dev->nr_children) {
|
||||||
|
dprintk("%s: invalid chunk idx %d (%lld/%lld)\n",
|
||||||
|
__func__, chunk_idx, offset, dev->chunk_size);
|
||||||
|
/* error, should not happen */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* truncate offset to the beginning of the stripe */
|
||||||
|
offset = chunk * dev->chunk_size;
|
||||||
|
|
||||||
|
/* disk offset of the stripe */
|
||||||
|
disk_offset = div_u64(offset, dev->nr_children);
|
||||||
|
|
||||||
|
child = &dev->children[chunk_idx];
|
||||||
|
child->map(child, disk_offset, map);
|
||||||
|
|
||||||
|
map->start += offset;
|
||||||
|
map->disk_offset += disk_offset;
|
||||||
|
map->len = dev->chunk_size;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
bl_parse_deviceid(struct nfs_server *server, struct pnfs_block_dev *d,
|
||||||
|
struct pnfs_block_volume *volumes, int idx, gfp_t gfp_mask);
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
bl_parse_simple(struct nfs_server *server, struct pnfs_block_dev *d,
|
||||||
|
struct pnfs_block_volume *volumes, int idx, gfp_t gfp_mask)
|
||||||
|
{
|
||||||
|
struct pnfs_block_volume *v = &volumes[idx];
|
||||||
|
dev_t dev;
|
||||||
|
|
||||||
|
dev = bl_resolve_deviceid(server, v, gfp_mask);
|
||||||
|
if (!dev)
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
d->bdev = blkdev_get_by_dev(dev, FMODE_READ, NULL);
|
||||||
|
if (IS_ERR(d->bdev)) {
|
||||||
|
printk(KERN_WARNING "pNFS: failed to open device %d:%d (%ld)\n",
|
||||||
|
MAJOR(dev), MINOR(dev), PTR_ERR(d->bdev));
|
||||||
|
return PTR_ERR(d->bdev);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
d->len = i_size_read(d->bdev->bd_inode);
|
||||||
|
d->map = bl_map_simple;
|
||||||
|
|
||||||
|
printk(KERN_INFO "pNFS: using block device %s\n",
|
||||||
|
d->bdev->bd_disk->disk_name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
bl_parse_slice(struct nfs_server *server, struct pnfs_block_dev *d,
|
||||||
|
struct pnfs_block_volume *volumes, int idx, gfp_t gfp_mask)
|
||||||
|
{
|
||||||
|
struct pnfs_block_volume *v = &volumes[idx];
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = bl_parse_deviceid(server, d, volumes, v->slice.volume, gfp_mask);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
d->disk_offset = v->slice.start;
|
||||||
|
d->len = v->slice.len;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
bl_parse_concat(struct nfs_server *server, struct pnfs_block_dev *d,
|
||||||
|
struct pnfs_block_volume *volumes, int idx, gfp_t gfp_mask)
|
||||||
|
{
|
||||||
|
struct pnfs_block_volume *v = &volumes[idx];
|
||||||
|
u64 len = 0;
|
||||||
|
int ret, i;
|
||||||
|
|
||||||
|
d->children = kcalloc(v->concat.volumes_count,
|
||||||
|
sizeof(struct pnfs_block_dev), GFP_KERNEL);
|
||||||
|
if (!d->children)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
for (i = 0; i < v->concat.volumes_count; i++) {
|
||||||
|
ret = bl_parse_deviceid(server, &d->children[i],
|
||||||
|
volumes, v->concat.volumes[i], gfp_mask);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
d->nr_children++;
|
||||||
|
d->children[i].start += len;
|
||||||
|
len += d->children[i].len;
|
||||||
|
}
|
||||||
|
|
||||||
|
d->len = len;
|
||||||
|
d->map = bl_map_concat;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
bl_parse_stripe(struct nfs_server *server, struct pnfs_block_dev *d,
|
||||||
|
struct pnfs_block_volume *volumes, int idx, gfp_t gfp_mask)
|
||||||
|
{
|
||||||
|
struct pnfs_block_volume *v = &volumes[idx];
|
||||||
|
u64 len = 0;
|
||||||
|
int ret, i;
|
||||||
|
|
||||||
|
d->children = kcalloc(v->stripe.volumes_count,
|
||||||
|
sizeof(struct pnfs_block_dev), GFP_KERNEL);
|
||||||
|
if (!d->children)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
for (i = 0; i < v->stripe.volumes_count; i++) {
|
||||||
|
ret = bl_parse_deviceid(server, &d->children[i],
|
||||||
|
volumes, v->stripe.volumes[i], gfp_mask);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
d->nr_children++;
|
||||||
|
len += d->children[i].len;
|
||||||
|
}
|
||||||
|
|
||||||
|
d->len = len;
|
||||||
|
d->chunk_size = v->stripe.chunk_size;
|
||||||
|
d->map = bl_map_stripe;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
bl_parse_deviceid(struct nfs_server *server, struct pnfs_block_dev *d,
|
||||||
|
struct pnfs_block_volume *volumes, int idx, gfp_t gfp_mask)
|
||||||
|
{
|
||||||
|
switch (volumes[idx].type) {
|
||||||
|
case PNFS_BLOCK_VOLUME_SIMPLE:
|
||||||
|
return bl_parse_simple(server, d, volumes, idx, gfp_mask);
|
||||||
|
case PNFS_BLOCK_VOLUME_SLICE:
|
||||||
|
return bl_parse_slice(server, d, volumes, idx, gfp_mask);
|
||||||
|
case PNFS_BLOCK_VOLUME_CONCAT:
|
||||||
|
return bl_parse_concat(server, d, volumes, idx, gfp_mask);
|
||||||
|
case PNFS_BLOCK_VOLUME_STRIPE:
|
||||||
|
return bl_parse_stripe(server, d, volumes, idx, gfp_mask);
|
||||||
|
default:
|
||||||
|
dprintk("unsupported volume type: %d\n", volumes[idx].type);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct nfs4_deviceid_node *
|
||||||
|
bl_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *pdev,
|
||||||
|
gfp_t gfp_mask)
|
||||||
|
{
|
||||||
|
struct nfs4_deviceid_node *node = NULL;
|
||||||
|
struct pnfs_block_volume *volumes;
|
||||||
|
struct pnfs_block_dev *top;
|
||||||
|
struct xdr_stream xdr;
|
||||||
|
struct xdr_buf buf;
|
||||||
|
struct page *scratch;
|
||||||
|
int nr_volumes, ret, i;
|
||||||
|
__be32 *p;
|
||||||
|
|
||||||
|
scratch = alloc_page(gfp_mask);
|
||||||
|
if (!scratch)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
xdr_init_decode_pages(&xdr, &buf, pdev->pages, pdev->pglen);
|
||||||
|
xdr_set_scratch_buffer(&xdr, page_address(scratch), PAGE_SIZE);
|
||||||
|
|
||||||
|
p = xdr_inline_decode(&xdr, sizeof(__be32));
|
||||||
|
if (!p)
|
||||||
|
goto out_free_scratch;
|
||||||
|
nr_volumes = be32_to_cpup(p++);
|
||||||
|
|
||||||
|
volumes = kcalloc(nr_volumes, sizeof(struct pnfs_block_volume),
|
||||||
|
gfp_mask);
|
||||||
|
if (!volumes)
|
||||||
|
goto out_free_scratch;
|
||||||
|
|
||||||
|
for (i = 0; i < nr_volumes; i++) {
|
||||||
|
ret = nfs4_block_decode_volume(&xdr, &volumes[i]);
|
||||||
|
if (ret < 0)
|
||||||
|
goto out_free_volumes;
|
||||||
|
}
|
||||||
|
|
||||||
|
top = kzalloc(sizeof(*top), gfp_mask);
|
||||||
|
if (!top)
|
||||||
|
goto out_free_volumes;
|
||||||
|
|
||||||
|
ret = bl_parse_deviceid(server, top, volumes, nr_volumes - 1, gfp_mask);
|
||||||
|
if (ret) {
|
||||||
|
bl_free_device(top);
|
||||||
|
kfree(top);
|
||||||
|
goto out_free_volumes;
|
||||||
|
}
|
||||||
|
|
||||||
|
node = &top->node;
|
||||||
|
nfs4_init_deviceid_node(node, server, &pdev->dev_id);
|
||||||
|
|
||||||
|
out_free_volumes:
|
||||||
|
kfree(volumes);
|
||||||
|
out_free_scratch:
|
||||||
|
__free_page(scratch);
|
||||||
|
out:
|
||||||
|
return node;
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,285 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2006,2007 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/genhd.h>
|
||||||
|
#include <linux/blkdev.h>
|
||||||
|
|
||||||
|
#include "blocklayout.h"
|
||||||
|
|
||||||
|
#define NFSDBG_FACILITY NFSDBG_PNFS_LD
|
||||||
|
|
||||||
|
static void
|
||||||
|
nfs4_encode_simple(__be32 *p, struct pnfs_block_volume *b)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
*p++ = cpu_to_be32(1);
|
||||||
|
*p++ = cpu_to_be32(b->type);
|
||||||
|
*p++ = cpu_to_be32(b->simple.nr_sigs);
|
||||||
|
for (i = 0; i < b->simple.nr_sigs; i++) {
|
||||||
|
p = xdr_encode_hyper(p, b->simple.sigs[i].offset);
|
||||||
|
p = xdr_encode_opaque(p, b->simple.sigs[i].sig,
|
||||||
|
b->simple.sigs[i].sig_len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_t
|
||||||
|
bl_resolve_deviceid(struct nfs_server *server, struct pnfs_block_volume *b,
|
||||||
|
gfp_t gfp_mask)
|
||||||
|
{
|
||||||
|
struct net *net = server->nfs_client->cl_net;
|
||||||
|
struct nfs_net *nn = net_generic(net, nfs_net_id);
|
||||||
|
struct bl_dev_msg *reply = &nn->bl_mount_reply;
|
||||||
|
struct bl_pipe_msg bl_pipe_msg;
|
||||||
|
struct rpc_pipe_msg *msg = &bl_pipe_msg.msg;
|
||||||
|
struct bl_msg_hdr *bl_msg;
|
||||||
|
DECLARE_WAITQUEUE(wq, current);
|
||||||
|
dev_t dev = 0;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
dprintk("%s CREATING PIPEFS MESSAGE\n", __func__);
|
||||||
|
|
||||||
|
bl_pipe_msg.bl_wq = &nn->bl_wq;
|
||||||
|
|
||||||
|
b->simple.len += 4; /* single volume */
|
||||||
|
if (b->simple.len > PAGE_SIZE)
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
memset(msg, 0, sizeof(*msg));
|
||||||
|
msg->len = sizeof(*bl_msg) + b->simple.len;
|
||||||
|
msg->data = kzalloc(msg->len, gfp_mask);
|
||||||
|
if (!msg->data)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
bl_msg = msg->data;
|
||||||
|
bl_msg->type = BL_DEVICE_MOUNT,
|
||||||
|
bl_msg->totallen = b->simple.len;
|
||||||
|
nfs4_encode_simple(msg->data + sizeof(*bl_msg), b);
|
||||||
|
|
||||||
|
dprintk("%s CALLING USERSPACE DAEMON\n", __func__);
|
||||||
|
add_wait_queue(&nn->bl_wq, &wq);
|
||||||
|
rc = rpc_queue_upcall(nn->bl_device_pipe, msg);
|
||||||
|
if (rc < 0) {
|
||||||
|
remove_wait_queue(&nn->bl_wq, &wq);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
set_current_state(TASK_UNINTERRUPTIBLE);
|
||||||
|
schedule();
|
||||||
|
__set_current_state(TASK_RUNNING);
|
||||||
|
remove_wait_queue(&nn->bl_wq, &wq);
|
||||||
|
|
||||||
|
if (reply->status != BL_DEVICE_REQUEST_PROC) {
|
||||||
|
printk(KERN_WARNING "%s failed to decode device: %d\n",
|
||||||
|
__func__, reply->status);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev = MKDEV(reply->major, reply->minor);
|
||||||
|
out:
|
||||||
|
kfree(msg->data);
|
||||||
|
return dev;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t bl_pipe_downcall(struct file *filp, const char __user *src,
|
||||||
|
size_t mlen)
|
||||||
|
{
|
||||||
|
struct nfs_net *nn = net_generic(filp->f_dentry->d_sb->s_fs_info,
|
||||||
|
nfs_net_id);
|
||||||
|
|
||||||
|
if (mlen != sizeof (struct bl_dev_msg))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (copy_from_user(&nn->bl_mount_reply, src, mlen) != 0)
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
wake_up(&nn->bl_wq);
|
||||||
|
|
||||||
|
return mlen;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bl_pipe_destroy_msg(struct rpc_pipe_msg *msg)
|
||||||
|
{
|
||||||
|
struct bl_pipe_msg *bl_pipe_msg =
|
||||||
|
container_of(msg, struct bl_pipe_msg, msg);
|
||||||
|
|
||||||
|
if (msg->errno >= 0)
|
||||||
|
return;
|
||||||
|
wake_up(bl_pipe_msg->bl_wq);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct rpc_pipe_ops bl_upcall_ops = {
|
||||||
|
.upcall = rpc_pipe_generic_upcall,
|
||||||
|
.downcall = bl_pipe_downcall,
|
||||||
|
.destroy_msg = bl_pipe_destroy_msg,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct dentry *nfs4blocklayout_register_sb(struct super_block *sb,
|
||||||
|
struct rpc_pipe *pipe)
|
||||||
|
{
|
||||||
|
struct dentry *dir, *dentry;
|
||||||
|
|
||||||
|
dir = rpc_d_lookup_sb(sb, NFS_PIPE_DIRNAME);
|
||||||
|
if (dir == NULL)
|
||||||
|
return ERR_PTR(-ENOENT);
|
||||||
|
dentry = rpc_mkpipe_dentry(dir, "blocklayout", NULL, pipe);
|
||||||
|
dput(dir);
|
||||||
|
return dentry;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nfs4blocklayout_unregister_sb(struct super_block *sb,
|
||||||
|
struct rpc_pipe *pipe)
|
||||||
|
{
|
||||||
|
if (pipe->dentry)
|
||||||
|
rpc_unlink(pipe->dentry);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event,
|
||||||
|
void *ptr)
|
||||||
|
{
|
||||||
|
struct super_block *sb = ptr;
|
||||||
|
struct net *net = sb->s_fs_info;
|
||||||
|
struct nfs_net *nn = net_generic(net, nfs_net_id);
|
||||||
|
struct dentry *dentry;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (!try_module_get(THIS_MODULE))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (nn->bl_device_pipe == NULL) {
|
||||||
|
module_put(THIS_MODULE);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (event) {
|
||||||
|
case RPC_PIPEFS_MOUNT:
|
||||||
|
dentry = nfs4blocklayout_register_sb(sb, nn->bl_device_pipe);
|
||||||
|
if (IS_ERR(dentry)) {
|
||||||
|
ret = PTR_ERR(dentry);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
nn->bl_device_pipe->dentry = dentry;
|
||||||
|
break;
|
||||||
|
case RPC_PIPEFS_UMOUNT:
|
||||||
|
if (nn->bl_device_pipe->dentry)
|
||||||
|
nfs4blocklayout_unregister_sb(sb, nn->bl_device_pipe);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ret = -ENOTSUPP;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
module_put(THIS_MODULE);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct notifier_block nfs4blocklayout_block = {
|
||||||
|
.notifier_call = rpc_pipefs_event,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct dentry *nfs4blocklayout_register_net(struct net *net,
|
||||||
|
struct rpc_pipe *pipe)
|
||||||
|
{
|
||||||
|
struct super_block *pipefs_sb;
|
||||||
|
struct dentry *dentry;
|
||||||
|
|
||||||
|
pipefs_sb = rpc_get_sb_net(net);
|
||||||
|
if (!pipefs_sb)
|
||||||
|
return NULL;
|
||||||
|
dentry = nfs4blocklayout_register_sb(pipefs_sb, pipe);
|
||||||
|
rpc_put_sb_net(net);
|
||||||
|
return dentry;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nfs4blocklayout_unregister_net(struct net *net,
|
||||||
|
struct rpc_pipe *pipe)
|
||||||
|
{
|
||||||
|
struct super_block *pipefs_sb;
|
||||||
|
|
||||||
|
pipefs_sb = rpc_get_sb_net(net);
|
||||||
|
if (pipefs_sb) {
|
||||||
|
nfs4blocklayout_unregister_sb(pipefs_sb, pipe);
|
||||||
|
rpc_put_sb_net(net);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nfs4blocklayout_net_init(struct net *net)
|
||||||
|
{
|
||||||
|
struct nfs_net *nn = net_generic(net, nfs_net_id);
|
||||||
|
struct dentry *dentry;
|
||||||
|
|
||||||
|
init_waitqueue_head(&nn->bl_wq);
|
||||||
|
nn->bl_device_pipe = rpc_mkpipe_data(&bl_upcall_ops, 0);
|
||||||
|
if (IS_ERR(nn->bl_device_pipe))
|
||||||
|
return PTR_ERR(nn->bl_device_pipe);
|
||||||
|
dentry = nfs4blocklayout_register_net(net, nn->bl_device_pipe);
|
||||||
|
if (IS_ERR(dentry)) {
|
||||||
|
rpc_destroy_pipe_data(nn->bl_device_pipe);
|
||||||
|
return PTR_ERR(dentry);
|
||||||
|
}
|
||||||
|
nn->bl_device_pipe->dentry = dentry;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nfs4blocklayout_net_exit(struct net *net)
|
||||||
|
{
|
||||||
|
struct nfs_net *nn = net_generic(net, nfs_net_id);
|
||||||
|
|
||||||
|
nfs4blocklayout_unregister_net(net, nn->bl_device_pipe);
|
||||||
|
rpc_destroy_pipe_data(nn->bl_device_pipe);
|
||||||
|
nn->bl_device_pipe = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct pernet_operations nfs4blocklayout_net_ops = {
|
||||||
|
.init = nfs4blocklayout_net_init,
|
||||||
|
.exit = nfs4blocklayout_net_exit,
|
||||||
|
};
|
||||||
|
|
||||||
|
int __init bl_init_pipefs(void)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = rpc_pipefs_notifier_register(&nfs4blocklayout_block);
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
ret = register_pernet_subsys(&nfs4blocklayout_net_ops);
|
||||||
|
if (ret)
|
||||||
|
goto out_unregister_notifier;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
out_unregister_notifier:
|
||||||
|
rpc_pipefs_notifier_unregister(&nfs4blocklayout_block);
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __exit bl_cleanup_pipefs(void)
|
||||||
|
{
|
||||||
|
rpc_pipefs_notifier_unregister(&nfs4blocklayout_block);
|
||||||
|
unregister_pernet_subsys(&nfs4blocklayout_net_ops);
|
||||||
|
}
|
||||||
+16
-7
@@ -171,14 +171,26 @@ static u32 initiate_file_draining(struct nfs_client *clp,
|
|||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
ino = lo->plh_inode;
|
ino = lo->plh_inode;
|
||||||
|
|
||||||
|
spin_lock(&ino->i_lock);
|
||||||
|
pnfs_set_layout_stateid(lo, &args->cbl_stateid, true);
|
||||||
|
spin_unlock(&ino->i_lock);
|
||||||
|
|
||||||
|
pnfs_layoutcommit_inode(ino, false);
|
||||||
|
|
||||||
spin_lock(&ino->i_lock);
|
spin_lock(&ino->i_lock);
|
||||||
if (test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags) ||
|
if (test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags) ||
|
||||||
pnfs_mark_matching_lsegs_invalid(lo, &free_me_list,
|
pnfs_mark_matching_lsegs_invalid(lo, &free_me_list,
|
||||||
&args->cbl_range))
|
&args->cbl_range)) {
|
||||||
rv = NFS4ERR_DELAY;
|
rv = NFS4ERR_DELAY;
|
||||||
else
|
goto unlock;
|
||||||
rv = NFS4ERR_NOMATCHING_LAYOUT;
|
}
|
||||||
pnfs_set_layout_stateid(lo, &args->cbl_stateid, true);
|
|
||||||
|
if (NFS_SERVER(ino)->pnfs_curr_ld->return_range) {
|
||||||
|
NFS_SERVER(ino)->pnfs_curr_ld->return_range(lo,
|
||||||
|
&args->cbl_range);
|
||||||
|
}
|
||||||
|
unlock:
|
||||||
spin_unlock(&ino->i_lock);
|
spin_unlock(&ino->i_lock);
|
||||||
pnfs_free_lseg_list(&free_me_list);
|
pnfs_free_lseg_list(&free_me_list);
|
||||||
pnfs_put_layout_hdr(lo);
|
pnfs_put_layout_hdr(lo);
|
||||||
@@ -277,9 +289,6 @@ __be32 nfs4_callback_devicenotify(struct cb_devicenotifyargs *args,
|
|||||||
}
|
}
|
||||||
|
|
||||||
found:
|
found:
|
||||||
if (dev->cbd_notify_type == NOTIFY_DEVICEID4_CHANGE)
|
|
||||||
dprintk("%s: NOTIFY_DEVICEID4_CHANGE not supported, "
|
|
||||||
"deleting instead\n", __func__);
|
|
||||||
nfs4_delete_deviceid(server->pnfs_curr_ld, clp, &dev->cbd_dev_id);
|
nfs4_delete_deviceid(server->pnfs_curr_ld, clp, &dev->cbd_dev_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+5
-1
@@ -1252,6 +1252,7 @@ static int nfs_server_list_open(struct inode *inode, struct file *file)
|
|||||||
* set up the iterator to start reading from the server list and return the first item
|
* set up the iterator to start reading from the server list and return the first item
|
||||||
*/
|
*/
|
||||||
static void *nfs_server_list_start(struct seq_file *m, loff_t *_pos)
|
static void *nfs_server_list_start(struct seq_file *m, loff_t *_pos)
|
||||||
|
__acquires(&nn->nfs_client_lock)
|
||||||
{
|
{
|
||||||
struct nfs_net *nn = net_generic(seq_file_net(m), nfs_net_id);
|
struct nfs_net *nn = net_generic(seq_file_net(m), nfs_net_id);
|
||||||
|
|
||||||
@@ -1274,6 +1275,7 @@ static void *nfs_server_list_next(struct seq_file *p, void *v, loff_t *pos)
|
|||||||
* clean up after reading from the transports list
|
* clean up after reading from the transports list
|
||||||
*/
|
*/
|
||||||
static void nfs_server_list_stop(struct seq_file *p, void *v)
|
static void nfs_server_list_stop(struct seq_file *p, void *v)
|
||||||
|
__releases(&nn->nfs_client_lock)
|
||||||
{
|
{
|
||||||
struct nfs_net *nn = net_generic(seq_file_net(p), nfs_net_id);
|
struct nfs_net *nn = net_generic(seq_file_net(p), nfs_net_id);
|
||||||
|
|
||||||
@@ -1318,7 +1320,7 @@ static int nfs_server_list_show(struct seq_file *m, void *v)
|
|||||||
*/
|
*/
|
||||||
static int nfs_volume_list_open(struct inode *inode, struct file *file)
|
static int nfs_volume_list_open(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
return seq_open_net(inode, file, &nfs_server_list_ops,
|
return seq_open_net(inode, file, &nfs_volume_list_ops,
|
||||||
sizeof(struct seq_net_private));
|
sizeof(struct seq_net_private));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1326,6 +1328,7 @@ static int nfs_volume_list_open(struct inode *inode, struct file *file)
|
|||||||
* set up the iterator to start reading from the volume list and return the first item
|
* set up the iterator to start reading from the volume list and return the first item
|
||||||
*/
|
*/
|
||||||
static void *nfs_volume_list_start(struct seq_file *m, loff_t *_pos)
|
static void *nfs_volume_list_start(struct seq_file *m, loff_t *_pos)
|
||||||
|
__acquires(&nn->nfs_client_lock)
|
||||||
{
|
{
|
||||||
struct nfs_net *nn = net_generic(seq_file_net(m), nfs_net_id);
|
struct nfs_net *nn = net_generic(seq_file_net(m), nfs_net_id);
|
||||||
|
|
||||||
@@ -1348,6 +1351,7 @@ static void *nfs_volume_list_next(struct seq_file *p, void *v, loff_t *pos)
|
|||||||
* clean up after reading from the transports list
|
* clean up after reading from the transports list
|
||||||
*/
|
*/
|
||||||
static void nfs_volume_list_stop(struct seq_file *p, void *v)
|
static void nfs_volume_list_stop(struct seq_file *p, void *v)
|
||||||
|
__releases(&nn->nfs_client_lock)
|
||||||
{
|
{
|
||||||
struct nfs_net *nn = net_generic(seq_file_net(p), nfs_net_id);
|
struct nfs_net *nn = net_generic(seq_file_net(p), nfs_net_id);
|
||||||
|
|
||||||
|
|||||||
@@ -178,7 +178,6 @@ static int nfs_direct_set_or_cmp_hdr_verf(struct nfs_direct_req *dreq,
|
|||||||
return memcmp(verfp, &hdr->verf, sizeof(struct nfs_writeverf));
|
return memcmp(verfp, &hdr->verf, sizeof(struct nfs_writeverf));
|
||||||
}
|
}
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_NFS_V3) || IS_ENABLED(CONFIG_NFS_V4)
|
|
||||||
/*
|
/*
|
||||||
* nfs_direct_cmp_commit_data_verf - compare verifier for commit data
|
* nfs_direct_cmp_commit_data_verf - compare verifier for commit data
|
||||||
* @dreq - direct request possibly spanning multiple servers
|
* @dreq - direct request possibly spanning multiple servers
|
||||||
@@ -197,7 +196,6 @@ static int nfs_direct_cmp_commit_data_verf(struct nfs_direct_req *dreq,
|
|||||||
WARN_ON_ONCE(verfp->committed < 0);
|
WARN_ON_ONCE(verfp->committed < 0);
|
||||||
return memcmp(verfp, &data->verf, sizeof(struct nfs_writeverf));
|
return memcmp(verfp, &data->verf, sizeof(struct nfs_writeverf));
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* nfs_direct_IO - NFS address space operation for direct I/O
|
* nfs_direct_IO - NFS address space operation for direct I/O
|
||||||
@@ -576,7 +574,6 @@ out:
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_NFS_V3) || IS_ENABLED(CONFIG_NFS_V4)
|
|
||||||
static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq)
|
static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq)
|
||||||
{
|
{
|
||||||
struct nfs_pageio_descriptor desc;
|
struct nfs_pageio_descriptor desc;
|
||||||
@@ -700,17 +697,6 @@ static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode
|
|||||||
schedule_work(&dreq->work); /* Calls nfs_direct_write_schedule_work */
|
schedule_work(&dreq->work); /* Calls nfs_direct_write_schedule_work */
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
|
||||||
static void nfs_direct_write_schedule_work(struct work_struct *work)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode *inode)
|
|
||||||
{
|
|
||||||
nfs_direct_complete(dreq, true);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void nfs_direct_write_completion(struct nfs_pgio_header *hdr)
|
static void nfs_direct_write_completion(struct nfs_pgio_header *hdr)
|
||||||
{
|
{
|
||||||
struct nfs_direct_req *dreq = hdr->dreq;
|
struct nfs_direct_req *dreq = hdr->dreq;
|
||||||
|
|||||||
+40
-12
@@ -36,6 +36,7 @@
|
|||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
#include "iostat.h"
|
#include "iostat.h"
|
||||||
#include "fscache.h"
|
#include "fscache.h"
|
||||||
|
#include "pnfs.h"
|
||||||
|
|
||||||
#include "nfstrace.h"
|
#include "nfstrace.h"
|
||||||
|
|
||||||
@@ -327,6 +328,12 @@ static int nfs_want_read_modify_write(struct file *file, struct page *page,
|
|||||||
unsigned int offset = pos & (PAGE_CACHE_SIZE - 1);
|
unsigned int offset = pos & (PAGE_CACHE_SIZE - 1);
|
||||||
unsigned int end = offset + len;
|
unsigned int end = offset + len;
|
||||||
|
|
||||||
|
if (pnfs_ld_read_whole_page(file->f_mapping->host)) {
|
||||||
|
if (!PageUptodate(page))
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if ((file->f_mode & FMODE_READ) && /* open for read? */
|
if ((file->f_mode & FMODE_READ) && /* open for read? */
|
||||||
!PageUptodate(page) && /* Uptodate? */
|
!PageUptodate(page) && /* Uptodate? */
|
||||||
!PagePrivate(page) && /* i/o request already? */
|
!PagePrivate(page) && /* i/o request already? */
|
||||||
@@ -468,17 +475,26 @@ static int nfs_release_page(struct page *page, gfp_t gfp)
|
|||||||
|
|
||||||
dfprintk(PAGECACHE, "NFS: release_page(%p)\n", page);
|
dfprintk(PAGECACHE, "NFS: release_page(%p)\n", page);
|
||||||
|
|
||||||
/* Only do I/O if gfp is a superset of GFP_KERNEL, and we're not
|
/* Always try to initiate a 'commit' if relevant, but only
|
||||||
* doing this memory reclaim for a fs-related allocation.
|
* wait for it if __GFP_WAIT is set. Even then, only wait 1
|
||||||
|
* second and only if the 'bdi' is not congested.
|
||||||
|
* Waiting indefinitely can cause deadlocks when the NFS
|
||||||
|
* server is on this machine, when a new TCP connection is
|
||||||
|
* needed and in other rare cases. There is no particular
|
||||||
|
* need to wait extensively here. A short wait has the
|
||||||
|
* benefit that someone else can worry about the freezer.
|
||||||
*/
|
*/
|
||||||
if (mapping && (gfp & GFP_KERNEL) == GFP_KERNEL &&
|
if (mapping) {
|
||||||
!(current->flags & PF_FSTRANS)) {
|
struct nfs_server *nfss = NFS_SERVER(mapping->host);
|
||||||
int how = FLUSH_SYNC;
|
nfs_commit_inode(mapping->host, 0);
|
||||||
|
if ((gfp & __GFP_WAIT) &&
|
||||||
/* Don't let kswapd deadlock waiting for OOM RPC calls */
|
!bdi_write_congested(&nfss->backing_dev_info)) {
|
||||||
if (current_is_kswapd())
|
wait_on_page_bit_killable_timeout(page, PG_private,
|
||||||
how = 0;
|
HZ);
|
||||||
nfs_commit_inode(mapping->host, how);
|
if (PagePrivate(page))
|
||||||
|
set_bdi_congested(&nfss->backing_dev_info,
|
||||||
|
BLK_RW_ASYNC);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/* If PagePrivate() is set, then the page is not freeable */
|
/* If PagePrivate() is set, then the page is not freeable */
|
||||||
if (PagePrivate(page))
|
if (PagePrivate(page))
|
||||||
@@ -539,13 +555,25 @@ static int nfs_launder_page(struct page *page)
|
|||||||
static int nfs_swap_activate(struct swap_info_struct *sis, struct file *file,
|
static int nfs_swap_activate(struct swap_info_struct *sis, struct file *file,
|
||||||
sector_t *span)
|
sector_t *span)
|
||||||
{
|
{
|
||||||
|
int ret;
|
||||||
|
struct rpc_clnt *clnt = NFS_CLIENT(file->f_mapping->host);
|
||||||
|
|
||||||
*span = sis->pages;
|
*span = sis->pages;
|
||||||
return xs_swapper(NFS_CLIENT(file->f_mapping->host)->cl_xprt, 1);
|
|
||||||
|
rcu_read_lock();
|
||||||
|
ret = xs_swapper(rcu_dereference(clnt->cl_xprt), 1);
|
||||||
|
rcu_read_unlock();
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nfs_swap_deactivate(struct file *file)
|
static void nfs_swap_deactivate(struct file *file)
|
||||||
{
|
{
|
||||||
xs_swapper(NFS_CLIENT(file->f_mapping->host)->cl_xprt, 0);
|
struct rpc_clnt *clnt = NFS_CLIENT(file->f_mapping->host);
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
xs_swapper(rcu_dereference(clnt->cl_xprt), 0);
|
||||||
|
rcu_read_unlock();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -265,7 +265,7 @@ filelayout_set_layoutcommit(struct nfs_pgio_header *hdr)
|
|||||||
{
|
{
|
||||||
|
|
||||||
if (FILELAYOUT_LSEG(hdr->lseg)->commit_through_mds ||
|
if (FILELAYOUT_LSEG(hdr->lseg)->commit_through_mds ||
|
||||||
hdr->res.verf->committed == NFS_FILE_SYNC)
|
hdr->res.verf->committed != NFS_DATA_SYNC)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
pnfs_set_layoutcommit(hdr);
|
pnfs_set_layoutcommit(hdr);
|
||||||
@@ -403,6 +403,9 @@ static int filelayout_commit_done_cb(struct rpc_task *task,
|
|||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (data->verf.committed == NFS_UNSTABLE)
|
||||||
|
pnfs_commit_set_layoutcommit(data);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -646,18 +649,15 @@ filelayout_check_layout(struct pnfs_layout_hdr *lo,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* find and reference the deviceid */
|
/* find and reference the deviceid */
|
||||||
d = nfs4_find_get_deviceid(NFS_SERVER(lo->plh_inode)->pnfs_curr_ld,
|
d = nfs4_find_get_deviceid(NFS_SERVER(lo->plh_inode), id,
|
||||||
NFS_SERVER(lo->plh_inode)->nfs_client, id);
|
lo->plh_lc_cred, gfp_flags);
|
||||||
if (d == NULL) {
|
if (d == NULL)
|
||||||
dsaddr = filelayout_get_device_info(lo->plh_inode, id,
|
goto out;
|
||||||
lo->plh_lc_cred, gfp_flags);
|
|
||||||
if (dsaddr == NULL)
|
dsaddr = container_of(d, struct nfs4_file_layout_dsaddr, id_node);
|
||||||
goto out;
|
|
||||||
} else
|
|
||||||
dsaddr = container_of(d, struct nfs4_file_layout_dsaddr, id_node);
|
|
||||||
/* Found deviceid is unavailable */
|
/* Found deviceid is unavailable */
|
||||||
if (filelayout_test_devid_unavailable(&dsaddr->id_node))
|
if (filelayout_test_devid_unavailable(&dsaddr->id_node))
|
||||||
goto out_put;
|
goto out_put;
|
||||||
|
|
||||||
fl->dsaddr = dsaddr;
|
fl->dsaddr = dsaddr;
|
||||||
|
|
||||||
@@ -1368,6 +1368,17 @@ out:
|
|||||||
cinfo->ds->ncommitting = 0;
|
cinfo->ds->ncommitting = 0;
|
||||||
return PNFS_ATTEMPTED;
|
return PNFS_ATTEMPTED;
|
||||||
}
|
}
|
||||||
|
static struct nfs4_deviceid_node *
|
||||||
|
filelayout_alloc_deviceid_node(struct nfs_server *server,
|
||||||
|
struct pnfs_device *pdev, gfp_t gfp_flags)
|
||||||
|
{
|
||||||
|
struct nfs4_file_layout_dsaddr *dsaddr;
|
||||||
|
|
||||||
|
dsaddr = nfs4_fl_alloc_deviceid_node(server, pdev, gfp_flags);
|
||||||
|
if (!dsaddr)
|
||||||
|
return NULL;
|
||||||
|
return &dsaddr->id_node;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
filelayout_free_deveiceid_node(struct nfs4_deviceid_node *d)
|
filelayout_free_deveiceid_node(struct nfs4_deviceid_node *d)
|
||||||
@@ -1420,6 +1431,7 @@ static struct pnfs_layoutdriver_type filelayout_type = {
|
|||||||
.commit_pagelist = filelayout_commit_pagelist,
|
.commit_pagelist = filelayout_commit_pagelist,
|
||||||
.read_pagelist = filelayout_read_pagelist,
|
.read_pagelist = filelayout_read_pagelist,
|
||||||
.write_pagelist = filelayout_write_pagelist,
|
.write_pagelist = filelayout_write_pagelist,
|
||||||
|
.alloc_deviceid_node = filelayout_alloc_deviceid_node,
|
||||||
.free_deviceid_node = filelayout_free_deveiceid_node,
|
.free_deviceid_node = filelayout_free_deveiceid_node,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -147,10 +147,11 @@ u32 nfs4_fl_calc_j_index(struct pnfs_layout_segment *lseg, loff_t offset);
|
|||||||
u32 nfs4_fl_calc_ds_index(struct pnfs_layout_segment *lseg, u32 j);
|
u32 nfs4_fl_calc_ds_index(struct pnfs_layout_segment *lseg, u32 j);
|
||||||
struct nfs4_pnfs_ds *nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg,
|
struct nfs4_pnfs_ds *nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg,
|
||||||
u32 ds_idx);
|
u32 ds_idx);
|
||||||
|
|
||||||
|
extern struct nfs4_file_layout_dsaddr *
|
||||||
|
nfs4_fl_alloc_deviceid_node(struct nfs_server *server,
|
||||||
|
struct pnfs_device *pdev, gfp_t gfp_flags);
|
||||||
extern void nfs4_fl_put_deviceid(struct nfs4_file_layout_dsaddr *dsaddr);
|
extern void nfs4_fl_put_deviceid(struct nfs4_file_layout_dsaddr *dsaddr);
|
||||||
extern void nfs4_fl_free_deviceid(struct nfs4_file_layout_dsaddr *dsaddr);
|
extern void nfs4_fl_free_deviceid(struct nfs4_file_layout_dsaddr *dsaddr);
|
||||||
struct nfs4_file_layout_dsaddr *
|
|
||||||
filelayout_get_device_info(struct inode *inode, struct nfs4_deviceid *dev_id,
|
|
||||||
struct rpc_cred *cred, gfp_t gfp_flags);
|
|
||||||
|
|
||||||
#endif /* FS_NFS_NFS4FILELAYOUT_H */
|
#endif /* FS_NFS_NFS4FILELAYOUT_H */
|
||||||
|
|||||||
@@ -484,8 +484,9 @@ out_err:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Decode opaque device data and return the result */
|
/* Decode opaque device data and return the result */
|
||||||
static struct nfs4_file_layout_dsaddr*
|
struct nfs4_file_layout_dsaddr *
|
||||||
decode_device(struct inode *ino, struct pnfs_device *pdev, gfp_t gfp_flags)
|
nfs4_fl_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *pdev,
|
||||||
|
gfp_t gfp_flags)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
u32 cnt, num;
|
u32 cnt, num;
|
||||||
@@ -570,10 +571,7 @@ decode_device(struct inode *ino, struct pnfs_device *pdev, gfp_t gfp_flags)
|
|||||||
dsaddr->stripe_indices = stripe_indices;
|
dsaddr->stripe_indices = stripe_indices;
|
||||||
stripe_indices = NULL;
|
stripe_indices = NULL;
|
||||||
dsaddr->ds_num = num;
|
dsaddr->ds_num = num;
|
||||||
nfs4_init_deviceid_node(&dsaddr->id_node,
|
nfs4_init_deviceid_node(&dsaddr->id_node, server, &pdev->dev_id);
|
||||||
NFS_SERVER(ino)->pnfs_curr_ld,
|
|
||||||
NFS_SERVER(ino)->nfs_client,
|
|
||||||
&pdev->dev_id);
|
|
||||||
|
|
||||||
INIT_LIST_HEAD(&dsaddrs);
|
INIT_LIST_HEAD(&dsaddrs);
|
||||||
|
|
||||||
@@ -587,7 +585,7 @@ decode_device(struct inode *ino, struct pnfs_device *pdev, gfp_t gfp_flags)
|
|||||||
|
|
||||||
mp_count = be32_to_cpup(p); /* multipath count */
|
mp_count = be32_to_cpup(p); /* multipath count */
|
||||||
for (j = 0; j < mp_count; j++) {
|
for (j = 0; j < mp_count; j++) {
|
||||||
da = decode_ds_addr(NFS_SERVER(ino)->nfs_client->cl_net,
|
da = decode_ds_addr(server->nfs_client->cl_net,
|
||||||
&stream, gfp_flags);
|
&stream, gfp_flags);
|
||||||
if (da)
|
if (da)
|
||||||
list_add_tail(&da->da_node, &dsaddrs);
|
list_add_tail(&da->da_node, &dsaddrs);
|
||||||
@@ -637,102 +635,6 @@ out_err:
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Decode the opaque device specified in 'dev' and add it to the cache of
|
|
||||||
* available devices.
|
|
||||||
*/
|
|
||||||
static struct nfs4_file_layout_dsaddr *
|
|
||||||
decode_and_add_device(struct inode *inode, struct pnfs_device *dev, gfp_t gfp_flags)
|
|
||||||
{
|
|
||||||
struct nfs4_deviceid_node *d;
|
|
||||||
struct nfs4_file_layout_dsaddr *n, *new;
|
|
||||||
|
|
||||||
new = decode_device(inode, dev, gfp_flags);
|
|
||||||
if (!new) {
|
|
||||||
printk(KERN_WARNING "NFS: %s: Could not decode or add device\n",
|
|
||||||
__func__);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
d = nfs4_insert_deviceid_node(&new->id_node);
|
|
||||||
n = container_of(d, struct nfs4_file_layout_dsaddr, id_node);
|
|
||||||
if (n != new) {
|
|
||||||
nfs4_fl_free_deviceid(new);
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Retrieve the information for dev_id, add it to the list
|
|
||||||
* of available devices, and return it.
|
|
||||||
*/
|
|
||||||
struct nfs4_file_layout_dsaddr *
|
|
||||||
filelayout_get_device_info(struct inode *inode,
|
|
||||||
struct nfs4_deviceid *dev_id,
|
|
||||||
struct rpc_cred *cred,
|
|
||||||
gfp_t gfp_flags)
|
|
||||||
{
|
|
||||||
struct pnfs_device *pdev = NULL;
|
|
||||||
u32 max_resp_sz;
|
|
||||||
int max_pages;
|
|
||||||
struct page **pages = NULL;
|
|
||||||
struct nfs4_file_layout_dsaddr *dsaddr = NULL;
|
|
||||||
int rc, i;
|
|
||||||
struct nfs_server *server = NFS_SERVER(inode);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Use the session max response size as the basis for setting
|
|
||||||
* GETDEVICEINFO's maxcount
|
|
||||||
*/
|
|
||||||
max_resp_sz = server->nfs_client->cl_session->fc_attrs.max_resp_sz;
|
|
||||||
max_pages = nfs_page_array_len(0, max_resp_sz);
|
|
||||||
dprintk("%s inode %p max_resp_sz %u max_pages %d\n",
|
|
||||||
__func__, inode, max_resp_sz, max_pages);
|
|
||||||
|
|
||||||
pdev = kzalloc(sizeof(struct pnfs_device), gfp_flags);
|
|
||||||
if (pdev == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
pages = kcalloc(max_pages, sizeof(struct page *), gfp_flags);
|
|
||||||
if (pages == NULL) {
|
|
||||||
kfree(pdev);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
for (i = 0; i < max_pages; i++) {
|
|
||||||
pages[i] = alloc_page(gfp_flags);
|
|
||||||
if (!pages[i])
|
|
||||||
goto out_free;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(&pdev->dev_id, dev_id, sizeof(*dev_id));
|
|
||||||
pdev->layout_type = LAYOUT_NFSV4_1_FILES;
|
|
||||||
pdev->pages = pages;
|
|
||||||
pdev->pgbase = 0;
|
|
||||||
pdev->pglen = max_resp_sz;
|
|
||||||
pdev->mincount = 0;
|
|
||||||
pdev->maxcount = max_resp_sz - nfs41_maxgetdevinfo_overhead;
|
|
||||||
|
|
||||||
rc = nfs4_proc_getdeviceinfo(server, pdev, cred);
|
|
||||||
dprintk("%s getdevice info returns %d\n", __func__, rc);
|
|
||||||
if (rc)
|
|
||||||
goto out_free;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Found new device, need to decode it and then add it to the
|
|
||||||
* list of known devices for this mountpoint.
|
|
||||||
*/
|
|
||||||
dsaddr = decode_and_add_device(inode, pdev, gfp_flags);
|
|
||||||
out_free:
|
|
||||||
for (i = 0; i < max_pages; i++)
|
|
||||||
__free_page(pages[i]);
|
|
||||||
kfree(pages);
|
|
||||||
kfree(pdev);
|
|
||||||
dprintk("<-- %s dsaddr %p\n", __func__, dsaddr);
|
|
||||||
return dsaddr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
nfs4_fl_put_deviceid(struct nfs4_file_layout_dsaddr *dsaddr)
|
nfs4_fl_put_deviceid(struct nfs4_file_layout_dsaddr *dsaddr)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -74,11 +74,10 @@ static uint16_t nfs_server_get_key(const void *cookie_netfs_data,
|
|||||||
struct nfs_server_key *key = buffer;
|
struct nfs_server_key *key = buffer;
|
||||||
uint16_t len = sizeof(struct nfs_server_key);
|
uint16_t len = sizeof(struct nfs_server_key);
|
||||||
|
|
||||||
|
memset(key, 0, len);
|
||||||
key->nfsversion = clp->rpc_ops->version;
|
key->nfsversion = clp->rpc_ops->version;
|
||||||
key->family = clp->cl_addr.ss_family;
|
key->family = clp->cl_addr.ss_family;
|
||||||
|
|
||||||
memset(key, 0, len);
|
|
||||||
|
|
||||||
switch (clp->cl_addr.ss_family) {
|
switch (clp->cl_addr.ss_family) {
|
||||||
case AF_INET:
|
case AF_INET:
|
||||||
key->port = sin->sin_port;
|
key->port = sin->sin_port;
|
||||||
|
|||||||
+3
-1
@@ -505,7 +505,9 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr)
|
|||||||
attr->ia_valid &= ~ATTR_MODE;
|
attr->ia_valid &= ~ATTR_MODE;
|
||||||
|
|
||||||
if (attr->ia_valid & ATTR_SIZE) {
|
if (attr->ia_valid & ATTR_SIZE) {
|
||||||
if (!S_ISREG(inode->i_mode) || attr->ia_size == i_size_read(inode))
|
BUG_ON(!S_ISREG(inode->i_mode));
|
||||||
|
|
||||||
|
if (attr->ia_size == i_size_read(inode))
|
||||||
attr->ia_valid &= ~ATTR_SIZE;
|
attr->ia_valid &= ~ATTR_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -218,13 +218,6 @@ static inline void nfs_fs_proc_exit(void)
|
|||||||
int nfs_sockaddr_match_ipaddr(const struct sockaddr *, const struct sockaddr *);
|
int nfs_sockaddr_match_ipaddr(const struct sockaddr *, const struct sockaddr *);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* nfs3client.c */
|
|
||||||
#if IS_ENABLED(CONFIG_NFS_V3)
|
|
||||||
struct nfs_server *nfs3_create_server(struct nfs_mount_info *, struct nfs_subversion *);
|
|
||||||
struct nfs_server *nfs3_clone_server(struct nfs_server *, struct nfs_fh *,
|
|
||||||
struct nfs_fattr *, rpc_authflavor_t);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* callback_xdr.c */
|
/* callback_xdr.c */
|
||||||
extern struct svc_version nfs4_callback_version1;
|
extern struct svc_version nfs4_callback_version1;
|
||||||
extern struct svc_version nfs4_callback_version4;
|
extern struct svc_version nfs4_callback_version4;
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user