Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 229229
b: refs/heads/master
c: 4541d16
h: refs/heads/master
i:
  229227: ca33536
v: v3
  • Loading branch information
Fred Isaman authored and Trond Myklebust committed Jan 6, 2011
1 parent a8ed03c commit c101867
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 45 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: fd6002e9b8a93220d5f53b93d9624caf73cdc8a2
refs/heads/master: 4541d16c024ce40a0781e03c185ecdfe34aec46f
2 changes: 1 addition & 1 deletion trunk/fs/nfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -1410,9 +1410,9 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
*/
void nfs4_evict_inode(struct inode *inode)
{
pnfs_destroy_layout(NFS_I(inode));
truncate_inode_pages(&inode->i_data, 0);
end_writeback(inode);
pnfs_destroy_layout(NFS_I(inode));
/* If we are holding a delegation, return it! */
nfs_inode_return_delegation_noreclaim(inode);
/* First call standard NFS clear_inode() code */
Expand Down
130 changes: 88 additions & 42 deletions trunk/fs/nfs/pnfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -211,68 +211,109 @@ static void
init_lseg(struct pnfs_layout_hdr *lo, struct pnfs_layout_segment *lseg)
{
INIT_LIST_HEAD(&lseg->pls_list);
kref_init(&lseg->pls_refcount);
atomic_set(&lseg->pls_refcount, 1);
smp_mb();
set_bit(NFS_LSEG_VALID, &lseg->pls_flags);
lseg->pls_layout = lo;
}

/* Called without i_lock held, as the free_lseg call may sleep */
static void
destroy_lseg(struct kref *kref)
static void free_lseg(struct pnfs_layout_segment *lseg)
{
struct pnfs_layout_segment *lseg =
container_of(kref, struct pnfs_layout_segment, pls_refcount);
struct inode *ino = lseg->pls_layout->plh_inode;

dprintk("--> %s\n", __func__);
NFS_SERVER(ino)->pnfs_curr_ld->free_lseg(lseg);
/* Matched by get_layout_hdr in pnfs_insert_layout */
put_layout_hdr(ino);
}

static void
put_lseg(struct pnfs_layout_segment *lseg)
/* The use of tmp_list is necessary because pnfs_curr_ld->free_lseg
* could sleep, so must be called outside of the lock.
* Returns 1 if object was removed, otherwise return 0.
*/
static int
put_lseg_locked(struct pnfs_layout_segment *lseg,
struct list_head *tmp_list)
{
if (!lseg)
return;
dprintk("%s: lseg %p ref %d valid %d\n", __func__, lseg,
atomic_read(&lseg->pls_refcount),
test_bit(NFS_LSEG_VALID, &lseg->pls_flags));
if (atomic_dec_and_test(&lseg->pls_refcount)) {
struct inode *ino = lseg->pls_layout->plh_inode;

dprintk("%s: lseg %p ref %d\n", __func__, lseg,
atomic_read(&lseg->pls_refcount.refcount));
kref_put(&lseg->pls_refcount, destroy_lseg);
BUG_ON(test_bit(NFS_LSEG_VALID, &lseg->pls_flags));
list_del(&lseg->pls_list);
if (list_empty(&lseg->pls_layout->plh_segs)) {
struct nfs_client *clp;

clp = NFS_SERVER(ino)->nfs_client;
spin_lock(&clp->cl_lock);
/* List does not take a reference, so no need for put here */
list_del_init(&lseg->pls_layout->plh_layouts);
spin_unlock(&clp->cl_lock);
}
list_add(&lseg->pls_list, tmp_list);
return 1;
}
return 0;
}

static void
pnfs_clear_lseg_list(struct pnfs_layout_hdr *lo, struct list_head *tmp_list)
static bool
should_free_lseg(u32 lseg_iomode, u32 recall_iomode)
{
struct pnfs_layout_segment *lseg, *next;
struct nfs_client *clp;
return (recall_iomode == IOMODE_ANY ||
lseg_iomode == recall_iomode);
}

dprintk("%s:Begin lo %p\n", __func__, lo);
/* Returns 1 if lseg is removed from list, 0 otherwise */
static int mark_lseg_invalid(struct pnfs_layout_segment *lseg,
struct list_head *tmp_list)
{
int rv = 0;

assert_spin_locked(&lo->plh_inode->i_lock);
list_for_each_entry_safe(lseg, next, &lo->plh_segs, pls_list) {
dprintk("%s: freeing lseg %p\n", __func__, lseg);
list_move(&lseg->pls_list, tmp_list);
if (test_and_clear_bit(NFS_LSEG_VALID, &lseg->pls_flags)) {
/* Remove the reference keeping the lseg in the
* list. It will now be removed when all
* outstanding io is finished.
*/
rv = put_lseg_locked(lseg, tmp_list);
}
clp = NFS_SERVER(lo->plh_inode)->nfs_client;
spin_lock(&clp->cl_lock);
/* List does not take a reference, so no need for put here */
list_del_init(&lo->plh_layouts);
spin_unlock(&clp->cl_lock);
return rv;
}

dprintk("%s:Return\n", __func__);
/* Returns count of number of matching invalid lsegs remaining in list
* after call.
*/
static int
mark_matching_lsegs_invalid(struct pnfs_layout_hdr *lo,
struct list_head *tmp_list,
u32 iomode)
{
struct pnfs_layout_segment *lseg, *next;
int invalid = 0, removed = 0;

dprintk("%s:Begin lo %p\n", __func__, lo);

list_for_each_entry_safe(lseg, next, &lo->plh_segs, pls_list)
if (should_free_lseg(lseg->pls_range.iomode, iomode)) {
dprintk("%s: freeing lseg %p iomode %d "
"offset %llu length %llu\n", __func__,
lseg, lseg->pls_range.iomode, lseg->pls_range.offset,
lseg->pls_range.length);
invalid++;
removed += mark_lseg_invalid(lseg, tmp_list);
}
dprintk("%s:Return %i\n", __func__, invalid - removed);
return invalid - removed;
}

static void
pnfs_free_lseg_list(struct list_head *tmp_list)
pnfs_free_lseg_list(struct list_head *free_me)
{
struct pnfs_layout_segment *lseg;
struct pnfs_layout_segment *lseg, *tmp;

while (!list_empty(tmp_list)) {
lseg = list_entry(tmp_list->next, struct pnfs_layout_segment,
pls_list);
dprintk("%s calling put_lseg on %p\n", __func__, lseg);
list_for_each_entry_safe(lseg, tmp, free_me, pls_list) {
list_del(&lseg->pls_list);
put_lseg(lseg);
free_lseg(lseg);
}
}

Expand All @@ -285,7 +326,8 @@ pnfs_destroy_layout(struct nfs_inode *nfsi)
spin_lock(&nfsi->vfs_inode.i_lock);
lo = nfsi->layout;
if (lo) {
pnfs_clear_lseg_list(lo, &tmp_list);
set_bit(NFS_LAYOUT_DESTROYED, &nfsi->layout->plh_flags);
mark_matching_lsegs_invalid(lo, &tmp_list, IOMODE_ANY);
/* Matched by refcount set to 1 in alloc_init_layout_hdr */
put_layout_hdr_locked(lo);
}
Expand Down Expand Up @@ -477,9 +519,12 @@ pnfs_find_alloc_layout(struct inode *ino)
dprintk("%s Begin ino=%p layout=%p\n", __func__, ino, nfsi->layout);

assert_spin_locked(&ino->i_lock);
if (nfsi->layout)
return nfsi->layout;

if (nfsi->layout) {
if (test_bit(NFS_LAYOUT_DESTROYED, &nfsi->layout->plh_flags))
return NULL;
else
return nfsi->layout;
}
spin_unlock(&ino->i_lock);
new = alloc_init_layout_hdr(ino);
spin_lock(&ino->i_lock);
Expand Down Expand Up @@ -520,7 +565,8 @@ pnfs_has_layout(struct pnfs_layout_hdr *lo, u32 iomode)

assert_spin_locked(&lo->plh_inode->i_lock);
list_for_each_entry(lseg, &lo->plh_segs, pls_list) {
if (is_matching_lseg(lseg, iomode)) {
if (test_bit(NFS_LSEG_VALID, &lseg->pls_flags) &&
is_matching_lseg(lseg, iomode)) {
ret = lseg;
break;
}
Expand All @@ -529,7 +575,7 @@ pnfs_has_layout(struct pnfs_layout_hdr *lo, u32 iomode)
}

dprintk("%s:Return lseg %p ref %d\n",
__func__, ret, ret ? atomic_read(&ret->pls_refcount.refcount) : 0);
__func__, ret, ret ? atomic_read(&ret->pls_refcount) : 0);
return ret;
}

Expand Down
8 changes: 7 additions & 1 deletion trunk/fs/nfs/pnfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,15 @@
#ifndef FS_NFS_PNFS_H
#define FS_NFS_PNFS_H

enum {
NFS_LSEG_VALID = 0, /* cleared when lseg is recalled/returned */
};

struct pnfs_layout_segment {
struct list_head pls_list;
struct pnfs_layout_range pls_range;
struct kref pls_refcount;
atomic_t pls_refcount;
unsigned long pls_flags;
struct pnfs_layout_hdr *pls_layout;
};

Expand All @@ -44,6 +49,7 @@ struct pnfs_layout_segment {
enum {
NFS_LAYOUT_RO_FAILED = 0, /* get ro layout failed stop trying */
NFS_LAYOUT_RW_FAILED, /* get rw layout failed stop trying */
NFS_LAYOUT_DESTROYED, /* no new use of layout allowed */
};

/* Per-layout driver specific registration structure */
Expand Down

0 comments on commit c101867

Please sign in to comment.