Skip to content

Commit

Permalink
Merge tag 'nfs-for-3.17-1' of git://git.linux-nfs.org/projects/trondm…
Browse files Browse the repository at this point in the history
…y/linux-nfs

Pull NFS client updates from Trond Myklebust:
 "Highlights include:

   - stable fix for a bug in nfs3_list_one_acl()
   - speed up NFS path walks by supporting LOOKUP_RCU
   - more read/write code cleanups
   - pNFS fixes for layout return on close
   - fixes for the RCU handling in the rpcsec_gss code
   - more NFS/RDMA fixes"

* tag 'nfs-for-3.17-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: (79 commits)
  nfs: reject changes to resvport and sharecache during remount
  NFS: Avoid infinite loop when RELEASE_LOCKOWNER getting expired error
  SUNRPC: remove all refcounting of groupinfo from rpcauth_lookupcred
  NFS: fix two problems in lookup_revalidate in RCU-walk
  NFS: allow lockless access to access_cache
  NFS: teach nfs_lookup_verify_inode to handle LOOKUP_RCU
  NFS: teach nfs_neg_need_reval to understand LOOKUP_RCU
  NFS: support RCU_WALK in nfs_permission()
  sunrpc/auth: allow lockless (rcu) lookup of credential cache.
  NFS: prepare for RCU-walk support but pushing tests later in code.
  NFS: nfs4_lookup_revalidate: only evaluate parent if it will be used.
  NFS: add checks for returned value of try_module_get()
  nfs: clear_request_commit while holding i_lock
  pnfs: add pnfs_put_lseg_async
  pnfs: find swapped pages on pnfs commit lists too
  nfs: fix comment and add warn_on for PG_INODE_REF
  nfs: check wait_on_bit_lock err in page_group_lock
  sunrpc: remove "ec" argument from encrypt_v2 operation
  sunrpc: clean up sparse endianness warnings in gss_krb5_wrap.c
  sunrpc: clean up sparse endianness warnings in gss_krb5_seal.c
  ...
  • Loading branch information
Linus Torvalds committed Aug 14, 2014
2 parents dc1cc85 + 71a6ec8 commit 06b8ab5
Show file tree
Hide file tree
Showing 54 changed files with 1,967 additions and 1,288 deletions.
101 changes: 50 additions & 51 deletions fs/nfs/blocklayout/blocklayout.c
Original file line number Diff line number Diff line change
Expand Up @@ -210,8 +210,7 @@ static void bl_end_io_read(struct bio *bio, int err)
SetPageUptodate(bvec->bv_page);

