v2 block layout patches
Subsystems (3)
cover v2 block layout patches
This version is based on commit 3f585d500f68912fa622749f519ed7df16e417b8. It fixes the whitespace errors, adds a couple of missing signed-offs, moves the configurable prefetch to the end and labels it DEVONLY, fixes the Kconfig, standardizes on "pnfsblock" for patch subject, and makes some other minor cleanups. I have not yet incorporated Fred's suggestions.
This patch set is also available on the for-benny branch ofgit://citi.umich.edu/projects/linux-pnfs-blk.git .
Andy Adamson (1):
pnfs: GETDEVICELIST
Benny Halevy (1):
pnfs: add set-clear layoutdriver interface
Fred (1):
pnfsblock: find_get_extent
Fred Isaman (21):
pnfsblock: define PNFS_BLOCK Kconfig option
pnfsblock: blocklayout stub
pnfsblock: layout alloc and free
pnfsblock: add support for simple rpc pipefs
pnfsblock: basic extent code
pnfsblock: lseg alloc and free
pnfsblock: merge extents
pnfsblock: call and parse getdevicelist
pnfsblock: allow use of PG_owner_priv_1 flag
pnfsblock: xdr decode pnfs_block_layout4
pnfsblock: SPLITME: add extent manipulation functions
pnfsblock: merge rw extents
pnfsblock: encode_layoutcommit
pnfsblock: cleanup_layoutcommit
pnfsblock: bl_read_pagelist
pnfsblock: write_begin
pnfsblock: write_end
pnfsblock: write_end_cleanup
pnfsblock: bl_write_pagelist support functions
pnfsblock: bl_write_pagelist
pnfsblock: note written INVAL areas for layoutcommit
Jim Rees (3):
pnfsblock: add block device discovery pipe
pnfsblock: add device operations
pnfsblock: remove device operations
Peng Tao (5):
pnfs: let layoutcommit code handle multiple segments
pnfs: hook nfs_write_begin/end to allow layout driver manipulation
pnfs: ask for layout_blksize and save it in nfs_server
pnfs: cleanup_layoutcommit
pnfsblock DEVONLY: Add configurable prefetch size for layoutget
Zhang Jingwang (1):
pnfsblock: Implement release_inval_marks
fs/nfs/Kconfig | 10 + fs/nfs/Makefile | 1 + fs/nfs/blocklayout/Makefile | 5 + fs/nfs/blocklayout/block-device-discovery-pipe.c | 66 ++ fs/nfs/blocklayout/blocklayout.c | 1085 ++++++++++++++++++++++ fs/nfs/blocklayout/blocklayout.h | 287 ++++++ fs/nfs/blocklayout/blocklayoutdev.c | 346 +++++++ fs/nfs/blocklayout/blocklayoutdm.c | 120 +++ fs/nfs/blocklayout/extents.c | 941 +++++++++++++++++++ fs/nfs/client.c | 9 +- fs/nfs/file.c | 26 +- fs/nfs/nfs4_fs.h | 2 +- fs/nfs/nfs4proc.c | 54 +- fs/nfs/nfs4xdr.c | 232 +++++- fs/nfs/pnfs.c | 107 ++- fs/nfs/pnfs.h | 142 +++- fs/nfs/sysctl.c | 10 + fs/nfs/write.c | 12 +- include/linux/nfs4.h | 1 + include/linux/nfs_fs.h | 3 +- include/linux/nfs_fs_sb.h | 4 +- include/linux/nfs_xdr.h | 15 +- include/linux/sunrpc/simple_rpc_pipefs.h | 105 +++ net/sunrpc/simple_rpc_pipefs.c | 423 +++++++++ 24 files changed, 3963 insertions(+), 43 deletions(-) create mode 100644 fs/nfs/blocklayout/Makefile create mode 100644 fs/nfs/blocklayout/block-device-discovery-pipe.c create mode 100644 fs/nfs/blocklayout/blocklayout.c create mode 100644 fs/nfs/blocklayout/blocklayout.h create mode 100644 fs/nfs/blocklayout/blocklayoutdev.c create mode 100644 fs/nfs/blocklayout/blocklayoutdm.c create mode 100644 fs/nfs/blocklayout/extents.c create mode 100644 include/linux/sunrpc/simple_rpc_pipefs.h create mode 100644 net/sunrpc/simple_rpc_pipefs.c
Signature · 1 line
1.7.4.1
PATCH 1/33 pnfs: GETDEVICELIST
From: Andy Adamson <[email protected]>
The block driver uses GETDEVICELIST
--- fs/nfs/nfs4proc.c | 48 ++++++++++++++++++ fs/nfs/nfs4xdr.c | 128 +++++++++++++++++++++++++++++++++++++++++++++++ fs/nfs/pnfs.h | 12 ++++ include/linux/nfs4.h | 1 + include/linux/nfs_xdr.h | 11 ++++ 5 files changed, 200 insertions(+), 0 deletions(-)
fs/nfs/nfs4proc.c +48 -0
@@ -5759,6 +5759,54 @@ int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp)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 _nfs4_proc_getdeviceinfo (struct nfs_server *server,struct pnfs_device *pdev) {
fs/nfs/nfs4xdr.c +128 -0
170 lines not on this page · raw message
fs/nfs/pnfs.h +12 -0
@@ -133,14 +133,26 @@ struct pnfs_device {unsigned int layout_type;unsigned int mincount;struct page **pages; +void *area;unsigned int pgbase;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 void pnfs_unregister_layoutdriver (struct pnfs_layoutdriver_type *);/* 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,struct pnfs_device *dev);extern int nfs4_proc_layoutget (struct nfs4_layoutget *lgp);
include/linux/nfs4.h +1 -0
@@ -560,6 +560,7 @@ enum {NFSPROC4_CLNT_GET_LEASE_TIME ,NFSPROC4_CLNT_RECLAIM_COMPLETE ,NFSPROC4_CLNT_LAYOUTGET , +NFSPROC4_CLNT_GETDEVICELIST ,NFSPROC4_CLNT_GETDEVICEINFO ,NFSPROC4_CLNT_LAYOUTCOMMIT , NFSPROC4_CLNT_LAYOUTRETURN,
include/linux/nfs_xdr.h +11 -0
@@ -235,6 +235,17 @@ struct nfs4_layoutget {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 pnfs_device *pdev;struct nfs4_sequence_args seq_args;
Signature · 1 line
1.7.4.1
PATCH 2/33 pnfs: add set-clear layoutdriver interface
In reply to Jim ReesFrom: Benny Halevy <[email protected]>
To allow layout driver to issue getdevicelist at mount time, and clean up at umount time.
--- fs/nfs/client.c | 8 +++++--- fs/nfs/pnfs.c | 16 ++++++++++++++-- fs/nfs/pnfs.h | 8 ++++++-- 3 files changed, 25 insertions(+), 7 deletions(-)
fs/nfs/client.c +5 -3
@@ -906,7 +906,9 @@ error:/* * 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;
@@ -936,7 +938,7 @@ static void nfs_server_set_fsinfo(struct nfs_server *server, struct nfs_fsinfo *if (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 ; -set_pnfs_layoutdriver (server, fsinfo->layouttype); +set_pnfs_layoutdriver (server, mntfh, fsinfo->layouttype); server->wtmult =nfs_block_bits (fsinfo->wtmult,NULL );
@@ -982,7 +984,7 @@ static int nfs_probe_fsinfo(struct nfs_server *server, struct nfs_fh *mntfh, strif (error <0 ) goto out_error; -nfs_server_set_fsinfo (server, &fsinfo); +nfs_server_set_fsinfo (server, mntfh, &fsinfo);/* Get some general file system info */ if (server->namelen ==0 ) {
fs/nfs/pnfs.c +14 -2
@@ -75,8 +75,11 @@ find_pnfs_driver(u32 id)void 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); + } nfss->pnfs_curr_ld =NULL ; }
@@ -87,7 +90,8 @@ unset_pnfs_layoutdriver(struct nfs_server *nfss)* @id layout type. Zero (illegal layout type) indicates pNFS not in use. */ 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 ;
@@ -114,6 +118,14 @@ set_pnfs_layoutdriver(struct nfs_server *server, u32 id) goto out_no_driver; } server->pnfs_curr_ld = ld_type; +if (ld_type->set_layoutdriver + && ld_type->set_layoutdriver (server, mntfh)) { +printk (KERN_ERR +"%s: Error initializing mount point for 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);return ;
fs/nfs/pnfs.h +6 -2
@@ -80,6 +80,9 @@ struct pnfs_layoutdriver_type {struct module *owner;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);void (*free_layout_hdr) (struct pnfs_layout_hdr *);
@@ -165,7 +168,7 @@ void put_lseg(struct pnfs_layout_segment *lseg);bool pnfs_pageio_init_read (struct nfs_pageio_descriptor *,struct inode *);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 *);enum pnfs_try_status pnfs_try_to_write_data (struct nfs_write_data *,const struct rpc_call_ops *,int );
@@ -375,7 +378,8 @@ pnfs_roc_drain(struct inode *ino, u32 *barrier)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); { }
Signature · 1 line
1.7.4.1
PATCH 3/33 pnfs: let layoutcommit code handle multiple segments
In reply to Jim ReesFrom: Peng Tao <[email protected]>
Some layout driver like block will have multiple segments. Generic code should be able to handle it.
--- fs/nfs/pnfs.c | 18 ++++++++++++++---- fs/nfs/pnfs.h | 1 + 2 files changed, 15 insertions(+), 4 deletions(-)
fs/nfs/pnfs.c +14 -4
@@ -893,7 +893,7 @@ pnfs_find_lseg(struct pnfs_layout_hdr *lo,dprintk ("%s:Begin\n" , __func__);assert_spin_locked (&lo->plh_inode->i_lock); -list_for_each_entry (lseg, &lo->plh_segs, pls_list) { +list_for_each_entry_reverse (lseg, &lo->plh_segs, pls_list) {if (test_bit (NFS_LSEG_VALID , &lseg->pls_flags) &&is_matching_lseg (&lseg->pls_range, range)) { ret =get_lseg (lseg);
@@ -1243,10 +1243,19 @@ pnfs_try_to_read_data(struct nfs_read_data *rdata,static struct pnfs_layout_segment *pnfs_list_write_lseg (struct inode *inode) {struct pnfs_layout_segment *lseg, *rv =NULL ; +loff_t max_pos =0 ; + +list_for_each_entry (lseg, &NFS_I (inode)->layout->plh_segs, pls_list) { +if (lseg->pls_range.iomode ==IOMODE_RW ) { +if (max_pos < lseg->pls_end_pos) + max_pos = lseg->pls_end_pos; +if (test_and_clear_bit + (NFS_LSEG_LAYOUTCOMMIT , &lseg->pls_flags)) + rv = lseg; + } + } + rv->pls_end_pos = max_pos; -list_for_each_entry (lseg, &NFS_I (inode)->layout->plh_segs, pls_list) -if (lseg->pls_range.iomode ==IOMODE_RW ) - rv = lseg;return rv; }
@@ -1261,6 +1270,7 @@ pnfs_set_layoutcommit(struct nfs_write_data *wdata)if (!test_and_set_bit (NFS_INO_LAYOUTCOMMIT , &nfsi->flags)) {/* references matched in nfs4_layoutcommit_release */ get_lseg (wdata->lseg); +set_bit (NFS_LSEG_LAYOUTCOMMIT , &wdata->lseg->pls_flags); wdata->lseg->pls_lc_cred =get_rpccred (wdata->args.context->state->owner->so_cred); mark_as_dirty = true;
fs/nfs/pnfs.h +1 -0
@@ -36,6 +36,7 @@enum {NFS_LSEG_VALID =0 ,/* cleared when lseg is recalled/returned */ NFS_LSEG_ROC ,/* roc bit received from server */ +NFS_LSEG_LAYOUTCOMMIT ,/* layoutcommit bit set for layoutcommit */ };struct pnfs_layout_segment {
Signature · 1 line
1.7.4.1
PATCH 4/33 pnfs: hook nfs_write_begin/end to allow layout driver manipulation
In reply to Jim ReesFrom: Peng Tao <[email protected]>
--- fs/nfs/file.c | 26 ++++++++++- fs/nfs/pnfs.c | 41 +++++++++++++++++ fs/nfs/pnfs.h | 115 ++++++++++++++++++++++++++++++++++++++++++++++++ fs/nfs/write.c | 12 +++-- include/linux/nfs_fs.h | 3 +- 5 files changed, 189 insertions(+), 8 deletions(-)
fs/nfs/file.c +23 -3
@@ -384,12 +384,15 @@ static int nfs_write_begin(struct file *file, struct address_space *mapping,pgoff_t index = pos >>PAGE_CACHE_SHIFT ;struct page *page;int once_thru =0 ; +struct pnfs_layout_segment *lseg;dfprintk (PAGECACHE ,"NFS: write_begin(%s/%s(%ld), %u@%lld)\n" , file->f_path.dentry->d_parent->d_name.name, file->f_path.dentry->d_name.name, mapping->host->i_ino, len, (long long ) pos); - + lseg =pnfs_update_layout (mapping->host, +nfs_file_open_context (file), + pos, len,IOMODE_RW ,GFP_NOFS ); start:/* * Prevent starvation issues if someone is doing a consistency
@@ -409,6 +412,9 @@ start:if (ret) {unlock_page (page);page_cache_release (page); + *pagep =NULL ; + *fsdata =NULL ; + goto out; }else if (!once_thru &&nfs_want_read_modify_write (file, page, pos, len)) { once_thru =1 ;
@@ -417,6 +423,12 @@ start:if (!ret) goto start; } + ret =pnfs_write_begin (file, page, pos, len, lseg, fsdata); + out: +if (ret) { +put_lseg (lseg); + *fsdata =NULL ; + }return ret; }
@@ -426,6 +438,7 @@ static int nfs_write_end(struct file *file, struct address_space *mapping, {unsigned offset = pos & (PAGE_CACHE_SIZE -1 );int status; +struct pnfs_layout_segment *lseg; dfprintk(PAGECACHE, "NFS: write_end(%s/%s(%ld), %u@%lld)\n", file->f_path.dentry->d_parent->d_name.name,
@@ -452,10 +465,17 @@ static int nfs_write_end(struct file *file, struct address_space *mapping,zero_user_segment (page, pglen,PAGE_CACHE_SIZE ); } - status =nfs_updatepage (file, page, offset, copied); + lseg =nfs4_pull_lseg_from_fsdata (file, fsdata); + status =pnfs_write_end (file, page, pos, len, copied, lseg); +if (status) + goto out; + status =nfs_updatepage (file, page, offset, copied, lseg, fsdata); +out:unlock_page (page);page_cache_release (page); +pnfs_write_end_cleanup (file, fsdata); +put_lseg (lseg);if (status <0 )return status;
@@ -577,7 +597,7 @@ static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) ret =VM_FAULT_LOCKED ;if (nfs_flush_incompatible (filp, page) ==0 && -nfs_updatepage (filp, page,0 , pagelen) ==0 ) +nfs_updatepage (filp, page,0 , pagelen,NULL ,NULL ) ==0 ) goto out; ret =VM_FAULT_SIGBUS ;
fs/nfs/pnfs.c +41 -0
53 lines not on this page · raw message
fs/nfs/pnfs.h +115 -0
175 lines not on this page · raw message
fs/nfs/write.c +8 -4
@@ -673,7 +673,9 @@ out: }static int nfs_writepage_setup (struct nfs_open_context *ctx,struct page *page, -unsigned int offset,unsigned int count) +unsigned int offset,unsigned int count, +struct pnfs_layout_segment *lseg,void *fsdata) + {struct nfs_page *req;
@@ -681,7 +683,8 @@ static int nfs_writepage_setup(struct nfs_open_context *ctx, struct page *page,if (IS_ERR (req))return PTR_ERR (req);/* Update file length */ -nfs_grow_file (page, offset, count); +if (pnfs_grow_ok (lseg, fsdata)) +nfs_grow_file (page, offset, count);nfs_mark_uptodate (page, req->wb_pgbase, req->wb_bytes);nfs_mark_request_dirty (req);nfs_clear_page_tag_locked (req);
@@ -734,7 +737,8 @@ static int nfs_write_pageuptodate(struct page *page, struct inode *inode)* things with a page scheduled for an RPC call (e.g. invalidate it). */ int nfs_updatepage (struct file *file,struct page *page, -unsigned int offset,unsigned int count) +unsigned int offset,unsigned int count, +struct pnfs_layout_segment *lseg,void *fsdata) {struct nfs_open_context *ctx =nfs_file_open_context (file);struct inode *inode = page->mapping->host;
@@ -759,7 +763,7 @@ int nfs_updatepage(struct file *file, struct page *page, offset =0 ; } - status =nfs_writepage_setup (ctx, page, offset, count); + status =nfs_writepage_setup (ctx, page, offset, count, lseg, fsdata);if (status <0 )nfs_set_pageerror (page);
include/linux/nfs_fs.h +2 -1
@@ -510,7 +510,8 @@ extern int nfs_congestion_kb;extern int nfs_writepage (struct page *page,struct writeback_control *wbc);extern int nfs_writepages (struct address_space *,struct writeback_control *);extern int nfs_flush_incompatible (struct file *file,struct page *page); -extern int nfs_updatepage (struct file *,struct page *,unsigned int ,unsigned int ); +extern int nfs_updatepage (struct file *,struct page *,unsigned int , +unsigned int ,struct pnfs_layout_segment *,void *);extern void nfs_writeback_done (struct rpc_task *,struct nfs_write_data *);/*
Signature · 1 line
1.7.4.1
PATCH 5/33 pnfs: ask for layout_blksize and save it in nfs_server
In reply to Jim ReesFrom: Peng Tao <[email protected]>
Block layout needs it to determine IO size.
--- fs/nfs/client.c | 1 + fs/nfs/nfs4_fs.h | 2 +- fs/nfs/nfs4proc.c | 5 +- fs/nfs/nfs4xdr.c | 101 +++++++++++++++++++++++++++++++++++++-------- include/linux/nfs_fs_sb.h | 4 +- include/linux/nfs_xdr.h | 3 +- 6 files changed, 93 insertions(+), 23 deletions(-)
fs/nfs/client.c +1 -0
@@ -938,6 +938,7 @@ static void nfs_server_set_fsinfo(struct nfs_server *server,if (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->pnfs_blksize = fsinfo->blksize;set_pnfs_layoutdriver (server, mntfh, fsinfo->layouttype); server->wtmult =nfs_block_bits (fsinfo->wtmult,NULL );
fs/nfs/nfs4_fs.h +1 -1
@@ -315,7 +315,7 @@ extern const struct nfs4_minor_version_ops *nfs_v4_minor_ops[];extern const u32 nfs4_fattr_bitmap[2 ];extern const u32 nfs4_statfs_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 ];/* nfs4renewd.c */
fs/nfs/nfs4proc.c +3 -2
@@ -137,12 +137,13 @@ const u32 nfs4_pathconf_bitmap[2] = {0 }; -const u32 nfs4_fsinfo_bitmap[2 ] = {FATTR4_WORD0_MAXFILESIZE +const u32 nfs4_fsinfo_bitmap[3 ] = {FATTR4_WORD0_MAXFILESIZE |FATTR4_WORD0_MAXREAD |FATTR4_WORD0_MAXWRITE |FATTR4_WORD0_LEASE_TIME ,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 ] = {
fs/nfs/nfs4xdr.c +83 -18
205 lines not on this page · raw message
include/linux/nfs_fs_sb.h +3 -1
@@ -130,7 +130,7 @@ struct nfs_server {#endif #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 filesystem */ u32 cache_consistency_bitmask[2 ];
@@ -143,6 +143,8 @@ struct nfs_server {filesystem */ struct pnfs_layoutdriver_type *pnfs_curr_ld;/* Active layout driver */ struct rpc_wait_queue roc_rpcwaitq; +void *pnfs_ld_data;/* per mount point data */ +u32 pnfs_blksize;/* layout_blksize attr */ /* the following fields are protected by nfs_client->cl_lock */ struct rb_root state_owners;
include/linux/nfs_xdr.h +2 -1
@@ -122,6 +122,7 @@ struct nfs_fsinfo {struct timespec time_delta;/* server time granularity */ __u32 lease_time;/* in seconds */ __u32 layouttype;/* supported pnfs layout driver */ +__u32 blksize;/* preferred pnfs io block size */ };struct nfs_fsstat {
@@ -953,7 +954,7 @@ struct nfs4_server_caps_arg { };struct nfs4_server_caps_res { -u32 attr_bitmask[2 ]; +u32 attr_bitmask[3 ];u32 acl_bitmask;u32 has_links;u32 has_symlinks;
Signature · 1 line
1.7.4.1
PATCH 6/33 pnfs: cleanup_layoutcommit
In reply to Jim ReesFrom: Peng Tao <[email protected]>
This gives layout driver a chance to cleanup structures they put in. Also ensure layoutcommit does not commit more than isize, as block layout driver may dirty pages beyond EOF.
--- fs/nfs/nfs4proc.c | 1 + fs/nfs/nfs4xdr.c | 3 ++- fs/nfs/pnfs.c | 15 +++++++++++++++ fs/nfs/pnfs.h | 5 +++++ include/linux/nfs_xdr.h | 1 + 5 files changed, 24 insertions(+), 1 deletions(-)
fs/nfs/nfs4proc.c +1 -0
@@ -5887,6 +5887,7 @@ static void nfs4_layoutcommit_release(void *calldata) {struct nfs4_layoutcommit_data *data = calldata; +pnfs_cleanup_layoutcommit (data->args.inode, data);/* Matched by references in pnfs_set_layoutcommit */ put_lseg (data->lseg);put_rpccred (data->cred);
fs/nfs/nfs4xdr.c +2 -1
@@ -1963,7 +1963,7 @@ encode_layoutcommit(struct xdr_stream *xdr, *p++ =cpu_to_be32 (OP_LAYOUTCOMMIT );/* Only whole file layouts */ p =xdr_encode_hyper (p,0 );/* offset */ - p =xdr_encode_hyper (p,NFS4_MAX_UINT64 );/* length */ + p =xdr_encode_hyper (p, args->lastbytewritten+1 );/* length */ *p++ =cpu_to_be32 (0 );/* reclaim */ p =xdr_encode_opaque_fixed (p, args->stateid.data,NFS4_STATEID_SIZE ); *p++ =cpu_to_be32 (1 );/* newoffset = TRUE */
@@ -5469,6 +5469,7 @@ static int decode_layoutcommit(struct xdr_stream *xdr,int status; status =decode_op_hdr (xdr,OP_LAYOUTCOMMIT ); + res->status = status;if (status)return status;
fs/nfs/pnfs.c +15 -0
@@ -1299,6 +1299,7 @@ pnfs_set_layoutcommit(struct nfs_write_data *wdata) {struct nfs_inode *nfsi =NFS_I (wdata->inode);loff_t end_pos = wdata->mds_offset + wdata->res.count; +loff_t isize =i_size_read (wdata->inode);bool mark_as_dirty = false;spin_lock (&nfsi->vfs_inode.i_lock);
@@ -1312,9 +1313,13 @@ pnfs_set_layoutcommit(struct nfs_write_data *wdata)dprintk ("%s: Set layoutcommit for inode %lu " , __func__, wdata->inode->i_ino); } +if (end_pos > isize) + end_pos = isize;if (end_pos > wdata->lseg->pls_end_pos) wdata->lseg->pls_end_pos = end_pos;spin_unlock (&nfsi->vfs_inode.i_lock); +dprintk ("%s: lseg %p end_pos %llu\n" , + __func__, wdata->lseg, wdata->lseg->pls_end_pos);/* if pnfs_layoutcommit_inode() runs between inode locks, the next one * will be a noop because NFS_INO_LAYOUTCOMMIT will not be set */
@@ -1323,6 +1328,16 @@ pnfs_set_layoutcommit(struct nfs_write_data *wdata) }EXPORT_SYMBOL_GPL (pnfs_set_layoutcommit); +void pnfs_cleanup_layoutcommit (struct inode *inode, +struct nfs4_layoutcommit_data *data) +{ +struct nfs_server *nfss =NFS_SERVER (inode); + +if (nfss->pnfs_curr_ld->cleanup_layoutcommit) + nfss->pnfs_curr_ld->cleanup_layoutcommit (NFS_I (inode)->layout, + data); +} +void pnfs_free_fsdata (struct pnfs_fsdata *fsdata) {/* lseg refcounting handled directly in nfs_write_end */
fs/nfs/pnfs.h +5 -0
@@ -128,6 +128,9 @@ struct pnfs_layoutdriver_type {struct xdr_stream *xdr, const struct nfs4_layoutreturn_args *args); +void (*cleanup_layoutcommit) (struct pnfs_layout_hdr *layoutid, +struct nfs4_layoutcommit_data *data); +void (*encode_layoutcommit) (struct pnfs_layout_hdr *layoutid,struct xdr_stream *xdr,const struct nfs4_layoutcommit_args *args);
@@ -216,6 +219,8 @@ void pnfs_roc_release(struct inode *ino);void pnfs_roc_set_barrier (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_cleanup_layoutcommit (struct inode *inode, +struct nfs4_layoutcommit_data *data);int pnfs_layoutcommit_inode (struct inode *inode,bool sync);int _pnfs_return_layout (struct inode *);int pnfs_ld_write_done (struct nfs_write_data *);
include/linux/nfs_xdr.h +1 -0
@@ -269,6 +269,7 @@ struct nfs4_layoutcommit_res {struct nfs_fattr *fattr;const struct nfs_server *server;struct nfs4_sequence_res seq_res; +int status; };struct nfs4_layoutcommit_data {
Signature · 1 line
1.7.4.1
PATCH 7/33 pnfsblock: define PNFS_BLOCK Kconfig option
In reply to Jim ReesFrom: Fred Isaman <[email protected]>
Define a configuration variable to enable/disable compilation of the block driver code.
--- fs/nfs/Kconfig | 10 ++++++++++ fs/nfs/Makefile | 1 + fs/nfs/blocklayout/Makefile | 5 +++++ 3 files changed, 16 insertions(+), 0 deletions(-) create mode 100644 fs/nfs/blocklayout/Makefile
fs/nfs/Kconfig +10 -0
@@ -97,6 +97,16 @@ config PNFS_OBJLAYOUT If unsure, say N. +config PNFS_BLOCK + tristate "Provide a pNFS block client (EXPERIMENTAL)" + depends on NFS_FS && NFS_V4_1 + select MD + select BLK_DEV_DM + help + Say M or y here if you want your pNfs client to support the block protocol + + If unsure, say N. + config ROOT_NFS bool "Root file system on NFS" depends on NFS_FS=y && IP_PNP
fs/nfs/Makefile +1 -0
@@ -23,3 +23,4 @@ obj-$(CONFIG_PNFS_FILE_LAYOUT) += nfs_layout_nfsv41_files.o nfs_layout_nfsv41_files-y := nfs4filelayout.o nfs4filelayoutdev.o obj-$(CONFIG_PNFS_OBJLAYOUT) += objlayout/ +obj-$(CONFIG_PNFS_BLOCK) += blocklayout/
fs/nfs/blocklayout/Makefile new file +5 -0
@@ -0,0 +1,5 @@ +# +# Makefile for the pNFS block layout driver kernel module +# +obj-$(CONFIG_PNFS_BLOCK) += +blocklayoutdriver-objs :=
Signature · 1 line
1.7.4.1
PATCH 8/33 pnfsblock: blocklayout stub
In reply to Jim ReesFrom: Fred Isaman <[email protected]>
Adds the minimal structure for a pnfs block layout driver, with all function pointers aimed at stubs.
--- fs/nfs/blocklayout/Makefile | 4 +- fs/nfs/blocklayout/blocklayout.c | 166 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 168 insertions(+), 2 deletions(-) create mode 100644 fs/nfs/blocklayout/blocklayout.c
fs/nfs/blocklayout/Makefile +2 -2
@@ -1,5 +1,5 @@ # # Makefile for the pNFS block layout driver kernel module # -obj-$(CONFIG_PNFS_BLOCK) += -blocklayoutdriver-objs := +obj-$(CONFIG_PNFS_BLOCK) += blocklayoutdriver.o +blocklayoutdriver-objs := blocklayout.o
fs/nfs/blocklayout/blocklayout.c new file +166 -0
166 lines not on this page · raw message
Signature · 1 line
1.7.4.1
PATCH 9/33 pnfsblock: layout alloc and free
In reply to Jim ReesFrom: Fred Isaman <[email protected]>
Allocate the empty list-heads that will hold all the extent data for the layout.
--- fs/nfs/blocklayout/blocklayout.c | 44 ++++++++++++++++-- fs/nfs/blocklayout/blocklayout.h | 90 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 129 insertions(+), 5 deletions(-) create mode 100644 fs/nfs/blocklayout/blocklayout.h
fs/nfs/blocklayout/blocklayout.c +39 -5
@@ -32,7 +32,7 @@#include <linux/module.h> #include <linux/init.h> -#include "../pnfs.h" +#include "blocklayout.h" #define NFSDBG_FACILITY NFSDBG_PNFS_LD
@@ -53,15 +53,49 @@ bl_write_pagelist(struct nfs_write_data *wdata,return PNFS_NOT_ATTEMPTED ; } +/* STUB */ static void -bl_free_layout_hdr (struct pnfs_layout_hdr *lo) +release_extents (struct pnfs_block_layout *bl, +struct pnfs_layout_range *range) { +return ; } -static struct pnfs_layout_hdr * -bl_alloc_layout_hdr (struct inode *inode,gfp_t gfp_flags) +/* STUB */ +static void +release_inval_marks (struct pnfs_inval_markings *marks) { -return NULL ; +return ; +} + +static void bl_free_layout_hdr (struct pnfs_layout_hdr *lo) +{ +struct pnfs_block_layout *bl =BLK_LO2EXT (lo); + +dprintk ("%s enter\n" , __func__); +release_extents (bl,NULL ); +release_inval_marks (&bl->bl_inval); +kfree (bl); +} + +static struct pnfs_layout_hdr *bl_alloc_layout_hdr (struct inode *inode, +gfp_t gfp_flags) +{ +struct pnfs_block_layout *bl; + +dprintk ("%s enter\n" , __func__); + bl =kzalloc (sizeof (*bl), gfp_flags); +if (!bl) +return NULL ; +spin_lock_init (&bl->bl_ext_lock); +INIT_LIST_HEAD (&bl->bl_extents[0 ]); +INIT_LIST_HEAD (&bl->bl_extents[1 ]); +INIT_LIST_HEAD (&bl->bl_commit); +INIT_LIST_HEAD (&bl->bl_committing); + bl->bl_count =0 ; + bl->bl_blocksize =NFS_SERVER (inode)->pnfs_blksize >>9 ; +INIT_INVAL_MARKS (&bl->bl_inval, bl->bl_blocksize); +return &bl->bl_layout; } static void
fs/nfs/blocklayout/blocklayout.h new file +90 -0
90 lines not on this page · raw message
Signature · 1 line
1.7.4.1
PATCH 10/33 pnfsblock: add support for simple rpc pipefs
In reply to Jim ReesFrom: Fred Isaman <[email protected]>
move include lines out of include file
--- include/linux/sunrpc/simple_rpc_pipefs.h | 105 ++++++++ net/sunrpc/simple_rpc_pipefs.c | 423 ++++++++++++++++++++++++++++++ 2 files changed, 528 insertions(+), 0 deletions(-) create mode 100644 include/linux/sunrpc/simple_rpc_pipefs.h create mode 100644 net/sunrpc/simple_rpc_pipefs.c
include/linux/sunrpc/simple_rpc_pipefs.h new file +105 -0
@@ -0,0 +1,105 @@ +/* +* Copyright (c) 2008 The Regents of the University of Michigan. +* All rights reserved. +* +* David M. Richter <[email protected]> +* +* Drawing on work done by Andy Adamson <[email protected]> and +* Marius Eriksen <[email protected]>. Thanks for the help over the +* years, guys. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* 3. Neither the name of the University nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +* With thanks to CITI's project sponsor and partner, IBM. +*/ + +#ifndef _SIMPLE_RPC_PIPEFS_H_ +#define _SIMPLE_RPC_PIPEFS_H_ + +#include <linux/sunrpc/rpc_pipe_fs.h> + +#define payload_of (headerp) ((void *)(headerp + 1)) + +/* +* struct pipefs_hdr -- the generic message format for simple_rpc_pipefs. +* Messages may simply be the header itself, although having an optional +* data payload follow the header allows much more flexibility. +* +* Messages are created using pipefs_alloc_init_msg() and +* pipefs_alloc_init_msg_padded(), both of which accept a pointer to an +* (optional) data payload. +* +* Given a struct pipefs_hdr *msg that has a struct foo payload, the data +* can be accessed using: struct foo *foop = payload_of(msg) +*/ +struct pipefs_hdr { +u32 msgid; +u8 type; +u8 flags; +u16 totallen;/* length of entire message, including hdr itself */ +u32 status; +}; + +/* +* struct pipefs_list -- a type of list used for tracking callers who've made an +* upcall and are blocked waiting for a reply. +* +* See pipefs_queue_upcall_waitreply() and pipefs_assign_upcall_reply(). +*/ +struct pipefs_list { +struct list_head list; +spinlock_t list_lock; +}; + + +/* See net/sunrpc/simple_rpc_pipefs.c for more info on using these functions. */ +extern struct dentry *pipefs_mkpipe (const char *name, +const struct rpc_pipe_ops *ops, +int wait_for_open); +extern void pipefs_closepipe (struct dentry *pipe); +extern void pipefs_init_list (struct pipefs_list *list); +extern struct pipefs_hdr *pipefs_alloc_init_msg (u32 msgid,u8 type,u8 flags, +void *data,u16 datalen); +extern struct pipefs_hdr *pipefs_alloc_init_msg_padded (u32 msgid,u8 type, +u8 flags,void *data, +u16 datalen,u16 padlen); +extern struct pipefs_hdr *pipefs_queue_upcall_waitreply (struct dentry *pipe, +struct pipefs_hdr *msg, +struct pipefs_list + *uplist,u8 upflags, +u32 timeout); +extern int pipefs_queue_upcall_noreply (struct dentry *pipe, +struct pipefs_hdr *msg,u8 upflags); +extern int pipefs_assign_upcall_reply (struct pipefs_hdr *reply, +struct pipefs_list *uplist); +extern struct pipefs_hdr *pipefs_readmsg (struct file *filp, +const char __user *src,size_t len); +extern ssize_t pipefs_generic_upcall (struct file *filp, +struct rpc_pipe_msg *rpcmsg, +char __user *dst,size_t buflen); +extern void pipefs_generic_destroy_msg (struct rpc_pipe_msg *rpcmsg); + +#endif /* _SIMPLE_RPC_PIPEFS_H_ */
net/sunrpc/simple_rpc_pipefs.c new file +423 -0
423 lines not on this page · raw message
Signature · 1 line
1.7.4.1
Re: [PATCH 10/33] pnfsblock: add support for simple rpc pipefs
Quoted 10 lines · Jim Rees
From: Fred Isaman <[email protected]>
Signed-off-by Eric Anderle <[email protected]>Signed-off-by Jim Rees <[email protected]>Signed-off-by Benny Halevy <[email protected]>move include lines out of include file
Signed-off-by Jim Rees <[email protected]>[This patch does *not* break the header's independence]Signed-off-by Boaz Harrosh <[email protected]>Signed-off-by Benny Halevy <[email protected]>
Quoted 6 lines
--- include/linux/sunrpc/simple_rpc_pipefs.h | 105 ++++++++ net/sunrpc/simple_rpc_pipefs.c | 423 ++++++++++++++++++++++++++++++ 2 files changed, 528 insertions(+), 0 deletions(-) create mode 100644 include/linux/sunrpc/simple_rpc_pipefs.h create mode 100644 net/sunrpc/simple_rpc_pipefs.c
what happnened to this hunk?
net/sunrpc/Makefile +1 -1
@@ -12,7 +12,7 @@ sunrpc-y := clnt.o xprt.o socklib.o xprtsock.o sched.o \ svc.o svcsock.o svcauth.o svcauth_unix.o \ addr.o rpcb_clnt.o timer.o xdr.o \ sunrpc_syms.o cache.o rpc_pipe.o \ - svc_xprt.o + svc_xprt.o simple_rpc_pipefs.o sunrpc-$(CONFIG_NFS_V4_1) += backchannel_rqst.o bc_svc.o sunrpc-$(CONFIG_PROC_FS) += stats.o sunrpc-$(CONFIG_SYSCTL) += sysctl.o
Benny
Quoted 541 lines
include/linux/sunrpc/simple_rpc_pipefs.h new file +105
-0@@ -0,0 +1,105 @@ +/* +* Copyright (c) 2008 The Regents of the University of Michigan. +* All rights reserved. +* +* David M. Richter <[email protected]> +* +* Drawing on work done by Andy Adamson <[email protected]> and +* Marius Eriksen <[email protected]>. Thanks for the help over the +* years, guys. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* 3. Neither the name of the University nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +* With thanks to CITI's project sponsor and partner, IBM. +*/ + +#ifndef _SIMPLE_RPC_PIPEFS_H_ +#define _SIMPLE_RPC_PIPEFS_H_ + +#include <linux/sunrpc/rpc_pipe_fs.h> + +#define payload_of (headerp) ((void *)(headerp + 1)) + +/* +* struct pipefs_hdr -- the generic message format for simple_rpc_pipefs. +* Messages may simply be the header itself, although having an optional +* data payload follow the header allows much more flexibility. +* +* Messages are created using pipefs_alloc_init_msg() and +* pipefs_alloc_init_msg_padded(), both of which accept a pointer to an +* (optional) data payload. +* +* Given a struct pipefs_hdr *msg that has a struct foo payload, the data +* can be accessed using: struct foo *foop = payload_of(msg) +*/ +struct pipefs_hdr { +u32 msgid; +u8 type; +u8 flags; +u16 totallen;/* length of entire message, including hdr itself */ +u32 status; +}; + +/* +* struct pipefs_list -- a type of list used for tracking callers who've made an +* upcall and are blocked waiting for a reply. +* +* See pipefs_queue_upcall_waitreply() and pipefs_assign_upcall_reply(). +*/ +struct pipefs_list { +struct list_head list; +spinlock_t list_lock; +}; + + +/* See net/sunrpc/simple_rpc_pipefs.c for more info on using these functions. */ +extern struct dentry *pipefs_mkpipe (const char *name, +const struct rpc_pipe_ops *ops, +int wait_for_open); +extern void pipefs_closepipe (struct dentry *pipe); +extern void pipefs_init_list (struct pipefs_list *list); +extern struct pipefs_hdr *pipefs_alloc_init_msg (u32 msgid,u8 type,u8 flags, +void *data,u16 datalen); +extern struct pipefs_hdr *pipefs_alloc_init_msg_padded (u32 msgid,u8 type, +u8 flags,void *data, +u16 datalen,u16 padlen); +extern struct pipefs_hdr *pipefs_queue_upcall_waitreply (struct dentry *pipe, +struct pipefs_hdr *msg, +struct pipefs_list + *uplist,u8 upflags, +u32 timeout); +extern int pipefs_queue_upcall_noreply (struct dentry *pipe, +struct pipefs_hdr *msg,u8 upflags); +extern int pipefs_assign_upcall_reply (struct pipefs_hdr *reply, +struct pipefs_list *uplist); +extern struct pipefs_hdr *pipefs_readmsg (struct file *filp, +const char __user *src,size_t len); +extern ssize_t pipefs_generic_upcall (struct file *filp, +struct rpc_pipe_msg *rpcmsg, +char __user *dst,size_t buflen); +extern void pipefs_generic_destroy_msg (struct rpc_pipe_msg *rpcmsg); + +#endif /* _SIMPLE_RPC_PIPEFS_H_ */ net/sunrpc/simple_rpc_pipefs.c new file +423
-0@@ -0,0 +1,423 @@ +/* +* net/sunrpc/simple_rpc_pipefs.c +* +* Copyright (c) 2008 The Regents of the University of Michigan. +* All rights reserved. +* +* David M. Richter <[email protected]> +* +* Drawing on work done by Andy Adamson <[email protected]> and +* Marius Eriksen <[email protected]>. Thanks for the help over the +* years, guys. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* 3. Neither the name of the University nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +* With thanks to CITI's project sponsor and partner, IBM. +*/ + +#include <linux/mount.h> +#include <linux/sunrpc/clnt.h> +#include <linux/sunrpc/simple_rpc_pipefs.h> + + +/* +* Make an rpc_pipefs pipe named @name at the root of the mounted rpc_pipefs +* filesystem. +* +* If @wait_for_open is non-zero and an upcall is later queued but the userland +* end of the pipe has not yet been opened, the upcall will remain queued until +* the pipe is opened; otherwise, the upcall queueing will return with -EPIPE. +*/ +struct dentry *pipefs_mkpipe (const char *name,const struct rpc_pipe_ops *ops, +int wait_for_open) +{ +struct dentry *dir, *pipe; +struct vfsmount *mnt; + + mnt =rpc_get_mount (); +if (IS_ERR (mnt)) { + pipe =ERR_CAST (mnt); + goto out; + } + dir = mnt->mnt_root; +if (!dir) { + pipe =ERR_PTR (-ENOENT ); + goto out; + } + pipe =rpc_mkpipe (dir, name,NULL , ops, + wait_for_open ?RPC_PIPE_WAIT_FOR_OPEN :0 ); +out: +return pipe; +} +EXPORT_SYMBOL (pipefs_mkpipe); + +/* +* Shutdown a pipe made by pipefs_mkpipe(). +* XXX: do we need to retain an extra reference on the mount? +*/ +void pipefs_closepipe (struct dentry *pipe) +{ +rpc_unlink (pipe); +rpc_put_mount (); +} +EXPORT_SYMBOL (pipefs_closepipe); + +/* +* Initialize a struct pipefs_list -- which are a way to keep track of callers +* who're blocked having made an upcall and are awaiting a reply. +* +* See pipefs_queue_upcall_waitreply() and pipefs_find_upcall_msgid() for how +* to use them. +*/ +inline void pipefs_init_list (struct pipefs_list *list) +{ +INIT_LIST_HEAD (&list->list); +spin_lock_init (&list->list_lock); +} +EXPORT_SYMBOL (pipefs_init_list); + +/* +* Alloc/init a generic pipefs message header and copy into its message body +* an arbitrary data payload. +* +* struct pipefs_hdr's are meant to serve as generic, general-purpose message +* headers for easy rpc_pipefs I/O. When an upcall is made, the +* struct pipefs_hdr is assigned to a struct rpc_pipe_msg and delivered +* therein. --And yes, the naming can seem a little confusing at first: +* +* When one thinks of an upcall "message", in simple_rpc_pipefs that's a +* struct pipefs_hdr (possibly with an attached message body). A +* struct rpc_pipe_msg is actually only the -vehicle- by which the "real" +* message is delivered and processed. +*/ +struct pipefs_hdr *pipefs_alloc_init_msg_padded (u32 msgid,u8 type,u8 flags, +void *data,u16 datalen,u16 padlen) +{ +u16 totallen; +struct pipefs_hdr *msg =NULL ; + + totallen =sizeof (*msg) + datalen + padlen; +if (totallen >PAGE_SIZE ) { + msg =ERR_PTR (-E2BIG ); + goto out; + } + + msg =kzalloc (totallen,GFP_KERNEL ); +if (!msg) { + msg =ERR_PTR (-ENOMEM ); + goto out; + } + + msg->msgid = msgid; + msg->type = type; + msg->flags = flags; + msg->totallen = totallen; +memcpy (payload_of (msg), data, datalen); +out: +return msg; +} +EXPORT_SYMBOL (pipefs_alloc_init_msg_padded); + +/* +* See the description of pipefs_alloc_init_msg_padded(). +*/ +struct pipefs_hdr *pipefs_alloc_init_msg (u32 msgid,u8 type,u8 flags, +void *data,u16 datalen) +{ +return pipefs_alloc_init_msg_padded (msgid, type, flags, data, + datalen,0 ); +} +EXPORT_SYMBOL (pipefs_alloc_init_msg); + + +static void pipefs_init_rpcmsg (struct rpc_pipe_msg *rpcmsg, +struct pipefs_hdr *msg,u8 upflags) +{ +memset (rpcmsg,0 ,sizeof (*rpcmsg)); + rpcmsg->data = msg; + rpcmsg->len = msg->totallen; + rpcmsg->flags = upflags; +} + +static struct rpc_pipe_msg *pipefs_alloc_init_rpcmsg (struct pipefs_hdr *msg, +u8 upflags) +{ +struct rpc_pipe_msg *rpcmsg; + + rpcmsg =kmalloc (sizeof (*rpcmsg),GFP_KERNEL ); +if (!rpcmsg) +return ERR_PTR (-ENOMEM ); + +pipefs_init_rpcmsg (rpcmsg, msg, upflags); +return rpcmsg; +} + + +/* represents an upcall that'll block and wait for a reply */ +struct pipefs_upcall { +u32 msgid; +struct rpc_pipe_msg rpcmsg; +struct list_head list; +wait_queue_head_t waitq; +struct pipefs_hdr *reply; +}; + + +static void pipefs_init_upcall_waitreply (struct pipefs_upcall *upcall, +struct pipefs_hdr *msg,u8 upflags) +{ + upcall->reply =NULL ; + upcall->msgid = msg->msgid; +INIT_LIST_HEAD (&upcall->list); +init_waitqueue_head (&upcall->waitq); +pipefs_init_rpcmsg (&upcall->rpcmsg, msg, upflags); +} + +static int __pipefs_queue_upcall_waitreply (struct dentry *pipe, +struct pipefs_upcall *upcall, +struct pipefs_list *uplist, +u32 timeout) +{ +int err =0 ; +DECLARE_WAITQUEUE (wq, current); + +add_wait_queue (&upcall->waitq, &wq); +spin_lock (&uplist->list_lock); +list_add (&upcall->list, &uplist->list); +spin_unlock (&uplist->list_lock); + + err =rpc_queue_upcall (pipe->d_inode, &upcall->rpcmsg); +if (err <0 ) + goto out; + +if (timeout) { +/* retval of 0 means timer expired */ + err =schedule_timeout_uninterruptible (timeout); +if (err ==0 && upcall->reply ==NULL ) + err = -ETIMEDOUT ; + }else { +set_current_state (TASK_UNINTERRUPTIBLE ); +schedule (); +__set_current_state (TASK_RUNNING ); + } + +out: +spin_lock (&uplist->list_lock); +list_del_init (&upcall->list); +spin_unlock (&uplist->list_lock); +remove_wait_queue (&upcall->waitq, &wq); +return err; +} + +/* +* Queue a pipefs msg for an upcall to userspace, place the calling thread +* on @uplist, and block the thread to wait for a reply. If @timeout is +* nonzero, the thread will be blocked for at most @timeout jiffies. +* +* (To convert time units into jiffies, consider the functions +* msecs_to_jiffies(), usecs_to_jiffies(), timeval_to_jiffies(), and +* timespec_to_jiffies().) +* +* Once a reply is received by your downcall handler, call +* pipefs_assign_upcall_reply() with @uplist to find the corresponding upcall, +* assign the reply, and wake the waiting thread. +* +* This function's return value pointer may be an error and should be checked +* with IS_ERR() before attempting to access the reply message. +* +* Callers are responsible for freeing @msg, unless pipefs_generic_destroy_msg() +* is used as the ->destroy_msg() callback and the PIPEFS_AUTOFREE_UPCALL_MSG +* flag is set in @upflags. See also rpc_pipe_fs.h. +*/ +struct pipefs_hdr *pipefs_queue_upcall_waitreply (struct dentry *pipe, +struct pipefs_hdr *msg, +struct pipefs_list *uplist, +u8 upflags,u32 timeout) +{ +int err =0 ; +struct pipefs_upcall upcall; + +pipefs_init_upcall_waitreply (&upcall, msg, upflags); + err =__pipefs_queue_upcall_waitreply (pipe, &upcall, uplist, timeout); +if (err <0 ) { +kfree (upcall.reply); + upcall.reply =ERR_PTR (err); + } + +return upcall.reply; +} +EXPORT_SYMBOL (pipefs_queue_upcall_waitreply); + +/* +* Queue a pipefs msg for an upcall to userspace and immediately return (i.e., +* no reply is expected). +* +* Callers are responsible for freeing @msg, unless pipefs_generic_destroy_msg() +* is used as the ->destroy_msg() callback and the PIPEFS_AUTOFREE_UPCALL_MSG +* flag is set in @upflags. See also rpc_pipe_fs.h. +*/ +int pipefs_queue_upcall_noreply (struct dentry *pipe,struct pipefs_hdr *msg, +u8 upflags) +{ +int err =0 ; +struct rpc_pipe_msg *rpcmsg; + + upflags |=PIPEFS_AUTOFREE_RPCMSG ; + rpcmsg =pipefs_alloc_init_rpcmsg (msg, upflags); +if (IS_ERR (rpcmsg)) { + err =PTR_ERR (rpcmsg); + goto out; + } + err =rpc_queue_upcall (pipe->d_inode, rpcmsg); +out: +return err; +} +EXPORT_SYMBOL (pipefs_queue_upcall_noreply); + + +static struct pipefs_upcall *pipefs_find_upcall_msgid (u32 msgid, +struct pipefs_list *uplist) +{ +struct pipefs_upcall *upcall; + +spin_lock (&uplist->list_lock); +list_for_each_entry (upcall, &uplist->list, list) +if (upcall->msgid == msgid) + goto out; + upcall =NULL ; +out: +spin_unlock (&uplist->list_lock); +return upcall; +} + +/* +* In your rpc_pipe_ops->downcall() handler, once you've read in a downcall +* message and have determined that it is a reply to a waiting upcall, +* you can use this function to find the appropriate upcall, assign the result, +* and wake the upcall thread. +* +* The reply message must have the same msgid as the original upcall message's. +* +* See also pipefs_queue_upcall_waitreply() and pipefs_readmsg(). +*/ +int pipefs_assign_upcall_reply (struct pipefs_hdr *reply, +struct pipefs_list *uplist) +{ +int err =0 ; +struct pipefs_upcall *upcall; + + upcall =pipefs_find_upcall_msgid (reply->msgid, uplist); +if (!upcall) { +printk (KERN_ERR "%s: ERROR: have reply but no matching upcall " +"for msgid %d\n" , __func__, reply->msgid); + err = -ENOENT ; + goto out; + } + upcall->reply = reply; +wake_up (&upcall->waitq); +out: +return err; +} +EXPORT_SYMBOL (pipefs_assign_upcall_reply); + +/* +* Generic method to read-in and return a newly-allocated message which begins +* with a struct pipefs_hdr. +*/ +struct pipefs_hdr *pipefs_readmsg (struct file *filp,const char __user *src, +size_t len) +{ +int err =0 , hdrsize; +struct pipefs_hdr *msg =NULL ; + + hdrsize =sizeof (*msg); +if (len < hdrsize) { +printk (KERN_ERR "%s: ERROR: header is too short (%d vs %d)\n" , + __func__, (int ) len, hdrsize); + err = -EINVAL ; + goto out; + } + + msg =kzalloc (len,GFP_KERNEL ); +if (!msg) { + err = -ENOMEM ; + goto out; + } +if (copy_from_user (msg, src, len)) + err = -EFAULT ; +out: +if (err) { +kfree (msg); + msg =ERR_PTR (err); + } +return msg; +} +EXPORT_SYMBOL (pipefs_readmsg); + +/* +* Generic rpc_pipe_ops->upcall() handler implementation. +* +* Don't call this directly: to make an upcall, use +* pipefs_queue_upcall_waitreply() or pipefs_queue_upcall_noreply(). +*/ +ssize_t pipefs_generic_upcall (struct file *filp,struct rpc_pipe_msg *rpcmsg, +char __user *dst,size_t buflen) +{ +char *data; +ssize_t len, left; + + data = (char *)rpcmsg->data + rpcmsg->copied; + len = rpcmsg->len - rpcmsg->copied; +if (len > buflen) + len = buflen; + + left =copy_to_user (dst, data, len); +if (left <0 ) { + rpcmsg->errno = left; +return left; + } + + len -= left; + rpcmsg->copied += len; + rpcmsg->errno =0 ; +return len; +} +EXPORT_SYMBOL (pipefs_generic_upcall); + +/* +* Generic rpc_pipe_ops->destroy_msg() handler implementation. +* +* Items are only freed if @rpcmsg->flags has been set appropriately. +* See pipefs_queue_upcall_noreply() and rpc_pipe_fs.h. +*/ +void pipefs_generic_destroy_msg (struct rpc_pipe_msg *rpcmsg) +{ +if (rpcmsg->flags &PIPEFS_AUTOFREE_UPCALL_MSG ) +kfree (rpcmsg->data); +if (rpcmsg->flags &PIPEFS_AUTOFREE_RPCMSG ) +kfree (rpcmsg); +} +EXPORT_SYMBOL (pipefs_generic_destroy_msg);
PATCH 11/33 pnfsblock: add block device discovery pipe
In reply to Jim Rees--- fs/nfs/blocklayout/Makefile | 2 +- fs/nfs/blocklayout/block-device-discovery-pipe.c | 66 ++++++++++++++++++++++ fs/nfs/blocklayout/blocklayout.c | 3 + fs/nfs/blocklayout/blocklayout.h | 14 +++++ 4 files changed, 84 insertions(+), 1 deletions(-) create mode 100644 fs/nfs/blocklayout/block-device-discovery-pipe.c
fs/nfs/blocklayout/Makefile +1 -1
@@ -2,4 +2,4 @@ # Makefile for the pNFS block layout driver kernel module # obj-$(CONFIG_PNFS_BLOCK) += blocklayoutdriver.o -blocklayoutdriver-objs := blocklayout.o +blocklayoutdriver-objs := blocklayout.o block-device-discovery-pipe.o
fs/nfs/blocklayout/block-device-discovery-pipe.c new file +66 -0
66 lines not on this page · raw message
fs/nfs/blocklayout/blocklayout.c +3 -0
@@ -185,6 +185,8 @@ static int __init nfs4blocklayout_init(void)dprintk ("%s: NFSv4 Block Layout Driver Registering...\n" , __func__); ret =pnfs_register_layoutdriver (&blocklayout_type); +if (!ret) +bl_pipe_init ();return ret; }
@@ -194,6 +196,7 @@ static void __exit nfs4blocklayout_exit(void) __func__);pnfs_unregister_layoutdriver (&blocklayout_type); +bl_pipe_exit (); }module_init (nfs4blocklayout_init);
fs/nfs/blocklayout/blocklayout.h +14 -0
@@ -87,4 +87,18 @@ static inline struct pnfs_block_layout *BLK_LO2EXT(struct pnfs_layout_hdr *lo) return container_of(lo, struct pnfs_block_layout, bl_layout); } +#include <linux/sunrpc/simple_rpc_pipefs.h> + +extern struct pipefs_list bl_device_list; +extern struct dentry *bl_device_pipe; + +int bl_pipe_init (void ); +void bl_pipe_exit (void ); + +#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 */ +#endif /* FS_NFS_NFS4BLOCKLAYOUT_H */
Signature · 1 line
1.7.4.1
PATCH 12/33 pnfsblock: basic extent code
In reply to Jim ReesFrom: Fred Isaman <[email protected]>
Adds structures and basic create/delete code for extents.
--- fs/nfs/blocklayout/Makefile | 2 +- fs/nfs/blocklayout/blocklayout.c | 20 ++++++-- fs/nfs/blocklayout/blocklayout.h | 1 + fs/nfs/blocklayout/extents.c | 97 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 115 insertions(+), 5 deletions(-) create mode 100644 fs/nfs/blocklayout/extents.c
fs/nfs/blocklayout/Makefile +1 -1
@@ -2,4 +2,4 @@ # Makefile for the pNFS block layout driver kernel module # obj-$(CONFIG_PNFS_BLOCK) += blocklayoutdriver.o -blocklayoutdriver-objs := blocklayout.o block-device-discovery-pipe.o +blocklayoutdriver-objs := blocklayout.o block-device-discovery-pipe.o extents.o
fs/nfs/blocklayout/blocklayout.c +17 -5
@@ -53,12 +53,24 @@ bl_write_pagelist(struct nfs_write_data *wdata,return PNFS_NOT_ATTEMPTED ; } -/* STUB */ +/* FIXME - range ignored */ static void -release_extents (struct pnfs_block_layout *bl, -struct pnfs_layout_range *range) -{ -return ; +release_extents (struct pnfs_block_layout *bl,struct pnfs_layout_range *range) +{ +int i; +struct pnfs_block_extent *be; + +spin_lock (&bl->bl_ext_lock); +for (i =0 ; i <EXTENT_LISTS ; i++) { +while (!list_empty (&bl->bl_extents[i])) { + be =list_first_entry (&bl->bl_extents[i], + struct pnfs_block_extent, + be_node); +list_del (&be->be_node); +put_extent (be); + } + } +spin_unlock (&bl->bl_ext_lock); }/* STUB */
fs/nfs/blocklayout/blocklayout.h +1 -0
@@ -101,4 +101,5 @@ void bl_pipe_exit(void);#define BL_DEVICE_REQUEST_PROC 0x1/* User level process succeeds */ #define BL_DEVICE_REQUEST_ERR 0x2/* User level process fails */ +void put_extent (struct pnfs_block_extent *be);#endif /* FS_NFS_NFS4BLOCKLAYOUT_H */
fs/nfs/blocklayout/extents.c new file +97 -0
97 lines not on this page · raw message
Signature · 1 line
1.7.4.1
PATCH 13/33 pnfsblock: add device operations
In reply to Jim Rees--- fs/nfs/blocklayout/Makefile | 2 +- fs/nfs/blocklayout/blocklayout.h | 15 ++++ fs/nfs/blocklayout/blocklayoutdev.c | 151 +++++++++++++++++++++++++++++++++++ 3 files changed, 167 insertions(+), 1 deletions(-) create mode 100644 fs/nfs/blocklayout/blocklayoutdev.c
fs/nfs/blocklayout/Makefile +1 -1
@@ -2,4 +2,4 @@ # Makefile for the pNFS block layout driver kernel module # obj-$(CONFIG_PNFS_BLOCK) += blocklayoutdriver.o -blocklayoutdriver-objs := blocklayout.o block-device-discovery-pipe.o extents.o +blocklayoutdriver-objs := blocklayout.o block-device-discovery-pipe.o extents.o blocklayoutdev.o
fs/nfs/blocklayout/blocklayout.h +15 -0
@@ -35,6 +35,12 @@#include <linux/nfs_fs.h> #include "../pnfs.h" +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 ,
@@ -87,6 +93,15 @@ static inline struct pnfs_block_layout *BLK_LO2EXT(struct pnfs_layout_hdr *lo) return container_of(lo, struct pnfs_block_layout, bl_layout); } +/* blocklayoutdev.c */ +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, +struct list_head *sdlist); +int nfs4_blk_process_layoutget (struct pnfs_layout_hdr *lo, +struct nfs4_layoutget_res *lgr,gfp_t gfp_flags); +#include <linux/sunrpc/simple_rpc_pipefs.h> extern struct pipefs_list bl_device_list;
fs/nfs/blocklayout/blocklayoutdev.c new file +151 -0
151 lines not on this page · raw message
Signature · 1 line
1.7.4.1
PATCH 14/33 pnfsblock: remove device operations
In reply to Jim Rees--- fs/nfs/blocklayout/Makefile | 2 +- fs/nfs/blocklayout/blocklayout.h | 2 + fs/nfs/blocklayout/blocklayoutdm.c | 120 ++++++++++++++++++++++++++++++++++++ 3 files changed, 123 insertions(+), 1 deletions(-) create mode 100644 fs/nfs/blocklayout/blocklayoutdm.c
fs/nfs/blocklayout/Makefile +1 -1
@@ -2,4 +2,4 @@ # Makefile for the pNFS block layout driver kernel module # obj-$(CONFIG_PNFS_BLOCK) += blocklayoutdriver.o -blocklayoutdriver-objs := blocklayout.o block-device-discovery-pipe.o extents.o blocklayoutdev.o +blocklayoutdriver-objs := blocklayout.o block-device-discovery-pipe.o extents.o blocklayoutdev.o blocklayoutdm.o
fs/nfs/blocklayout/blocklayout.h +2 -0
@@ -101,6 +101,8 @@ struct pnfs_block_dev *nfs4_blk_decode_device(struct nfs_server *server, struct list_head *sdlist);int nfs4_blk_process_layoutget (struct pnfs_layout_hdr *lo,struct nfs4_layoutget_res *lgr,gfp_t gfp_flags); +/* blocklayoutdm.c */ +void free_block_dev (struct pnfs_block_dev *bdev);#include <linux/sunrpc/simple_rpc_pipefs.h>
fs/nfs/blocklayout/blocklayoutdm.c new file +120 -0
120 lines not on this page · raw message
Signature · 1 line
1.7.4.1
PATCH 15/33 pnfsblock: lseg alloc and free
In reply to Jim ReesFrom: Fred Isaman <[email protected]>
--- fs/nfs/blocklayout/blocklayout.c | 39 +++++++++++++++++++++++++++++----- fs/nfs/blocklayout/blocklayout.h | 6 +++++ fs/nfs/blocklayout/blocklayoutdev.c | 8 +++++++ 3 files changed, 47 insertions(+), 6 deletions(-)
fs/nfs/blocklayout/blocklayout.c +33 -6
@@ -110,16 +110,43 @@ static struct pnfs_layout_hdr *bl_alloc_layout_hdr(struct inode *inode,return &bl->bl_layout; } -static void -bl_free_lseg (struct pnfs_layout_segment *lseg) +static void bl_free_lseg (struct pnfs_layout_segment *lseg) { +dprintk ("%s enter\n" , __func__); +kfree (lseg); } -static struct pnfs_layout_segment * -bl_alloc_lseg (struct pnfs_layout_hdr *lo, -struct nfs4_layoutget_res *lgr,gfp_t gfp_flags) +/* Because the generic infrastructure does not correctly merge layouts, +* we pretty much ignore lseg, and store all data layout wide, so we +* can correctly merge. Eventually we should push some correct merge +* behavior up to the generic code, as the current behavior tends to +* cause lots of unnecessary overlapping LAYOUTGET requests. +*/ +static struct pnfs_layout_segment *bl_alloc_lseg (struct pnfs_layout_hdr *lo, +struct nfs4_layoutget_res *lgr, +gfp_t gfp_flags) { -return NULL ; +struct pnfs_layout_segment *lseg; +int status; + +dprintk ("%s enter\n" , __func__); + lseg =kzalloc (sizeof (*lseg) +0 , gfp_flags); +if (!lseg) +return NULL ; + status =nfs4_blk_process_layoutget (lo, lgr, gfp_flags); +if (status) { +/* We don't want to call the full-blown bl_free_lseg, +* since on error extents were not touched. +*/ +/* STUB - we really want to distinguish between 2 error +* conditions here. This lseg failed, but lo data structures +* are OK, or we hosed the lo data structures. The calling +* code probably needs to distinguish this too. +*/ +kfree (lseg); +return ERR_PTR (status); + } +return lseg; } static void
fs/nfs/blocklayout/blocklayout.h +6 -0
@@ -93,6 +93,12 @@ 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); +} +/* blocklayoutdev.c */ struct block_device *nfs4_blkdev_get (dev_t dev);int nfs4_blkdev_put (struct block_device *bdev);
fs/nfs/blocklayout/blocklayoutdev.c +8 -0
@@ -149,3 +149,11 @@ out_err:kfree (msg);return NULL ; } + +int +nfs4_blk_process_layoutget (struct pnfs_layout_hdr *lo, +struct nfs4_layoutget_res *lgr,gfp_t gfp_flags) +{ +/* STUB */ +return -EIO ; +}
Signature · 1 line
1.7.4.1
PATCH 16/33 pnfsblock: merge extents
In reply to Jim ReesFrom: Fred Isaman <[email protected]>
Replace a stub, so that extents underlying the layouts are properly added, merged, or ignored as necessary.
--- fs/nfs/blocklayout/blocklayout.h | 14 +++++- fs/nfs/blocklayout/extents.c | 106 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+), 1 deletions(-)
fs/nfs/blocklayout/blocklayout.h +13 -1
@@ -77,6 +77,14 @@ enum extentclass4 { EXTENT_LISTS = 2, }; +static inline int 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 */
@@ -109,6 +117,11 @@ int nfs4_blk_process_layoutget(struct pnfs_layout_hdr *lo, struct nfs4_layoutget_res *lgr, gfp_t gfp_flags);/* blocklayoutdm.c */ void free_block_dev (struct pnfs_block_dev *bdev); +/* extents.c */ +void put_extent (struct pnfs_block_extent *be); +struct pnfs_block_extent *alloc_extent (void ); +int add_and_merge_extent (struct pnfs_block_layout *bl, +struct pnfs_block_extent *new);#include <linux/sunrpc/simple_rpc_pipefs.h>
@@ -124,5 +137,4 @@ void bl_pipe_exit(void);#define BL_DEVICE_REQUEST_PROC 0x1/* User level process succeeds */ #define BL_DEVICE_REQUEST_ERR 0x2/* User level process fails */ -void put_extent (struct pnfs_block_extent *be);#endif /* FS_NFS_NFS4BLOCKLAYOUT_H */
fs/nfs/blocklayout/extents.c +106 -0
109 lines not on this page · raw message
Signature · 1 line
1.7.4.1
PATCH 17/33 pnfsblock: call and parse getdevicelist
In reply to Jim ReesFrom: Fred Isaman <[email protected]>
Call GETDEVICELIST during mount, then call and parse GETDEVICEINFO for each device returned.
--- fs/nfs/blocklayout/blocklayout.c | 155 +++++++++++++++++++++++++++++++++++++- fs/nfs/blocklayout/blocklayout.h | 98 ++++++++++++++++++++++++- 2 files changed, 250 insertions(+), 3 deletions(-)
fs/nfs/blocklayout/blocklayout.c +153 -2
@@ -31,7 +31,7 @@*/ #include <linux/module.h> #include <linux/init.h> - +#include <linux/vmalloc.h> #include "blocklayout.h" #define NFSDBG_FACILITY NFSDBG_PNFS_LD
@@ -161,17 +161,168 @@ bl_cleanup_layoutcommit(struct pnfs_layout_hdr *lo, { } +static void free_blk_mountid (struct block_mount_id *mid) +{ +if (mid) { +struct pnfs_block_dev *dev; +spin_lock (&mid->bm_lock); +while (!list_empty (&mid->bm_devlist)) { + dev =list_first_entry (&mid->bm_devlist, + struct pnfs_block_dev, + bm_node); +list_del (&dev->bm_node); +free_block_dev (dev); + } +spin_unlock (&mid->bm_lock); +kfree (mid); + } +} + +/* This is mostly copied from the filelayout's get_device_info function. +* It seems much of this should be at the generic pnfs level. +*/ +static struct pnfs_block_dev * +nfs4_blk_get_deviceinfo (struct nfs_server *server,const struct nfs_fh *fh, +struct nfs4_deviceid *d_id, +struct list_head *sdlist) +{ +struct pnfs_device *dev; +struct pnfs_block_dev *rv =NULL ; +u32 max_resp_sz; +int max_pages; +struct page **pages =NULL ; +int i, rc; + +/* +* 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 = max_resp_sz >>PAGE_SHIFT ; +dprintk ("%s max_resp_sz %u max_pages %d\n" , + __func__, max_resp_sz, max_pages); + + dev =kmalloc (sizeof (*dev),GFP_KERNEL ); +if (!dev) { +dprintk ("%s kmalloc failed\n" , __func__); +return NULL ; + } + + pages =kzalloc (max_pages *sizeof (struct page *),GFP_KERNEL ); +if (pages ==NULL ) { +kfree (dev); +return NULL ; + } +for (i =0 ; i < max_pages; i++) { + pages[i] =alloc_page (GFP_KERNEL ); +if (!pages[i]) + goto out_free; + } + +/* set dev->area */ + dev->area =vmap (pages, max_pages,VM_MAP ,PAGE_KERNEL ); +if (!dev->area) + goto out_free; + +memcpy (&dev->dev_id, d_id,sizeof (*d_id)); + dev->layout_type =LAYOUT_BLOCK_VOLUME ; + dev->pages = pages; + dev->pgbase =0 ; + dev->pglen =PAGE_SIZE * max_pages; + dev->mincount =0 ; + +dprintk ("%s: dev_id: %s\n" , __func__, dev->dev_id.data); + rc =nfs4_proc_getdeviceinfo (server, dev); +dprintk ("%s getdevice info returns %d\n" , __func__, rc); +if (rc) + goto out_free; + + rv =nfs4_blk_decode_device (server, dev, sdlist); + out_free: +if (dev->area !=NULL ) +vunmap (dev->area); +for (i =0 ; i < max_pages; i++) +__free_page (pages[i]); +kfree (pages); +kfree (dev); +return rv; +} +static int bl_set_layoutdriver (struct nfs_server *server,const struct nfs_fh *fh) { +struct block_mount_id *b_mt_id =NULL ; +struct pnfs_mount_type *mtype =NULL ; +struct pnfs_devicelist *dlist =NULL ; +struct pnfs_block_dev *bdev; +LIST_HEAD (block_disklist); +int status =0 , i; +dprintk ("%s enter\n" , __func__); -return 0 ; + +if (server->pnfs_blksize ==0 ) { +dprintk ("%s Server did not return blksize\n" , __func__); +return -EINVAL ; + } + b_mt_id =kzalloc (sizeof (struct block_mount_id ),GFP_KERNEL ); +if (!b_mt_id) { + status = -ENOMEM ; + goto out_error; + } +/* Initialize nfs4 block layout mount id */ +spin_lock_init (&b_mt_id->bm_lock); +INIT_LIST_HEAD (&b_mt_id->bm_devlist); + + dlist =kmalloc (sizeof (struct pnfs_devicelist ),GFP_KERNEL ); +if (!dlist) + goto out_error; + dlist->eof =0 ; +while (!dlist->eof) { + status =nfs4_proc_getdevicelist (server, fh, dlist); +if (status) + goto out_error; +dprintk ("%s GETDEVICELIST numdevs=%i, eof=%i\n" , + __func__, dlist->num_devs, dlist->eof); +/* For each device returned in dlist, call GETDEVICEINFO, and +* decode the opaque topology encoding to create a flat +* volume topology, matching VOLUME_SIMPLE disk signatures +* to disks in the visible block disk list. +* Construct an LVM meta device from the flat volume topology. +*/ +for (i =0 ; i < dlist->num_devs; i++) { + bdev =nfs4_blk_get_deviceinfo (server, fh, + &dlist->dev_id[i], + &block_disklist); +if (!bdev) { + status = -ENODEV ; + goto out_error; + } +spin_lock (&b_mt_id->bm_lock); +list_add (&bdev->bm_node, &b_mt_id->bm_devlist); +spin_unlock (&b_mt_id->bm_lock); + } + } +dprintk ("%s SUCCESS\n" , __func__); + server->pnfs_ld_data = b_mt_id; + + out_return: +kfree (dlist); +return status; + + out_error: +free_blk_mountid (b_mt_id); +kfree (mtype); + goto out_return; }static int bl_clear_layoutdriver (struct nfs_server *server) { +struct block_mount_id *b_mt_id = server->pnfs_ld_data; +dprintk ("%s enter\n" , __func__); +free_blk_mountid (b_mt_id); +dprintk ("%s RETURNS\n" , __func__);return 0 ; }
fs/nfs/blocklayout/blocklayout.h +97 -1
122 lines not on this page · raw message
Signature · 1 line
1.7.4.1
PATCH 18/33 pnfsblock: allow use of PG_owner_priv_1 flag
In reply to Jim ReesFrom: Fred Isaman <[email protected]>
There is currently no good way for pnfs to communicate problems. For example - the linux read code first tries to do readahead through nfs_readpages. Failure there is ignored, and it will later call nfs_readpage. Failure there is also ignored, except that the lack of PG_uptodate is communicated back via -EIO.
With pnfs, it would be useful to be able to communicate to nfs_readpage that direct disk IO failed on readahead, and that it should failover to using the MDS.
Making the page flag PG_owner_priv_1 available as PG_pnfserr is one way to do so. (An alternative would be to embed this in the layout, but then pg_test can't easily access the info.)
This may be better as generic pnfs code, in which case it should be put in pnfs.h, or even page-flags.h
--- fs/nfs/blocklayout/blocklayout.h | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-)
fs/nfs/blocklayout/blocklayout.h +5 -0
@@ -35,6 +35,11 @@#include <linux/nfs_fs.h> #include "../pnfs.h" +#define PG_pnfserr PG_owner_priv_1 +#define PagePnfsErr (page) test_bit(PG_pnfserr, &(page)->flags) +#define SetPagePnfsErr (page) set_bit(PG_pnfserr, &(page)->flags) +#define ClearPagePnfsErr (page) clear_bit(PG_pnfserr, &(page)->flags) +struct block_mount_id {spinlock_t bm_lock;/* protects list */ struct list_head bm_devlist;/* holds pnfs_block_dev */
Signature · 1 line
1.7.4.1
PATCH 19/33 pnfsblock: xdr decode pnfs_block_layout4
In reply to Jim ReesFrom: Fred Isaman <[email protected]>
XDR decodes the block layout payload sent in LAYOUTGET result, storing the result in an extent list.
--- fs/nfs/blocklayout/blocklayoutdev.c | 191 ++++++++++++++++++++++++++++++++++- 1 files changed, 189 insertions(+), 2 deletions(-)
fs/nfs/blocklayout/blocklayoutdev.c +189 -2
@@ -150,10 +150,197 @@ out_err:return NULL ; } +/* 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) { -/* STUB */ -return -EIO ; +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; +uint64_t tmp;/* Used by READSECTOR */ +struct layout_verification lv = { + .mode = lgr->range.iomode, + .start = lgr->range.offset >>9 , + .inval = lgr->range.offset >>9 , + .cowread = lgr->range.offset >>9 , + }; +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; + +READ32 (count); + +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 =alloc_extent (); +if (!be) { + status = -ENOMEM ; + goto out_err; + } +READ_DEVID (&be->be_devid); + 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 +*/ +READ_SECTOR (be->be_f_offset); +READ_SECTOR (be->be_length); +READ_SECTOR (be->be_v_offset); +READ32 (be->be_state); +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 <<9 ) { +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 =add_and_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: +put_extent (be); +while (!list_empty (&extents)) { + be = list_first_entry(&extents, struct pnfs_block_extent, + be_node); +list_del (&be->be_node); +put_extent (be); + } + goto out; }
Signature · 1 line
1.7.4.1
PATCH 20/33 pnfsblock: find_get_extent
In reply to Jim ReesFrom: Fred <[email protected]>
Implement find_get_extent(), one of the core extent manipulation routines.
pnfsblock: fix print format warnings for sector_t and size_t
gcc spews warnings about these on x86_64, e.g.:fs/nfs/blocklayout/blocklayout.c:74: warning: format ‘%Lu’ expects type ‘long long unsigned int’, but argument 2 has type ‘sector_t’ fs/nfs/blocklayout/blocklayout.c:388: warning: format ‘%d’ expects type ‘int’, but argument 5 has type ‘size_t’
--- fs/nfs/blocklayout/blocklayout.h | 3 ++ fs/nfs/blocklayout/extents.c | 47 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 0 deletions(-)
fs/nfs/blocklayout/blocklayout.h +3 -0
@@ -219,6 +219,9 @@ int nfs4_blk_process_layoutget(struct pnfs_layout_hdr *lo,/* blocklayoutdm.c */ void free_block_dev (struct pnfs_block_dev *bdev);/* extents.c */ +struct pnfs_block_extent * +find_get_extent (struct pnfs_block_layout *bl,sector_t isect, +struct pnfs_block_extent **cow_read);void put_extent (struct pnfs_block_extent *be);struct pnfs_block_extent *alloc_extent (void ); int add_and_merge_extent(struct pnfs_block_layout *bl,
fs/nfs/blocklayout/extents.c +47 -0
50 lines not on this page · raw message
Signature · 1 line
1.7.4.1
PATCH 21/33 pnfsblock: SPLITME: add extent manipulation functions
In reply to Jim ReesFrom: Fred Isaman <[email protected]>
Adds working implementations of various support functions to handle INVAL extents, needed by writes, such as mark_initialized_sectors and is_sector_initialized.
SPLIT: this needs to be split into the exported functions, and the range support functions (which will be replaced eventually.)
--- fs/nfs/blocklayout/blocklayout.h | 30 ++++- fs/nfs/blocklayout/extents.c | 253 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 281 insertions(+), 2 deletions(-)
fs/nfs/blocklayout/blocklayout.h +28 -2
@@ -35,6 +35,8 @@#include <linux/nfs_fs.h> #include "../pnfs.h" +#define PAGE_CACHE_SECTORS (PAGE_CACHE_SIZE >> 9) +#define PG_pnfserr PG_owner_priv_1#define PagePnfsErr (page) test_bit(PG_pnfserr, &(page)->flags)#define SetPagePnfsErr (page) set_bit(PG_pnfserr, &(page)->flags)
@@ -101,8 +103,23 @@ enum exstate4 { 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_t { +sector_t mtt_step_size;/* Internal sector alignment */ +struct list_head mtt_stub;/* Should be a radix tree */ +}; +struct pnfs_inval_markings { -/* STUB */ +spinlock_t im_lock; +struct my_tree_t 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 */
@@ -121,7 +138,11 @@ struct pnfs_block_extent {static inline void INIT_INVAL_MARKS (struct pnfs_inval_markings *marks,sector_t blocksize) { -/* STUB */ +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 {
@@ -222,8 +243,13 @@ void free_block_dev(struct pnfs_block_dev *bdev);struct pnfs_block_extent *find_get_extent (struct pnfs_block_layout *bl,sector_t isect,struct pnfs_block_extent **cow_read); +int mark_initialized_sectors (struct pnfs_inval_markings *marks, +sector_t offset,sector_t length, +sector_t **pages);void put_extent (struct pnfs_block_extent *be);struct pnfs_block_extent *alloc_extent (void ); +struct pnfs_block_extent *get_extent (struct pnfs_block_extent *be); +int is_sector_initialized (struct pnfs_inval_markings *marks,sector_t isect);int add_and_merge_extent (struct pnfs_block_layout *bl,struct pnfs_block_extent *new);
fs/nfs/blocklayout/extents.c +253 -0
259 lines not on this page · raw message
Signature · 1 line
1.7.4.1
PATCH 22/33 pnfsblock: merge rw extents
In reply to Jim ReesFrom: Fred Isaman <[email protected]>
--- fs/nfs/blocklayout/extents.c | 47 ++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 47 insertions(+), 0 deletions(-)
fs/nfs/blocklayout/extents.c +47 -0
@@ -501,3 +501,50 @@ find_get_extent(struct pnfs_block_layout *bl, sector_t isect,print_bl_extent (ret);return ret; } + +/* Helper function to set_to_rw that initialize a new extent */ +static void +_prep_new_extent (struct pnfs_block_extent *new, +struct pnfs_block_extent *orig, +sector_t offset,sector_t length,int state) +{ +kref_init (&new->be_refcnt); +/* don't need to INIT_LIST_HEAD(&new->be_node) */ +memcpy (&new->be_devid, &orig->be_devid,sizeof (struct nfs4_deviceid )); + new->be_mdev = orig->be_mdev; + new->be_f_offset = offset; + new->be_length = length; + new->be_v_offset = orig->be_v_offset - orig->be_f_offset + offset; + new->be_state = state; + new->be_inval = orig->be_inval; +} + +/* Tries to merge be with extent in front of it in list. +* Frees storage if not used. +*/ +static struct pnfs_block_extent * +_front_merge (struct pnfs_block_extent *be,struct list_head *head, +struct pnfs_block_extent *storage) +{ +struct pnfs_block_extent *prev; + +if (!storage) + goto no_merge; +if (&be->be_node == head || be->be_node.prev == head) + goto no_merge; + prev = list_entry(be->be_node.prev, struct pnfs_block_extent, be_node); +if ((prev->be_f_offset + prev->be_length != be->be_f_offset) || + !extents_consistent (prev, be)) + goto no_merge; +_prep_new_extent (storage, prev, prev->be_f_offset, + prev->be_length + be->be_length, prev->be_state); +list_replace (&prev->be_node, &storage->be_node); +put_extent (prev); +list_del (&be->be_node); +put_extent (be); +return storage; + + no_merge: +kfree (storage); +return be; +}
Signature · 1 line
1.7.4.1
PATCH 23/33 pnfsblock: encode_layoutcommit
In reply to Jim ReesFrom: Fred Isaman <[email protected]>
In blocklayout driver. There are two things happening while layoutcommit/cleanup.
1. the modified extents are encoded.
2. On cleanup the extents are put back on the layout rw extents list, for reads.
In the new system where actual xdr encoding is done in encode_layoutcommit() directly into xdr buffer, these are the new commit stages:
1. On setup_layoutcommit, the range is adjusted as before and a structure is allocated for communication with bl_encode_layoutcommit && bl_cleanup_layoutcommit (Generic layer provides a void-star to hang it on)
2. bl_encode_layoutcommit is called to do the actual encoding directly into xdr. The commit-extent-list is not freed and is stored on above structure.
FIXME: The code is not yet converted to the new XDR cleanup
3. On cleanup the commit-extent-list is put back by a call to set_to_rw() as before, but with no need for XDR decoding of the list as before. And the commit-extent-list is freed. Finally allocated structure is freed.
--- fs/nfs/blocklayout/blocklayout.c | 2 + fs/nfs/blocklayout/blocklayout.h | 12 +++ fs/nfs/blocklayout/extents.c | 175 ++++++++++++++++++++++++++++---------- 3 files changed, 145 insertions(+), 44 deletions(-)
fs/nfs/blocklayout/blocklayout.c +2 -0
@@ -153,6 +153,8 @@ static void bl_encode_layoutcommit(struct pnfs_layout_hdr *lo, struct xdr_stream *xdr, const struct nfs4_layoutcommit_args *arg) { + dprintk("%s enter\n", __func__); +encode_pnfs_block_layoutupdate (BLK_LO2EXT (lo), xdr, arg); } static void
fs/nfs/blocklayout/blocklayout.h +12 -0
@@ -135,6 +135,15 @@ struct pnfs_block_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;/* STUB - removable??? */ +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 INIT_INVAL_MARKS (struct pnfs_inval_markings *marks,sector_t blocksize) {
@@ -250,6 +259,9 @@ void put_extent(struct pnfs_block_extent *be);struct pnfs_block_extent *alloc_extent (void );struct pnfs_block_extent *get_extent (struct pnfs_block_extent *be);int is_sector_initialized (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);int add_and_merge_extent (struct pnfs_block_layout *bl,struct pnfs_block_extent *new);
fs/nfs/blocklayout/extents.c +131 -44
208 lines not on this page · raw message
Signature · 1 line
1.7.4.1
PATCH 24/33 pnfsblock: cleanup_layoutcommit
In reply to Jim ReesFrom: Fred Isaman <[email protected]>
In blocklayout driver. There are two things happening while layoutcommit/cleanup.
1. the modified extents are encoded.
2. On cleanup the extents are put back on the layout rw extents list, for reads.
In the new system where actual xdr encoding is done in encode_layoutcommit() directly into xdr buffer, these are the new commit stages:
1. On setup_layoutcommit, the range is adjusted as before and a structure is allocated for communication with bl_encode_layoutcommit && bl_cleanup_layoutcommit (Generic layer provides a void-star to hang it on)
2. bl_encode_layoutcommit is called to do the actual encoding directly into xdr. The commit-extent-list is not freed and is stored on above structure.
FIXME: The code is not yet converted to the new XDR cleanup
3. On cleanup the commit-extent-list is put back by a call to set_to_rw() as before, but with no need for XDR decoding of the list as before. And the commit-extent-list is freed. Finally allocated structure is freed.
--- fs/nfs/blocklayout/blocklayout.c | 2 + fs/nfs/blocklayout/blocklayout.h | 3 + fs/nfs/blocklayout/extents.c | 209 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 214 insertions(+), 0 deletions(-)
fs/nfs/blocklayout/blocklayout.c +2 -0
@@ -161,6 +161,8 @@ static void bl_cleanup_layoutcommit(struct pnfs_layout_hdr *lo, struct nfs4_layoutcommit_data *lcdata) { + dprintk("%s enter\n", __func__); +clean_pnfs_block_layoutupdate (BLK_LO2EXT (lo), &lcdata->args, lcdata->res.status); }static void free_blk_mountid (struct block_mount_id *mid)
fs/nfs/blocklayout/blocklayout.h +3 -0
@@ -262,6 +262,9 @@ int is_sector_initialized(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 add_and_merge_extent (struct pnfs_block_layout *bl,struct pnfs_block_extent *new);
fs/nfs/blocklayout/extents.c +209 -0
224 lines not on this page · raw message
Signature · 1 line
1.7.4.1
PATCH 25/33 pnfsblock: bl_read_pagelist
In reply to Jim ReesFrom: Fred Isaman <[email protected]>
Note: When upper layer's read/write request cannot be fulfilled, the block layout driver shouldn't silently mark the page as error. It should do what can be done and leave the rest to the upper layer. To do so, we should set rdata/wdata->res.count properly.
When upper layer re-send the read/write request to finish the rest part of the request, pgbase is the position where we should start at.
--- fs/nfs/blocklayout/blocklayout.c | 259 ++++++++++++++++++++++++++++++++++++++ 1 files changed, 259 insertions(+), 0 deletions(-)
fs/nfs/blocklayout/blocklayout.c +259 -0
@@ -31,6 +31,7 @@*/ #include <linux/module.h> #include <linux/init.h> +#include <linux/bio.h> /* struct bio */ #include <linux/vmalloc.h> #include "blocklayout.h"
@@ -40,9 +41,267 @@ MODULE_LICENSE("GPL");MODULE_AUTHOR ("Andy Adamson <[email protected]>" );MODULE_DESCRIPTION ("The NFSv4.1 pNFS Block layout driver" ); +static void print_page (struct page *page) +{ +dprintk ("PRINTPAGE page %p\n" , page); +dprintk (" PagePrivate %d\n" ,PagePrivate (page)); +dprintk (" PageUptodate %d\n" ,PageUptodate (page)); +dprintk (" PageError %d\n" ,PageError (page)); +dprintk (" PageDirty %d\n" ,PageDirty (page)); +dprintk (" PageReferenced %d\n" ,PageReferenced (page)); +dprintk (" PageLocked %d\n" ,PageLocked (page)); +dprintk (" PageWriteback %d\n" ,PageWriteback (page)); +dprintk (" PageMappedToDisk %d\n" ,PageMappedToDisk (page)); +dprintk ("\n" ); +} + +/* Given the be associated with isect, determine if page data needs to be +* initialized. +*/ +static int is_hole (struct pnfs_block_extent *be,sector_t isect) +{ +if (be->be_state ==PNFS_BLOCK_NONE_DATA ) +return 1 ; +else if (be->be_state !=PNFS_BLOCK_INVALID_DATA ) +return 0 ; +else +return !is_sector_initialized (be->be_inval, isect); +} + +static int +dont_like_caller (struct nfs_page *req) +{ +if (atomic_read (&req->wb_complete)) { +/* Called by _multi */ +return 1 ; + }else { +/* Called by _one */ +return 0 ; + } +} + +/* The data we are handed might be spread across several bios. We need +* to track when the last one is finished. +*/ +struct parallel_io { +struct kref refcnt; +struct rpc_call_ops call_ops; +void (*pnfs_callback) (void *data); +void *data; +}; + +static inline struct parallel_io *alloc_parallel (void *data) +{ +struct parallel_io *rv; + + rv =kmalloc (sizeof (*rv),GFP_KERNEL ); +if (rv) { + rv->data = data; +kref_init (&rv->refcnt); + } +return rv; +} + +static inline void get_parallel (struct parallel_io *p) +{ +kref_get (&p->refcnt); +} + +static void destroy_parallel (struct kref *kref) +{ + struct parallel_io *p = container_of(kref, struct parallel_io, refcnt); + +dprintk ("%s enter\n" , __func__); + p->pnfs_callback (p->data); +kfree (p); +} + +static inline void put_parallel (struct parallel_io *p) +{ +kref_put (&p->refcnt, destroy_parallel); +} + +static struct bio * +bl_submit_bio (int rw,struct bio *bio) +{ +if (bio) { +get_parallel (bio->bi_private); +dprintk ("%s submitting %s bio %u@%llu\n" , __func__, + rw ==READ ?"read" :"write" , + bio->bi_size, (u64 )bio->bi_sector); +submit_bio (rw, bio); + } +return NULL ; +} + +static inline void +bl_done_with_rpage (struct page *page,const int ok) +{ +if (ok) { +ClearPagePnfsErr (page); +SetPageUptodate (page); + }else { +ClearPageUptodate (page); +SetPageError (page); +SetPagePnfsErr (page); + } +/* Page is unlocked via rpc_release. Should really be done here. */ +} + +/* This is basically copied from mpage_end_io_read */ +static void bl_end_io_read (struct bio *bio,int err) +{ +void *data = bio->bi_private; +const int uptodate =test_bit (BIO_UPTODATE , &bio->bi_flags); +struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt -1 ; + +do { +struct page *page = bvec->bv_page; + +if (--bvec >= bio->bi_io_vec) +prefetchw (&bvec->bv_page->flags); +bl_done_with_rpage (page, uptodate); + }while (bvec >= bio->bi_io_vec); +bio_put (bio); +put_parallel (data); +} + +static void bl_read_cleanup (struct work_struct *work) +{ +struct rpc_task *task; +struct nfs_read_data *rdata; +dprintk ("%s enter\n" , __func__); + task = container_of(work, struct rpc_task, u.tk_work); + rdata = container_of(task, struct nfs_read_data, task); +pnfs_ld_read_done (rdata); +} + +static void +bl_end_par_io_read (void *data) +{ +struct nfs_read_data *rdata = data; + +INIT_WORK (&rdata->task.u.tk_work, bl_read_cleanup); +schedule_work (&rdata->task.u.tk_work); +} + +/* We don't want normal .rpc_call_done callback used, so we replace it +* with this stub. +*/ +static void bl_rpc_do_nothing (struct rpc_task *task,void *calldata) +{ +return ; +} +static enum pnfs_try_status bl_read_pagelist (struct nfs_read_data *rdata) { +int i, hole; +struct bio *bio =NULL ; +struct pnfs_block_extent *be =NULL , *cow_read =NULL ; +sector_t isect, extent_length =0 ; +struct parallel_io *par; +loff_t f_offset = rdata->args.offset; +size_t count = rdata->args.count; +struct page **pages = rdata->args.pages; +int pg_index = rdata->args.pgbase >>PAGE_CACHE_SHIFT ; + +dprintk ("%s enter nr_pages %u offset %lld count %Zd\n" , __func__, + rdata->npages, f_offset, count); + +if (dont_like_caller (rdata->req)) { +dprintk ("%s dont_like_caller failed\n" , __func__); + goto use_mds; + } +if ((rdata->npages ==1 ) &&PagePnfsErr (rdata->req->wb_page)) { +/* We want to fall back to mds in case of read_page +* after error on read_pages. +*/ +dprintk ("%s PG_pnfserr set\n" , __func__); + goto use_mds; + } + par =alloc_parallel (rdata); +if (!par) + goto use_mds; + par->call_ops = *rdata->mds_ops; + par->call_ops.rpc_call_done = bl_rpc_do_nothing; + par->pnfs_callback = bl_end_par_io_read; +/* At this point, we can no longer jump to use_mds */ + + isect = (sector_t) (f_offset >>9 ); +/* Code assumes extents are page-aligned */ +for (i = pg_index; i < rdata->npages; i++) { +if (!extent_length) { +/* We've used up the previous extent */ +put_extent (be); +put_extent (cow_read); + bio =bl_submit_bio (READ , bio); +/* Get the next one */ + be =find_get_extent (BLK_LSEG2EXT (rdata->lseg), + isect, &cow_read); +if (!be) { +/* Error out this page */ +bl_done_with_rpage (pages[i],0 ); +break ; + } + extent_length = be->be_length - + (isect - be->be_f_offset); +if (cow_read) { +sector_t cow_length = cow_read->be_length - + (isect - cow_read->be_f_offset); + extent_length =min (extent_length, cow_length); + } + } + hole =is_hole (be, isect); +if (hole && !cow_read) { + bio =bl_submit_bio (READ , bio); +/* Fill hole w/ zeroes w/o accessing device */ +dprintk ("%s Zeroing page for hole\n" , __func__); +zero_user (pages[i],0 , +min_t (int,PAGE_CACHE_SIZE , count)); +print_page (pages[i]); +bl_done_with_rpage (pages[i],1 ); + }else { +struct pnfs_block_extent *be_read; + + be_read = (hole && cow_read) ? cow_read : be; +for (;;) { +if (!bio) { + bio =bio_alloc (GFP_NOIO , rdata->npages - i); +if (!bio) { +/* Error out this page */ +bl_done_with_rpage (pages[i],0 ); +break ; + } + bio->bi_sector = isect - + be_read->be_f_offset + + be_read->be_v_offset; + bio->bi_bdev = be_read->be_mdev; + bio->bi_end_io = bl_end_io_read; + bio->bi_private = par; + } +if (bio_add_page (bio, pages[i],PAGE_SIZE ,0 )) +break ; + bio =bl_submit_bio (READ , bio); + } + } + isect +=PAGE_CACHE_SIZE >>9 ; + extent_length -=PAGE_CACHE_SIZE >>9 ; + } +if ((isect <<9 ) >= rdata->inode->i_size) { + rdata->res.eof =1 ; + rdata->res.count = rdata->inode->i_size - f_offset; + }else { + rdata->res.count = (isect <<9 ) - f_offset; + } +put_extent (be); +put_extent (cow_read); +bl_submit_bio (READ , bio); +put_parallel (par); +return PNFS_ATTEMPTED ; + + use_mds: +dprintk ("Giving up and using normal NFS\n" );return PNFS_NOT_ATTEMPTED ; }
Signature · 1 line
1.7.4.1
PATCH 26/33 pnfsblock: write_begin
In reply to Jim ReesFrom: Fred Isaman <[email protected]>
Implements bl_write_begin and bl_do_flush, allowing block driver to read in page "around" the data that is about to be copied to the page.
--- fs/nfs/blocklayout/blocklayout.c | 178 +++++++++++++++++++++++++++++++++++++- 1 files changed, 177 insertions(+), 1 deletions(-)
fs/nfs/blocklayout/blocklayout.c +177 -1
@@ -31,6 +31,8 @@*/ #include <linux/module.h> #include <linux/init.h> + +#include <linux/buffer_head.h> /* various write calls */ #include <linux/bio.h> /* struct bio */ #include <linux/vmalloc.h> #include "blocklayout.h"
@@ -589,11 +591,185 @@ bl_clear_layoutdriver(struct nfs_server *server)return 0 ; } +/* STUB - mark intersection of layout and page as bad, so is not +* used again. +*/ +static void mark_bad_read (void ) +{ +return ; +} + +/* Copied from buffer.c */ +static void __end_buffer_read_notouch (struct buffer_head *bh,int uptodate) +{ +if (uptodate) { +set_buffer_uptodate (bh); + }else { +/* This happens, due to failed READA attempts. */ +clear_buffer_uptodate (bh); + } +unlock_buffer (bh); +} + +/* Copied from buffer.c */ +static void end_buffer_read_nobh (struct buffer_head *bh,int uptodate) +{ +__end_buffer_read_notouch (bh, uptodate); +} + +/* +* map_block: map a requested I/0 block (isect) into an offset in the LVM +* meta block_device +*/ +static void +map_block (sector_t isect,struct pnfs_block_extent *be,struct buffer_head *bh) +{ +dprintk ("%s enter be=%p\n" , __func__, be); + +set_buffer_mapped (bh); + bh->b_bdev = be->be_mdev; + bh->b_blocknr = (isect - be->be_f_offset + be->be_v_offset) >> + (be->be_mdev->bd_inode->i_blkbits -9 ); + +dprintk ("%s isect %ld, bh->b_blocknr %ld, using bsize %Zd\n" , + __func__, (long )isect, + (long )bh->b_blocknr, + bh->b_size); +return ; +} + +/* Given an unmapped page, zero it (or read in page for COW), +* and set appropriate flags/markings, but it is safe to not initialize +* the range given in [from, to). +*/ +/* This is loosely based on nobh_write_begin */ +static int +init_page_for_write (struct pnfs_block_layout *bl,struct page *page, +unsigned from,unsigned to,sector_t **pages_to_mark) +{ +struct buffer_head *bh; +int inval, ret = -EIO ; +struct pnfs_block_extent *be =NULL , *cow_read =NULL ; +sector_t isect; + +dprintk ("%s enter, %p\n" , __func__, page); + bh =alloc_page_buffers (page,PAGE_CACHE_SIZE ,0 ); +if (!bh) { + ret = -ENOMEM ; + goto cleanup; + } + + isect = (sector_t )page->index << (PAGE_CACHE_SHIFT -9 ); + be =find_get_extent (bl, isect, &cow_read); +if (!be) + goto cleanup; + inval =is_hole (be, isect); +dprintk ("%s inval=%i, from=%u, to=%u\n" , __func__, inval, from, to); +if (inval) { +if (be->be_state ==PNFS_BLOCK_NONE_DATA ) { +dprintk ("%s PANIC - got NONE_DATA extent %p\n" , + __func__, be); + goto cleanup; + } +map_block (isect, be, bh); +unmap_underlying_metadata (bh->b_bdev, bh->b_blocknr); + } +if (PageUptodate (page)) { +/* Do nothing */ + }else if (inval & !cow_read) { +zero_user_segments (page,0 , from, to,PAGE_CACHE_SIZE ); + }else if (0 < from ||PAGE_CACHE_SIZE > to) { +struct pnfs_block_extent *read_extent; + + read_extent = (inval && cow_read) ? cow_read : be; +map_block (isect, read_extent, bh); +lock_buffer (bh); + bh->b_end_io = end_buffer_read_nobh; +submit_bh (READ , bh); +dprintk ("%s: Waiting for buffer read\n" , __func__); +/* XXX Don't really want to hold layout lock here */ +wait_on_buffer (bh); +if (!buffer_uptodate (bh)) + goto cleanup; + } +if (be->be_state ==PNFS_BLOCK_INVALID_DATA ) { +/* There is a BUG here if is a short copy after write_begin, +* but I think this is a generic fs bug. The problem is that +* we have marked the page as initialized, but it is possible +* that the section not copied may never get copied. +*/ + ret =mark_initialized_sectors (be->be_inval, isect, +PAGE_CACHE_SECTORS , + pages_to_mark); +/* Want to preallocate mem so above can't fail */ +if (ret) + goto cleanup; + } +SetPageMappedToDisk (page); + ret =0 ; + +cleanup: +free_buffer_head (bh); +put_extent (be); +put_extent (cow_read); +if (ret) { +/* Need to mark layout with bad read...should now +* just use nfs4 for reads and writes. +*/ +mark_bad_read (); + } +return ret; +} +static int bl_write_begin (struct pnfs_layout_segment *lseg,struct page *page,loff_t pos,unsigned count,struct pnfs_fsdata *fsdata) { -return 0 ; +unsigned from, to; +int ret; +sector_t *pages_to_mark =NULL ; +struct pnfs_block_layout *bl =BLK_LSEG2EXT (lseg); + +dprintk ("%s enter, %u@%lld\n" , __func__, count, pos); +print_page (page); +/* The following code assumes blocksize >= PAGE_CACHE_SIZE */ +if (bl->bl_blocksize < (PAGE_CACHE_SIZE >>9 )) { +dprintk ("%s Can't handle blocksize %llu\n" , __func__, + (u64 )bl->bl_blocksize); +put_lseg (fsdata->lseg); + fsdata->lseg =NULL ; +return 0 ; + } +if (PageMappedToDisk (page)) { +/* Basically, this is a flag that says we have +* successfully called write_begin already on this page. +*/ +/* NOTE - there are cache consistency issues here. +* For example, what if the layout is recalled, then regained? +* If the file is closed and reopened, will the page flags +* be reset? If not, we'll have to use layout info instead of +* the page flag. +*/ +return 0 ; + } + from = pos & (PAGE_CACHE_SIZE -1 ); + to = from + count; + ret =init_page_for_write (bl, page, from, to, &pages_to_mark); +if (ret) { +dprintk ("%s init page failed with %i" , __func__, ret); +/* Revert back to plain NFS and just continue on with +* write. This assumes there is no request attached, which +* should be true if we get here. +*/ +BUG_ON (PagePrivate (page)); +put_lseg (fsdata->lseg); + fsdata->lseg =NULL ; +kfree (pages_to_mark); + ret =0 ; + }else { + fsdata->private = pages_to_mark; + } +return ret; } static int
Signature · 1 line
1.7.4.1
PATCH 27/33 pnfsblock: write_end
In reply to Jim ReesFrom: Fred Isaman <[email protected]>
Implements bl_write_end, which basically just calls SetPageUptodate.
--- fs/nfs/blocklayout/blocklayout.c | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-)
fs/nfs/blocklayout/blocklayout.c +5 -0
@@ -772,10 +772,15 @@ bl_write_begin(struct pnfs_layout_segment *lseg, struct page *page, loff_t pos,return ret; } +/* CAREFUL - what happens if copied < count??? */ static int bl_write_end (struct inode *inode,struct page *page,loff_t pos,unsigned count,unsigned copied,struct pnfs_layout_segment *lseg) { +dprintk ("%s enter, %u@%lld, lseg=%p\n" , __func__, count, pos, lseg); +print_page (page); +if (lseg) +SetPageUptodate (page);return 0 ; }
Signature · 1 line
1.7.4.1
PATCH 28/33 pnfsblock: write_end_cleanup
In reply to Jim ReesFrom: Fred Isaman <[email protected]>
Ensure all pages in block are marked for initialization if needed.
--- fs/nfs/blocklayout/blocklayout.c | 54 ++++++++++++++++++++++++++++++++++++++ 1 files changed, 54 insertions(+), 0 deletions(-)
fs/nfs/blocklayout/blocklayout.c +54 -0
@@ -791,6 +791,60 @@ bl_write_end(struct inode *inode, struct page *page, loff_t pos,static void bl_write_end_cleanup (struct file *filp,struct pnfs_fsdata *fsdata) { +struct page *page; +pgoff_t index; +sector_t *pos; +struct address_space *mapping = filp->f_mapping; +struct pnfs_fsdata *fake_data; +struct pnfs_layout_segment *lseg; + +if (!fsdata) +return ; + lseg = fsdata->lseg; +if (!lseg) +return ; + pos = fsdata->private; +if (!pos) +return ; +dprintk ("%s enter with pos=%llu\n" , __func__, (u64)(*pos)); +for (; *pos != ~0 ; pos++) { + index = *pos >> (PAGE_CACHE_SHIFT -9 ); +/* XXX How do we properly deal with failures here??? */ + page =grab_cache_page_write_begin (mapping, index,0 ); +if (!page) { +printk (KERN_ERR "%s BUG BUG BUG NoMem\n" , __func__); +continue ; + } +dprintk ("%s: Examining block page\n" , __func__); +print_page (page); +if (!PageMappedToDisk (page)) { +/* XXX How do we properly deal with failures here??? */ +dprintk ("%s Marking block page\n" , __func__); +init_page_for_write (BLK_LSEG2EXT (fsdata->lseg), page, +PAGE_CACHE_SIZE ,PAGE_CACHE_SIZE , +NULL ); +print_page (page); + fake_data =kzalloc (sizeof (*fake_data),GFP_KERNEL ); +if (!fake_data) { +printk (KERN_ERR "%s BUG BUG BUG NoMem\n" , + __func__); +unlock_page (page); +continue ; + } +get_lseg (lseg); + fake_data->lseg = lseg; + fake_data->bypass_eof =1 ; + mapping->a_ops->write_end (filp, mapping, + index <<PAGE_CACHE_SHIFT , +PAGE_CACHE_SIZE , +PAGE_CACHE_SIZE , + page, fake_data); +/* Note fake_data is freed by nfs_write_end */ + }else +unlock_page (page); + } +kfree (fsdata->private); + fsdata->private =NULL ; }static struct pnfs_layoutdriver_type blocklayout_type = {
Signature · 1 line
1.7.4.1
PATCH 29/33 pnfsblock: bl_write_pagelist support functions
In reply to Jim ReesFrom: Fred Isaman <[email protected]>
--- fs/nfs/blocklayout/blocklayout.c | 13 +++++++++++++ 1 files changed, 13 insertions(+), 0 deletions(-)
fs/nfs/blocklayout/blocklayout.c +13 -0
@@ -70,6 +70,19 @@ static int is_hole(struct pnfs_block_extent *be, sector_t isect)return !is_sector_initialized (be->be_inval, isect); } +/* Given the be associated with isect, determine if page data can be +* written to disk. +*/ +static int is_writable (struct pnfs_block_extent *be,sector_t isect) +{ +if (be->be_state ==PNFS_BLOCK_READWRITE_DATA ) +return 1 ; +else if (be->be_state !=PNFS_BLOCK_INVALID_DATA ) +return 0 ; +else +return is_sector_initialized (be->be_inval, isect); +} +static int dont_like_caller (struct nfs_page *req) {
Signature · 1 line
1.7.4.1
PATCH 30/33 pnfsblock: bl_write_pagelist
In reply to Jim ReesFrom: Fred Isaman <[email protected]>
Note: When upper layer's read/write request cannot be fulfilled, the block layout driver shouldn't silently mark the page as error. It should do what can be done and leave the rest to the upper layer. To do so, we should set rdata/wdata->res.count properly.
When upper layer re-send the read/write request to finish the rest part of the request, pgbase is the position where we should start at.
--- fs/nfs/blocklayout/blocklayout.c | 146 +++++++++++++++++++++++++++++++++++++- 1 files changed, 145 insertions(+), 1 deletions(-)
fs/nfs/blocklayout/blocklayout.c +145 -1
@@ -320,11 +320,155 @@ bl_read_pagelist(struct nfs_read_data *rdata)return PNFS_NOT_ATTEMPTED ; } +/* STUB - this needs thought */ +static inline void +bl_done_with_wpage (struct page *page,const int ok) +{ +if (!ok) { +SetPageError (page); +SetPagePnfsErr (page); +/* This is an inline copy of nfs_zap_mapping */ +/* This is oh so fishy, and needs deep thought */ +if (page->mapping->nrpages !=0 ) { +struct inode *inode = page->mapping->host; +spin_lock (&inode->i_lock); +NFS_I (inode)->cache_validity |=NFS_INO_INVALID_DATA ; +spin_unlock (&inode->i_lock); + } + } +/* end_page_writeback called in rpc_release. Should be done here. */ +} + +/* This is basically copied from mpage_end_io_read */ +static void bl_end_io_write (struct bio *bio,int err) +{ +void *data = bio->bi_private; +const int uptodate =test_bit (BIO_UPTODATE , &bio->bi_flags); +struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt -1 ; + +do { +struct page *page = bvec->bv_page; + +if (--bvec >= bio->bi_io_vec) +prefetchw (&bvec->bv_page->flags); +bl_done_with_wpage (page, uptodate); + }while (bvec >= bio->bi_io_vec); +bio_put (bio); +put_parallel (data); +} + +/* Function scheduled for call during bl_end_par_io_write, +* it marks sectors as written and extends the commitlist. +*/ +static void bl_write_cleanup (struct work_struct *work) +{ +struct rpc_task *task; +struct nfs_write_data *wdata; +dprintk ("%s enter\n" , __func__); + task = container_of(work, struct rpc_task, u.tk_work); + wdata = container_of(task, struct nfs_write_data, task); +pnfs_ld_write_done (wdata); +} + +/* Called when last of bios associated with a bl_write_pagelist call finishes */ +static void +bl_end_par_io_write (void *data) +{ +struct nfs_write_data *wdata = data; + +/* STUB - ignoring error handling */ + wdata->task.tk_status =0 ; + wdata->verf.committed =NFS_FILE_SYNC ; +INIT_WORK (&wdata->task.u.tk_work, bl_write_cleanup); +schedule_work (&wdata->task.u.tk_work); +} +static enum pnfs_try_status bl_write_pagelist (struct nfs_write_data *wdata,int sync) { -return PNFS_NOT_ATTEMPTED ; +int i; +struct bio *bio =NULL ; +struct pnfs_block_extent *be =NULL ; +sector_t isect, extent_length =0 ; +struct parallel_io *par; +loff_t offset = wdata->args.offset; +size_t count = wdata->args.count; +struct page **pages = wdata->args.pages; +int pg_index = wdata->args.pgbase >>PAGE_CACHE_SHIFT ; + +dprintk ("%s enter, %Zu@%lld\n" , __func__, count, offset); +if (!wdata->lseg) { +dprintk ("%s no lseg, falling back to MDS\n" , __func__); +return PNFS_NOT_ATTEMPTED ; + } +if (dont_like_caller (wdata->req)) { +dprintk ("%s dont_like_caller failed\n" , __func__); +return PNFS_NOT_ATTEMPTED ; + } +/* At this point, wdata->pages is a (sequential) list of nfs_pages. +* We want to write each, and if there is an error remove it from +* list and call +* nfs_retry_request(req) to have it redone using nfs. +* QUEST? Do as block or per req? Think have to do per block +* as part of end_bio +*/ + par =alloc_parallel (wdata); +if (!par) +return PNFS_NOT_ATTEMPTED ; + par->call_ops = *wdata->mds_ops; + par->call_ops.rpc_call_done = bl_rpc_do_nothing; + par->pnfs_callback = bl_end_par_io_write; +/* At this point, have to be more careful with error handling */ + + isect = (sector_t) ((offset & (long )PAGE_CACHE_MASK ) >>9 ); +for (i = pg_index; i < wdata->npages ; i++) { +if (!extent_length) { +/* We've used up the previous extent */ +put_extent (be); + bio =bl_submit_bio (WRITE , bio); +/* Get the next one */ + be =find_get_extent (BLK_LSEG2EXT (wdata->lseg), + isect,NULL ); +if (!be || !is_writable (be, isect)) { +/* FIXME */ +bl_done_with_wpage (pages[i],0 ); +break ; + } + extent_length = be->be_length - + (isect - be->be_f_offset); + } +for (;;) { +if (!bio) { + bio =bio_alloc (GFP_NOIO , wdata->npages - i); +if (!bio) { +/* Error out this page */ +/* FIXME */ +bl_done_with_wpage (pages[i],0 ); +break ; + } + bio->bi_sector = isect - be->be_f_offset + + be->be_v_offset; + bio->bi_bdev = be->be_mdev; + bio->bi_end_io = bl_end_io_write; + bio->bi_private = par; + } +if (bio_add_page (bio, pages[i],PAGE_SIZE ,0 )) +break ; + bio =bl_submit_bio (WRITE , bio); + } + isect +=PAGE_CACHE_SIZE >>9 ; + extent_length -=PAGE_CACHE_SIZE >>9 ; + } + wdata->res.count = (isect <<9 ) - (offset); +if (count < wdata->res.count) + wdata->res.count = count; +/* pnfs_set_layoutcommit needs this */ + wdata->mds_offset = offset; +put_extent (be); +bl_submit_bio (WRITE , bio); +put_parallel (par); +return PNFS_ATTEMPTED ; }/* FIXME - range ignored */
Signature · 1 line
1.7.4.1
PATCH 31/33 pnfsblock: note written INVAL areas for layoutcommit
In reply to Jim ReesFrom: Fred Isaman <[email protected]>
--- fs/nfs/blocklayout/blocklayout.c | 32 +++++++++++++ fs/nfs/blocklayout/blocklayout.h | 2 + fs/nfs/blocklayout/extents.c | 95 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 129 insertions(+), 0 deletions(-)
fs/nfs/blocklayout/blocklayout.c +32 -0
@@ -320,6 +320,30 @@ bl_read_pagelist(struct nfs_read_data *rdata)return PNFS_NOT_ATTEMPTED ; } +static void mark_extents_written (struct pnfs_block_layout *bl, +__u64 offset,__u32 count) +{ +sector_t isect, end; +struct pnfs_block_extent *be; + +dprintk ("%s(%llu, %u)\n" , __func__, offset, count); +if (count ==0 ) +return ; + isect = (offset & (long )(PAGE_CACHE_MASK )) >>9 ; + end = (offset + count +PAGE_CACHE_SIZE -1 ) & (long )(PAGE_CACHE_MASK ); + end >>=9 ; +while (isect < end) { +sector_t len; + be =find_get_extent (bl, isect,NULL ); +BUG_ON (!be);/* FIXME */ + len =min (end, be->be_f_offset + be->be_length) - isect; +if (be->be_state ==PNFS_BLOCK_INVALID_DATA ) +mark_for_commit (be, isect, len);/* What if fails? */ + isect += len; +put_extent (be); + } +} +/* STUB - this needs thought */ static inline void bl_done_with_wpage (struct page *page,const int ok)
@@ -367,6 +391,14 @@ static void bl_write_cleanup(struct work_struct *work)dprintk ("%s enter\n" , __func__); task = container_of(work, struct rpc_task, u.tk_work); wdata = container_of(task, struct nfs_write_data, task); +if (!wdata->task.tk_status) { +/* Marks for LAYOUTCOMMIT */ +/* BUG - this should be called after each bio, not after +* all finish, unless have some way of storing success/failure +*/ +mark_extents_written (BLK_LSEG2EXT (wdata->lseg), + wdata->args.offset, wdata->args.count); + }pnfs_ld_write_done (wdata); }
fs/nfs/blocklayout/blocklayout.h +2 -0
@@ -267,6 +267,8 @@ void clean_pnfs_block_layoutupdate(struct pnfs_block_layout *bl, int status);int add_and_merge_extent (struct pnfs_block_layout *bl,struct pnfs_block_extent *new); +int mark_for_commit (struct pnfs_block_extent *be, +sector_t offset,sector_t length);#include <linux/sunrpc/simple_rpc_pipefs.h>
fs/nfs/blocklayout/extents.c +95 -0
107 lines not on this page · raw message
Signature · 1 line
1.7.4.1
PATCH 32/33 pnfsblock: Implement release_inval_marks
In reply to Jim ReesFrom: Zhang Jingwang <[email protected]>
Leaving it unimplemented will cause memory leak.
--- fs/nfs/blocklayout/blocklayout.c | 7 ++++++- 1 files changed, 6 insertions(+), 1 deletions(-)
fs/nfs/blocklayout/blocklayout.c +6 -1
@@ -523,10 +523,15 @@ release_extents(struct pnfs_block_layout *bl, struct pnfs_layout_range *range)spin_unlock (&bl->bl_ext_lock); } -/* STUB */ static void release_inval_marks (struct pnfs_inval_markings *marks) { +struct pnfs_inval_tracking *pos, *temp; + +list_for_each_entry_safe (pos, temp, &marks->im_tree.mtt_stub, it_link) { +list_del (&pos->it_link); +kfree (pos); + }return ; }
Signature · 1 line
1.7.4.1
PATCH 33/33 pnfsblock DEVONLY: Add configurable prefetch size for layoutget
In reply to Jim ReesFrom: Peng Tao <[email protected]>
Do not send upstream. Only for dealing with servers that return small layouts.
pnfs_layout_prefetch_kb can be modified via sysctl. default to 0 so no effect if not set via sysctl.
--- fs/nfs/pnfs.c | 17 +++++++++++++++++ fs/nfs/pnfs.h | 1 + fs/nfs/sysctl.c | 10 ++++++++++ 3 files changed, 28 insertions(+), 0 deletions(-)
fs/nfs/pnfs.c +17 -0
@@ -46,6 +46,11 @@ static DEFINE_SPINLOCK(pnfs_spinlock);*/ static LIST_HEAD (pnfs_modules_tbl); +/* +* layoutget prefetch size +*/ +unsigned int pnfs_layout_prefetch_kb; +/* Return the registered pnfs layout driver module matching given id */ static struct pnfs_layoutdriver_type *find_pnfs_driver_locked (u32 id)
@@ -909,6 +914,16 @@ pnfs_find_lseg(struct pnfs_layout_hdr *lo, }/* +* Set layout prefetch length. +*/ +static void +pnfs_set_layout_prefetch (struct pnfs_layout_range *range) +{ +if (range->length < (pnfs_layout_prefetch_kb <<10 )) + range->length = pnfs_layout_prefetch_kb <<10 ; +} + +/* * Layout segment is retreived from the server if not cached. * The appropriate layout segment is referenced and returned to the caller. */
@@ -959,6 +974,8 @@ pnfs_update_layout(struct inode *ino,if (pnfs_layoutgets_blocked (lo,NULL ,0 )) goto out_unlock; + +pnfs_set_layout_prefetch (&arg);atomic_inc (&lo->plh_outstanding);get_layout_hdr (lo);
fs/nfs/pnfs.h +1 -0
@@ -180,6 +180,7 @@ extern int nfs4_proc_layoutget(struct nfs4_layoutget *lgp);extern int nfs4_proc_layoutreturn (struct nfs4_layoutreturn *lrp);/* pnfs.c */ +extern unsigned int pnfs_layout_prefetch_kb;void get_layout_hdr (struct pnfs_layout_hdr *lo);void put_lseg (struct pnfs_layout_segment *lseg);
fs/nfs/sysctl.c +10 -0
@@ -14,6 +14,7 @@#include <linux/nfs_fs.h> #include "callback.h" +#include "pnfs.h" #ifdef CONFIG_NFS_V4 static const int nfs_set_port_min =0 ;
@@ -42,6 +43,15 @@ static ctl_table nfs_cb_sysctls[] = { },#endif /* CONFIG_NFS_USE_NEW_IDMAPPER */ #endif +#ifdef CONFIG_NFS_V4_1 + { + .procname = "pnfs_layout_prefetch_kb", + .data = &pnfs_layout_prefetch_kb, + .maxlen = sizeof(pnfs_layout_prefetch_kb), + .mode = 0644, + .proc_handler = proc_dointvec, + }, +#endif { .procname = "nfs_mountpoint_timeout", .data = &nfs_mountpoint_expiry_timeout,
Signature · 1 line
1.7.4.1