if (err) {
struct nfs_pgio_data *rdata = par->data;
struct nfs_pgio_header *header = rdata->header;
struct nfs_pgio_header *header = par->data;

if (!header->pnfs_error)
header->pnfs_error = -EIO;
Expand All @@ -224,51 +223,52 @@ static void bl_end_io_read(struct bio *bio, int err)
static void bl_read_cleanup(struct work_struct *work)
{
struct rpc_task *task;
struct nfs_pgio_data *rdata;
struct nfs_pgio_header *hdr;
dprintk("%s enter\n", __func__);
task = container_of(work, struct rpc_task, u.tk_work);
rdata = container_of(task, struct nfs_pgio_data, task);
pnfs_ld_read_done(rdata);
hdr = container_of(task, struct nfs_pgio_header, task);
pnfs_ld_read_done(hdr);
}

static void
bl_end_par_io_read(void *data, int unused)
{
struct nfs_pgio_data *rdata = data;
struct nfs_pgio_header *hdr = data;

rdata->task.tk_status = rdata->header->pnfs_error;
INIT_WORK(&rdata->task.u.tk_work, bl_read_cleanup);
schedule_work(&rdata->task.u.tk_work);
hdr->task.tk_status = hdr->pnfs_error;
INIT_WORK(&hdr->task.u.tk_work, bl_read_cleanup);
schedule_work(&hdr->task.u.tk_work);
}

static enum pnfs_try_status
bl_read_pagelist(struct nfs_pgio_data *rdata)
bl_read_pagelist(struct nfs_pgio_header *hdr)
{
struct nfs_pgio_header *header = rdata->header;
struct nfs_pgio_header *header = hdr;
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 bytes_left = rdata->args.count;
loff_t f_offset = hdr->args.offset;
size_t bytes_left = hdr->args.count;
unsigned int pg_offset, pg_len;
struct page **pages = rdata->args.pages;
int pg_index = rdata->args.pgbase >> PAGE_CACHE_SHIFT;
struct page **pages = hdr->args.pages;
int pg_index = hdr->args.pgbase >> PAGE_CACHE_SHIFT;
const bool is_dio = (header->dreq != NULL);

dprintk("%s enter nr_pages %u offset %lld count %u\n", __func__,
rdata->pages.npages, f_offset, (unsigned int)rdata->args.count);
hdr->page_array.npages, f_offset,
(unsigned int)hdr->args.count);

par = alloc_parallel(rdata);
par = alloc_parallel(hdr);
if (!par)
goto use_mds;
par->pnfs_callback = bl_end_par_io_read;
/* At this point, we can no longer jump to use_mds */

isect = (sector_t) (f_offset >> SECTOR_SHIFT);
/* Code assumes extents are page-aligned */
for (i = pg_index; i < rdata->pages.npages; i++) {
for (i = pg_index; i < hdr->page_array.npages; i++) {
if (!extent_length) {
/* We've used up the previous extent */
bl_put_extent(be);
Expand Down Expand Up @@ -317,7 +317,8 @@ bl_read_pagelist(struct nfs_pgio_data *rdata)
struct pnfs_block_extent *be_read;

be_read = (hole && cow_read) ? cow_read : be;
bio = do_add_page_to_bio(bio, rdata->pages.npages - i,
bio = do_add_page_to_bio(bio,
hdr->page_array.npages - i,
READ,
isect, pages[i], be_read,
bl_end_io_read, par,
Expand All @@ -332,10 +333,10 @@ bl_read_pagelist(struct nfs_pgio_data *rdata)
extent_length -= PAGE_CACHE_SECTORS;
}
if ((isect << SECTOR_SHIFT) >= header->inode->i_size) {
rdata->res.eof = 1;
rdata->res.count = header->inode->i_size - rdata->args.offset;
hdr->res.eof = 1;
hdr->res.count = header->inode->i_size - hdr->args.offset;
} else {
rdata->res.count = (isect << SECTOR_SHIFT) - rdata->args.offset;
hdr->res.count = (isect << SECTOR_SHIFT) - hdr->args.offset;
}
out:
bl_put_extent(be);
Expand Down Expand Up @@ -390,8 +391,7 @@ static void bl_end_io_write_zero(struct bio *bio, int err)
}

if (unlikely(err)) {
struct nfs_pgio_data *data = par->data;
struct nfs_pgio_header *header = data->header;
struct nfs_pgio_header *header = par->data;

if (!header->pnfs_error)
header->pnfs_error = -EIO;
Expand All @@ -405,8 +405,7 @@ static void bl_end_io_write(struct bio *bio, int err)
{
struct parallel_io *par = bio->bi_private;
const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
struct nfs_pgio_data *data = par->data;
struct nfs_pgio_header *header = data->header;
struct nfs_pgio_header *header = par->data;

if (!uptodate) {
if (!header->pnfs_error)
Expand All @@ -423,32 +422,32 @@ static void bl_end_io_write(struct bio *bio, int err)
static void bl_write_cleanup(struct work_struct *work)
{
struct rpc_task *task;
struct nfs_pgio_data *wdata;
struct nfs_pgio_header *hdr;
dprintk("%s enter\n", __func__);
task = container_of(work, struct rpc_task, u.tk_work);
wdata = container_of(task, struct nfs_pgio_data, task);
if (likely(!wdata->header->pnfs_error)) {
hdr = container_of(task, struct nfs_pgio_header, task);
if (likely(!hdr->pnfs_error)) {
/* Marks for LAYOUTCOMMIT */
mark_extents_written(BLK_LSEG2EXT(wdata->header->lseg),
wdata->args.offset, wdata->args.count);
mark_extents_written(BLK_LSEG2EXT(hdr->lseg),
hdr->args.offset, hdr->args.count);
}
pnfs_ld_write_done(wdata);
pnfs_ld_write_done(hdr);
}

/* Called when last of bios associated with a bl_write_pagelist call finishes */
static void bl_end_par_io_write(void *data, int num_se)
{
struct nfs_pgio_data *wdata = data;
struct nfs_pgio_header *hdr = data;

if (unlikely(wdata->header->pnfs_error)) {
bl_free_short_extents(&BLK_LSEG2EXT(wdata->header->lseg)->bl_inval,
if (unlikely(hdr->pnfs_error)) {
bl_free_short_extents(&BLK_LSEG2EXT(hdr->lseg)->bl_inval,
num_se);
}

wdata->task.tk_status = wdata->header->pnfs_error;
wdata->verf.committed = NFS_FILE_SYNC;
INIT_WORK(&wdata->task.u.tk_work, bl_write_cleanup);
schedule_work(&wdata->task.u.tk_work);
hdr->task.tk_status = hdr->pnfs_error;
hdr->verf.committed = NFS_FILE_SYNC;
INIT_WORK(&hdr->task.u.tk_work, bl_write_cleanup);
schedule_work(&hdr->task.u.tk_work);
}

/* FIXME STUB - mark intersection of layout and page as bad, so is not
Expand Down Expand Up @@ -673,18 +672,17 @@ bl_find_get_zeroing_page(struct inode *inode, pgoff_t index,
}

static enum pnfs_try_status
bl_write_pagelist(struct nfs_pgio_data *wdata, int sync)
bl_write_pagelist(struct nfs_pgio_header *header, int sync)
{
struct nfs_pgio_header *header = wdata->header;
int i, ret, npg_zero, pg_index, last = 0;
struct bio *bio = NULL;
struct pnfs_block_extent *be = NULL, *cow_read = NULL;
sector_t isect, last_isect = 0, extent_length = 0;
struct parallel_io *par = NULL;
loff_t offset = wdata->args.offset;
size_t count = wdata->args.count;
loff_t offset = header->args.offset;
size_t count = header->args.count;
unsigned int pg_offset, pg_len, saved_len;
struct page **pages = wdata->args.pages;
struct page **pages = header->args.pages;
struct page *page;
pgoff_t index;
u64 temp;
Expand All @@ -699,11 +697,11 @@ bl_write_pagelist(struct nfs_pgio_data *wdata, int sync)
dprintk("pnfsblock nonblock aligned DIO writes. Resend MDS\n");
goto out_mds;
}
/* At this point, wdata->pages is a (sequential) list of nfs_pages.
/* At this point, header->page_aray is a (sequential) list of nfs_pages.
* We want to write each, and if there is an error set pnfs_error
* to have it redone using nfs.
*/
par = alloc_parallel(wdata);
par = alloc_parallel(header);
if (!par)
goto out_mds;
par->pnfs_callback = bl_end_par_io_write;
Expand Down Expand Up @@ -790,8 +788,8 @@ bl_write_pagelist(struct nfs_pgio_data *wdata, int sync)
bio = bl_submit_bio(WRITE, bio);

/* Middle pages */
pg_index = wdata->args.pgbase >> PAGE_CACHE_SHIFT;
for (i = pg_index; i < wdata->pages.npages; i++) {
pg_index = header->args.pgbase >> PAGE_CACHE_SHIFT;
for (i = pg_index; i < header->page_array.npages; i++) {
if (!extent_length) {
/* We've used up the previous extent */
bl_put_extent(be);
Expand Down Expand Up @@ -862,7 +860,8 @@ bl_write_pagelist(struct nfs_pgio_data *wdata, int sync)
}


bio = do_add_page_to_bio(bio, wdata->pages.npages - i, WRITE,
bio = do_add_page_to_bio(bio, header->page_array.npages - i,
WRITE,
isect, pages[i], be,
bl_end_io_write, par,
pg_offset, pg_len);
Expand Down Expand Up @@ -890,7 +889,7 @@ bl_write_pagelist(struct nfs_pgio_data *wdata, int sync)
}

write_done:
wdata->res.count = wdata->args.count;
header->res.count = header->args.count;
out:
bl_put_extent(be);
bl_put_extent(cow_read);
Expand Down Expand Up @@ -1063,7 +1062,7 @@ nfs4_blk_get_deviceinfo(struct nfs_server *server, const struct nfs_fh *fh,
return ERR_PTR(-ENOMEM);
}

pages = kzalloc(max_pages * sizeof(struct page *), GFP_NOFS);
pages = kcalloc(max_pages, sizeof(struct page *), GFP_NOFS);
if (pages == NULL) {
kfree(dev);
return ERR_PTR(-ENOMEM);
Expand Down
12 changes: 12 additions & 0 deletions fs/nfs/callback.c
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,18 @@ check_gss_callback_principal(struct nfs_client *clp, struct svc_rqst *rqstp)
if (p == NULL)
return 0;

/*
* Did we get the acceptor from userland during the SETCLIENID
* negotiation?
*/
if (clp->cl_acceptor)
return !strcmp(p, clp->cl_acceptor);

/*
* Otherwise try to verify it using the cl_hostname. Note that this
* doesn't work if a non-canonical hostname was used in the devname.
*/

/* Expect a GSS_C_NT_HOSTBASED_NAME like "nfs@serverhostname" */

if (memcmp(p, "nfs@", 4) != 0)
Expand Down
18 changes: 13 additions & 5 deletions fs/nfs/client.c
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,8 @@ struct nfs_subversion *get_nfs_version(unsigned int version)
mutex_unlock(&nfs_version_mutex);
}

if (!IS_ERR(nfs))
try_module_get(nfs->owner);
if (!IS_ERR(nfs) && !try_module_get(nfs->owner))
return ERR_PTR(-EAGAIN);
return nfs;
}

Expand Down Expand Up @@ -158,7 +158,8 @@ struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_init)
goto error_0;

clp->cl_nfs_mod = cl_init->nfs_mod;
try_module_get(clp->cl_nfs_mod->owner);
if (!try_module_get(clp->cl_nfs_mod->owner))
goto error_dealloc;

clp->rpc_ops = clp->cl_nfs_mod->rpc_ops;

Expand Down Expand Up @@ -190,6 +191,7 @@ struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_init)

error_cleanup:
put_nfs_version(clp->cl_nfs_mod);
error_dealloc:
kfree(clp);
error_0:
return ERR_PTR(err);
Expand Down Expand Up @@ -252,6 +254,7 @@ void nfs_free_client(struct nfs_client *clp)
put_net(clp->cl_net);
put_nfs_version(clp->cl_nfs_mod);
kfree(clp->cl_hostname);
kfree(clp->cl_acceptor);
kfree(clp);

dprintk("<-- nfs_free_client()\n");
Expand Down Expand Up @@ -482,8 +485,13 @@ nfs_get_client(const struct nfs_client_initdata *cl_init,
struct nfs_net *nn = net_generic(cl_init->net, nfs_net_id);
const struct nfs_rpc_ops *rpc_ops = cl_init->nfs_mod->rpc_ops;

if (cl_init->hostname == NULL) {
WARN_ON(1);
return NULL;
}

dprintk("--> nfs_get_client(%s,v%u)\n",
cl_init->hostname ?: "", rpc_ops->version);
cl_init->hostname, rpc_ops->version);

/* see if the client already exists */
do {
Expand All @@ -510,7 +518,7 @@ nfs_get_client(const struct nfs_client_initdata *cl_init,
} while (!IS_ERR(new));

dprintk("<-- nfs_get_client() Failed to find %s (%ld)\n",
cl_init->hostname ?: "", PTR_ERR(new));
cl_init->hostname, PTR_ERR(new));
return new;
}
EXPORT_SYMBOL_GPL(nfs_get_client);
Expand Down
34 changes: 25 additions & 9 deletions fs/nfs/delegation.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,8 @@ void nfs_mark_delegation_referenced(struct nfs_delegation *delegation)
set_bit(NFS_DELEGATION_REFERENCED, &delegation->flags);
}

/**
* nfs_have_delegation - check if inode has a delegation
* @inode: inode to check
* @flags: delegation types to check for
*
* Returns one if inode has the indicated delegation, otherwise zero.
*/
int nfs4_have_delegation(struct inode *inode, fmode_t flags)
static int
nfs4_do_check_delegation(struct inode *inode, fmode_t flags, bool mark)
{
struct nfs_delegation *delegation;
int ret = 0;
Expand All @@ -58,12 +52,34 @@ int nfs4_have_delegation(struct inode *inode, fmode_t flags)
delegation = rcu_dereference(NFS_I(inode)->delegation);
if (delegation != NULL && (delegation->type & flags) == flags &&
!test_bit(NFS_DELEGATION_RETURNING, &delegation->flags)) {
nfs_mark_delegation_referenced(delegation);
if (mark)
nfs_mark_delegation_referenced(delegation);
ret = 1;
}
rcu_read_unlock();
return ret;
}
/**
* nfs_have_delegation - check if inode has a delegation, mark it
* NFS_DELEGATION_REFERENCED if there is one.
* @inode: inode to check
* @flags: delegation types to check for
*
* Returns one if inode has the indicated delegation, otherwise zero.
*/
int nfs4_have_delegation(struct inode *inode, fmode_t flags)
{
return nfs4_do_check_delegation(inode, flags, true);
}

/*
* nfs4_check_delegation - check if inode has a delegation, do not mark
* NFS_DELEGATION_REFERENCED if it has one.
*/
int nfs4_check_delegation(struct inode *inode, fmode_t flags)
{
return nfs4_do_check_delegation(inode, flags, false);
}

static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid)
{
Expand Down
1 change: 1 addition & 0 deletions fs/nfs/delegation.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ bool nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode, fmode_

void nfs_mark_delegation_referenced(struct nfs_delegation *delegation);
int nfs4_have_delegation(struct inode *inode, fmode_t flags);
int nfs4_check_delegation(struct inode *inode, fmode_t flags);

#endif

Expand Down
Loading

0 comments on commit 06b8ab5

Please sign in to comment.