aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/ext4/extents.c9
-rw-r--r--fs/jfs/resize.c6
-rw-r--r--fs/nfs/client.c2
-rw-r--r--fs/nfs/dir.c2
-rw-r--r--fs/nfsd/nfs4xdr.c8
-rw-r--r--fs/ocfs2/buffer_head_io.c2
-rw-r--r--fs/ocfs2/dlm/dlmfs.c2
-rw-r--r--fs/ocfs2/inode.c1
-rw-r--r--fs/ocfs2/refcounttree.c3
-rw-r--r--fs/proc/base.c2
-rw-r--r--fs/reiserfs/dir.c2
-rw-r--r--fs/reiserfs/xattr.c19
-rw-r--r--fs/xfs/linux-2.6/xfs_super.c5
-rw-r--r--fs/xfs/linux-2.6/xfs_sync.c107
-rw-r--r--fs/xfs/linux-2.6/xfs_sync.h7
-rw-r--r--fs/xfs/quota/xfs_qm_syscalls.c3
-rw-r--r--fs/xfs/xfs_ag.h1
-rw-r--r--fs/xfs/xfs_mount.h1
18 files changed, 148 insertions, 34 deletions
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index c56877972b0e..cae75c122ea4 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -3767,7 +3767,6 @@ int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
3767 __u64 start, __u64 len) 3767 __u64 start, __u64 len)
3768{ 3768{
3769 ext4_lblk_t start_blk; 3769 ext4_lblk_t start_blk;
3770 ext4_lblk_t len_blks;
3771 int error = 0; 3770 int error = 0;
3772 3771
3773 /* fallback to generic here if not in extents fmt */ 3772 /* fallback to generic here if not in extents fmt */
@@ -3781,8 +3780,14 @@ int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
3781 if (fieinfo->fi_flags & FIEMAP_FLAG_XATTR) { 3780 if (fieinfo->fi_flags & FIEMAP_FLAG_XATTR) {
3782 error = ext4_xattr_fiemap(inode, fieinfo); 3781 error = ext4_xattr_fiemap(inode, fieinfo);
3783 } else { 3782 } else {
3783 ext4_lblk_t len_blks;
3784 __u64 last_blk;
3785
3784 start_blk = start >> inode->i_sb->s_blocksize_bits; 3786 start_blk = start >> inode->i_sb->s_blocksize_bits;
3785 len_blks = len >> inode->i_sb->s_blocksize_bits; 3787 last_blk = (start + len - 1) >> inode->i_sb->s_blocksize_bits;
3788 if (last_blk >= EXT_MAX_BLOCK)
3789 last_blk = EXT_MAX_BLOCK-1;
3790 len_blks = ((ext4_lblk_t) last_blk) - start_blk + 1;
3786 3791
3787 /* 3792 /*
3788 * Walk the extent tree gathering extent information. 3793 * Walk the extent tree gathering extent information.
diff --git a/fs/jfs/resize.c b/fs/jfs/resize.c
index 7f24a0bb08ca..1aba0039f1c9 100644
--- a/fs/jfs/resize.c
+++ b/fs/jfs/resize.c
@@ -81,6 +81,7 @@ int jfs_extendfs(struct super_block *sb, s64 newLVSize, int newLogSize)
81 struct inode *iplist[1]; 81 struct inode *iplist[1];
82 struct jfs_superblock *j_sb, *j_sb2; 82 struct jfs_superblock *j_sb, *j_sb2;
83 uint old_agsize; 83 uint old_agsize;
84 int agsizechanged = 0;
84 struct buffer_head *bh, *bh2; 85 struct buffer_head *bh, *bh2;
85 86
86 /* If the volume hasn't grown, get out now */ 87 /* If the volume hasn't grown, get out now */
@@ -333,6 +334,9 @@ int jfs_extendfs(struct super_block *sb, s64 newLVSize, int newLogSize)
333 */ 334 */
334 if ((rc = dbExtendFS(ipbmap, XAddress, nblocks))) 335 if ((rc = dbExtendFS(ipbmap, XAddress, nblocks)))
335 goto error_out; 336 goto error_out;
337
338 agsizechanged |= (bmp->db_agsize != old_agsize);
339
336 /* 340 /*
337 * the map now has extended to cover additional nblocks: 341 * the map now has extended to cover additional nblocks:
338 * dn_mapsize = oldMapsize + nblocks; 342 * dn_mapsize = oldMapsize + nblocks;
@@ -432,7 +436,7 @@ int jfs_extendfs(struct super_block *sb, s64 newLVSize, int newLogSize)
432 * will correctly identify the new ag); 436 * will correctly identify the new ag);
433 */ 437 */
434 /* if new AG size the same as old AG size, done! */ 438 /* if new AG size the same as old AG size, done! */
435 if (bmp->db_agsize != old_agsize) { 439 if (agsizechanged) {
436 if ((rc = diExtendFS(ipimap, ipbmap))) 440 if ((rc = diExtendFS(ipimap, ipbmap)))
437 goto error_out; 441 goto error_out;
438 442
diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index bd39abc51508..37d555c32cd8 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -965,6 +965,8 @@ out_error:
965static void nfs_server_copy_userdata(struct nfs_server *target, struct nfs_server *source) 965static void nfs_server_copy_userdata(struct nfs_server *target, struct nfs_server *source)
966{ 966{
967 target->flags = source->flags; 967 target->flags = source->flags;
968 target->rsize = source->rsize;
969 target->wsize = source->wsize;
968 target->acregmin = source->acregmin; 970 target->acregmin = source->acregmin;
969 target->acregmax = source->acregmax; 971 target->acregmax = source->acregmax;
970 target->acdirmin = source->acdirmin; 972 target->acdirmin = source->acdirmin;
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index d896d3e55024..01a0b9acb1f8 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -837,6 +837,8 @@ out_zap_parent:
837 /* If we have submounts, don't unhash ! */ 837 /* If we have submounts, don't unhash ! */
838 if (have_submounts(dentry)) 838 if (have_submounts(dentry))
839 goto out_valid; 839 goto out_valid;
840 if (dentry->d_flags & DCACHE_DISCONNECTED)
841 goto out_valid;
840 shrink_dcache_parent(dentry); 842 shrink_dcache_parent(dentry);
841 } 843 }
842 d_drop(dentry); 844 d_drop(dentry);
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index bbf72d8f9fc0..718f3fb312d0 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -160,10 +160,10 @@ static __be32 *read_buf(struct nfsd4_compoundargs *argp, u32 nbytes)
160 argp->p = page_address(argp->pagelist[0]); 160 argp->p = page_address(argp->pagelist[0]);
161 argp->pagelist++; 161 argp->pagelist++;
162 if (argp->pagelen < PAGE_SIZE) { 162 if (argp->pagelen < PAGE_SIZE) {
163 argp->end = p + (argp->pagelen>>2); 163 argp->end = argp->p + (argp->pagelen>>2);
164 argp->pagelen = 0; 164 argp->pagelen = 0;
165 } else { 165 } else {
166 argp->end = p + (PAGE_SIZE>>2); 166 argp->end = argp->p + (PAGE_SIZE>>2);
167 argp->pagelen -= PAGE_SIZE; 167 argp->pagelen -= PAGE_SIZE;
168 } 168 }
169 memcpy(((char*)p)+avail, argp->p, (nbytes - avail)); 169 memcpy(((char*)p)+avail, argp->p, (nbytes - avail));
@@ -1425,10 +1425,10 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
1425 argp->p = page_address(argp->pagelist[0]); 1425 argp->p = page_address(argp->pagelist[0]);
1426 argp->pagelist++; 1426 argp->pagelist++;
1427 if (argp->pagelen < PAGE_SIZE) { 1427 if (argp->pagelen < PAGE_SIZE) {
1428 argp->end = p + (argp->pagelen>>2); 1428 argp->end = argp->p + (argp->pagelen>>2);
1429 argp->pagelen = 0; 1429 argp->pagelen = 0;
1430 } else { 1430 } else {
1431 argp->end = p + (PAGE_SIZE>>2); 1431 argp->end = argp->p + (PAGE_SIZE>>2);
1432 argp->pagelen -= PAGE_SIZE; 1432 argp->pagelen -= PAGE_SIZE;
1433 } 1433 }
1434 } 1434 }
diff --git a/fs/ocfs2/buffer_head_io.c b/fs/ocfs2/buffer_head_io.c
index 21c808f752d8..b18c6d677f9d 100644
--- a/fs/ocfs2/buffer_head_io.c
+++ b/fs/ocfs2/buffer_head_io.c
@@ -407,6 +407,7 @@ int ocfs2_write_super_or_backup(struct ocfs2_super *osb,
407 struct buffer_head *bh) 407 struct buffer_head *bh)
408{ 408{
409 int ret = 0; 409 int ret = 0;
410 struct ocfs2_dinode *di = (struct ocfs2_dinode *)bh->b_data;
410 411
411 mlog_entry_void(); 412 mlog_entry_void();
412 413
@@ -426,6 +427,7 @@ int ocfs2_write_super_or_backup(struct ocfs2_super *osb,
426 427
427 get_bh(bh); /* for end_buffer_write_sync() */ 428 get_bh(bh); /* for end_buffer_write_sync() */
428 bh->b_end_io = end_buffer_write_sync; 429 bh->b_end_io = end_buffer_write_sync;
430 ocfs2_compute_meta_ecc(osb->sb, bh->b_data, &di->i_check);
429 submit_bh(WRITE, bh); 431 submit_bh(WRITE, bh);
430 432
431 wait_on_buffer(bh); 433 wait_on_buffer(bh);
diff --git a/fs/ocfs2/dlm/dlmfs.c b/fs/ocfs2/dlm/dlmfs.c
index 02bf17808bdc..18bc101d603f 100644
--- a/fs/ocfs2/dlm/dlmfs.c
+++ b/fs/ocfs2/dlm/dlmfs.c
@@ -205,7 +205,7 @@ static ssize_t dlmfs_file_read(struct file *filp,
205 if ((count + *ppos) > i_size_read(inode)) 205 if ((count + *ppos) > i_size_read(inode))
206 readlen = i_size_read(inode) - *ppos; 206 readlen = i_size_read(inode) - *ppos;
207 else 207 else
208 readlen = count - *ppos; 208 readlen = count;
209 209
210 lvb_buf = kmalloc(readlen, GFP_NOFS); 210 lvb_buf = kmalloc(readlen, GFP_NOFS);
211 if (!lvb_buf) 211 if (!lvb_buf)
diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c
index 88459bdd1ff3..ec4d97faffbf 100644
--- a/fs/ocfs2/inode.c
+++ b/fs/ocfs2/inode.c
@@ -559,6 +559,7 @@ static int ocfs2_truncate_for_delete(struct ocfs2_super *osb,
559 handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS); 559 handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS);
560 if (IS_ERR(handle)) { 560 if (IS_ERR(handle)) {
561 status = PTR_ERR(handle); 561 status = PTR_ERR(handle);
562 handle = NULL;
562 mlog_errno(status); 563 mlog_errno(status);
563 goto out; 564 goto out;
564 } 565 }
diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c
index 8ae65c9c020c..a8e85720d1f4 100644
--- a/fs/ocfs2/refcounttree.c
+++ b/fs/ocfs2/refcounttree.c
@@ -4083,6 +4083,9 @@ static int ocfs2_complete_reflink(struct inode *s_inode,
4083 di->i_attr = s_di->i_attr; 4083 di->i_attr = s_di->i_attr;
4084 4084
4085 if (preserve) { 4085 if (preserve) {
4086 t_inode->i_uid = s_inode->i_uid;
4087 t_inode->i_gid = s_inode->i_gid;
4088 t_inode->i_mode = s_inode->i_mode;
4086 di->i_uid = s_di->i_uid; 4089 di->i_uid = s_di->i_uid;
4087 di->i_gid = s_di->i_gid; 4090 di->i_gid = s_di->i_gid;
4088 di->i_mode = s_di->i_mode; 4091 di->i_mode = s_di->i_mode;
diff --git a/fs/proc/base.c b/fs/proc/base.c
index d59e279874c7..6ab0bd692968 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -2912,7 +2912,7 @@ out_no_task:
2912 */ 2912 */
2913static const struct pid_entry tid_base_stuff[] = { 2913static const struct pid_entry tid_base_stuff[] = {
2914 DIR("fd", S_IRUSR|S_IXUSR, proc_fd_inode_operations, proc_fd_operations), 2914 DIR("fd", S_IRUSR|S_IXUSR, proc_fd_inode_operations, proc_fd_operations),
2915 DIR("fdinfo", S_IRUSR|S_IXUSR, proc_fdinfo_inode_operations, proc_fd_operations), 2915 DIR("fdinfo", S_IRUSR|S_IXUSR, proc_fdinfo_inode_operations, proc_fdinfo_operations),
2916 REG("environ", S_IRUSR, proc_environ_operations), 2916 REG("environ", S_IRUSR, proc_environ_operations),
2917 INF("auxv", S_IRUSR, proc_pid_auxv), 2917 INF("auxv", S_IRUSR, proc_pid_auxv),
2918 ONE("status", S_IRUGO, proc_pid_status), 2918 ONE("status", S_IRUGO, proc_pid_status),
diff --git a/fs/reiserfs/dir.c b/fs/reiserfs/dir.c
index c094f58c7448..1e686eeb2867 100644
--- a/fs/reiserfs/dir.c
+++ b/fs/reiserfs/dir.c
@@ -45,8 +45,6 @@ static inline bool is_privroot_deh(struct dentry *dir,
45 struct reiserfs_de_head *deh) 45 struct reiserfs_de_head *deh)
46{ 46{
47 struct dentry *privroot = REISERFS_SB(dir->d_sb)->priv_root; 47 struct dentry *privroot = REISERFS_SB(dir->d_sb)->priv_root;
48 if (reiserfs_expose_privroot(dir->d_sb))
49 return 0;
50 return (dir == dir->d_parent && privroot->d_inode && 48 return (dir == dir->d_parent && privroot->d_inode &&
51 deh->deh_objectid == INODE_PKEY(privroot->d_inode)->k_objectid); 49 deh->deh_objectid == INODE_PKEY(privroot->d_inode)->k_objectid);
52} 50}
diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c
index 75f4c0bf0506..1347e9f32c52 100644
--- a/fs/reiserfs/xattr.c
+++ b/fs/reiserfs/xattr.c
@@ -557,7 +557,7 @@ reiserfs_xattr_set_handle(struct reiserfs_transaction_handle *th,
557 if (!err && new_size < i_size_read(dentry->d_inode)) { 557 if (!err && new_size < i_size_read(dentry->d_inode)) {
558 struct iattr newattrs = { 558 struct iattr newattrs = {
559 .ia_ctime = current_fs_time(inode->i_sb), 559 .ia_ctime = current_fs_time(inode->i_sb),
560 .ia_size = buffer_size, 560 .ia_size = new_size,
561 .ia_valid = ATTR_SIZE | ATTR_CTIME, 561 .ia_valid = ATTR_SIZE | ATTR_CTIME,
562 }; 562 };
563 563
@@ -976,21 +976,13 @@ int reiserfs_permission(struct inode *inode, int mask)
976 return generic_permission(inode, mask, NULL); 976 return generic_permission(inode, mask, NULL);
977} 977}
978 978
979/* This will catch lookups from the fs root to .reiserfs_priv */ 979static int xattr_hide_revalidate(struct dentry *dentry, struct nameidata *nd)
980static int
981xattr_lookup_poison(struct dentry *dentry, struct qstr *q1, struct qstr *name)
982{ 980{
983 struct dentry *priv_root = REISERFS_SB(dentry->d_sb)->priv_root; 981 return -EPERM;
984 if (container_of(q1, struct dentry, d_name) == priv_root)
985 return -ENOENT;
986 if (q1->len == name->len &&
987 !memcmp(q1->name, name->name, name->len))
988 return 0;
989 return 1;
990} 982}
991 983
992static const struct dentry_operations xattr_lookup_poison_ops = { 984static const struct dentry_operations xattr_lookup_poison_ops = {
993 .d_compare = xattr_lookup_poison, 985 .d_revalidate = xattr_hide_revalidate,
994}; 986};
995 987
996int reiserfs_lookup_privroot(struct super_block *s) 988int reiserfs_lookup_privroot(struct super_block *s)
@@ -1004,8 +996,7 @@ int reiserfs_lookup_privroot(struct super_block *s)
1004 strlen(PRIVROOT_NAME)); 996 strlen(PRIVROOT_NAME));
1005 if (!IS_ERR(dentry)) { 997 if (!IS_ERR(dentry)) {
1006 REISERFS_SB(s)->priv_root = dentry; 998 REISERFS_SB(s)->priv_root = dentry;
1007 if (!reiserfs_expose_privroot(s)) 999 dentry->d_op = &xattr_lookup_poison_ops;
1008 s->s_root->d_op = &xattr_lookup_poison_ops;
1009 if (dentry->d_inode) 1000 if (dentry->d_inode)
1010 dentry->d_inode->i_flags |= S_PRIVATE; 1001 dentry->d_inode->i_flags |= S_PRIVATE;
1011 } else 1002 } else
diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c
index 5eddd6fcc3ab..64e92454ef1a 100644
--- a/fs/xfs/linux-2.6/xfs_super.c
+++ b/fs/xfs/linux-2.6/xfs_super.c
@@ -1160,6 +1160,7 @@ xfs_fs_put_super(
1160 1160
1161 xfs_unmountfs(mp); 1161 xfs_unmountfs(mp);
1162 xfs_freesb(mp); 1162 xfs_freesb(mp);
1163 xfs_inode_shrinker_unregister(mp);
1163 xfs_icsb_destroy_counters(mp); 1164 xfs_icsb_destroy_counters(mp);
1164 xfs_close_devices(mp); 1165 xfs_close_devices(mp);
1165 xfs_dmops_put(mp); 1166 xfs_dmops_put(mp);
@@ -1523,6 +1524,8 @@ xfs_fs_fill_super(
1523 if (error) 1524 if (error)
1524 goto fail_vnrele; 1525 goto fail_vnrele;
1525 1526
1527 xfs_inode_shrinker_register(mp);
1528
1526 kfree(mtpt); 1529 kfree(mtpt);
1527 return 0; 1530 return 0;
1528 1531
@@ -1767,6 +1770,7 @@ init_xfs_fs(void)
1767 goto out_cleanup_procfs; 1770 goto out_cleanup_procfs;
1768 1771
1769 vfs_initquota(); 1772 vfs_initquota();
1773 xfs_inode_shrinker_init();
1770 1774
1771 error = register_filesystem(&xfs_fs_type); 1775 error = register_filesystem(&xfs_fs_type);
1772 if (error) 1776 if (error)
@@ -1794,6 +1798,7 @@ exit_xfs_fs(void)
1794{ 1798{
1795 vfs_exitquota(); 1799 vfs_exitquota();
1796 unregister_filesystem(&xfs_fs_type); 1800 unregister_filesystem(&xfs_fs_type);
1801 xfs_inode_shrinker_destroy();
1797 xfs_sysctl_unregister(); 1802 xfs_sysctl_unregister();
1798 xfs_cleanup_procfs(); 1803 xfs_cleanup_procfs();
1799 xfs_buf_terminate(); 1804 xfs_buf_terminate();
diff --git a/fs/xfs/linux-2.6/xfs_sync.c b/fs/xfs/linux-2.6/xfs_sync.c
index 6b6b39416ad3..57adf2d60dfc 100644
--- a/fs/xfs/linux-2.6/xfs_sync.c
+++ b/fs/xfs/linux-2.6/xfs_sync.c
@@ -95,7 +95,8 @@ xfs_inode_ag_walk(
95 struct xfs_perag *pag, int flags), 95 struct xfs_perag *pag, int flags),
96 int flags, 96 int flags,
97 int tag, 97 int tag,
98 int exclusive) 98 int exclusive,
99 int *nr_to_scan)
99{ 100{
100 struct xfs_perag *pag = &mp->m_perag[ag]; 101 struct xfs_perag *pag = &mp->m_perag[ag];
101 uint32_t first_index; 102 uint32_t first_index;
@@ -135,7 +136,7 @@ restart:
135 if (error == EFSCORRUPTED) 136 if (error == EFSCORRUPTED)
136 break; 137 break;
137 138
138 } while (1); 139 } while ((*nr_to_scan)--);
139 140
140 if (skipped) { 141 if (skipped) {
141 delay(1); 142 delay(1);
@@ -153,23 +154,30 @@ xfs_inode_ag_iterator(
153 struct xfs_perag *pag, int flags), 154 struct xfs_perag *pag, int flags),
154 int flags, 155 int flags,
155 int tag, 156 int tag,
156 int exclusive) 157 int exclusive,
158 int *nr_to_scan)
157{ 159{
158 int error = 0; 160 int error = 0;
159 int last_error = 0; 161 int last_error = 0;
160 xfs_agnumber_t ag; 162 xfs_agnumber_t ag;
163 int nr;
161 164
165 nr = nr_to_scan ? *nr_to_scan : INT_MAX;
162 for (ag = 0; ag < mp->m_sb.sb_agcount; ag++) { 166 for (ag = 0; ag < mp->m_sb.sb_agcount; ag++) {
163 if (!mp->m_perag[ag].pag_ici_init) 167 if (!mp->m_perag[ag].pag_ici_init)
164 continue; 168 continue;
165 error = xfs_inode_ag_walk(mp, ag, execute, flags, tag, 169 error = xfs_inode_ag_walk(mp, ag, execute, flags, tag,
166 exclusive); 170 exclusive, &nr);
167 if (error) { 171 if (error) {
168 last_error = error; 172 last_error = error;
169 if (error == EFSCORRUPTED) 173 if (error == EFSCORRUPTED)
170 break; 174 break;
171 } 175 }
176 if (nr <= 0)
177 break;
172 } 178 }
179 if (nr_to_scan)
180 *nr_to_scan = nr;
173 return XFS_ERROR(last_error); 181 return XFS_ERROR(last_error);
174} 182}
175 183
@@ -289,7 +297,7 @@ xfs_sync_data(
289 ASSERT((flags & ~(SYNC_TRYLOCK|SYNC_WAIT)) == 0); 297 ASSERT((flags & ~(SYNC_TRYLOCK|SYNC_WAIT)) == 0);
290 298
291 error = xfs_inode_ag_iterator(mp, xfs_sync_inode_data, flags, 299 error = xfs_inode_ag_iterator(mp, xfs_sync_inode_data, flags,
292 XFS_ICI_NO_TAG, 0); 300 XFS_ICI_NO_TAG, 0, NULL);
293 if (error) 301 if (error)
294 return XFS_ERROR(error); 302 return XFS_ERROR(error);
295 303
@@ -311,7 +319,7 @@ xfs_sync_attr(
311 ASSERT((flags & ~SYNC_WAIT) == 0); 319 ASSERT((flags & ~SYNC_WAIT) == 0);
312 320
313 return xfs_inode_ag_iterator(mp, xfs_sync_inode_attr, flags, 321 return xfs_inode_ag_iterator(mp, xfs_sync_inode_attr, flags,
314 XFS_ICI_NO_TAG, 0); 322 XFS_ICI_NO_TAG, 0, NULL);
315} 323}
316 324
317STATIC int 325STATIC int
@@ -679,6 +687,7 @@ __xfs_inode_set_reclaim_tag(
679 radix_tree_tag_set(&pag->pag_ici_root, 687 radix_tree_tag_set(&pag->pag_ici_root,
680 XFS_INO_TO_AGINO(ip->i_mount, ip->i_ino), 688 XFS_INO_TO_AGINO(ip->i_mount, ip->i_ino),
681 XFS_ICI_RECLAIM_TAG); 689 XFS_ICI_RECLAIM_TAG);
690 pag->pag_ici_reclaimable++;
682} 691}
683 692
684/* 693/*
@@ -710,6 +719,7 @@ __xfs_inode_clear_reclaim_tag(
710{ 719{
711 radix_tree_tag_clear(&pag->pag_ici_root, 720 radix_tree_tag_clear(&pag->pag_ici_root,
712 XFS_INO_TO_AGINO(mp, ip->i_ino), XFS_ICI_RECLAIM_TAG); 721 XFS_INO_TO_AGINO(mp, ip->i_ino), XFS_ICI_RECLAIM_TAG);
722 pag->pag_ici_reclaimable--;
713} 723}
714 724
715STATIC int 725STATIC int
@@ -770,5 +780,88 @@ xfs_reclaim_inodes(
770 int mode) 780 int mode)
771{ 781{
772 return xfs_inode_ag_iterator(mp, xfs_reclaim_inode, mode, 782 return xfs_inode_ag_iterator(mp, xfs_reclaim_inode, mode,
773 XFS_ICI_RECLAIM_TAG, 1); 783 XFS_ICI_RECLAIM_TAG, 1, NULL);
784}
785
786/*
787 * Shrinker infrastructure.
788 *
789 * This is all far more complex than it needs to be. It adds a global list of
790 * mounts because the shrinkers can only call a global context. We need to make
791 * the shrinkers pass a context to avoid the need for global state.
792 */
793static LIST_HEAD(xfs_mount_list);
794static struct rw_semaphore xfs_mount_list_lock;
795
796static int
797xfs_reclaim_inode_shrink(
798 int nr_to_scan,
799 gfp_t gfp_mask)
800{
801 struct xfs_mount *mp;
802 xfs_agnumber_t ag;
803 int reclaimable = 0;
804
805 if (nr_to_scan) {
806 if (!(gfp_mask & __GFP_FS))
807 return -1;
808
809 down_read(&xfs_mount_list_lock);
810 list_for_each_entry(mp, &xfs_mount_list, m_mplist) {
811 xfs_inode_ag_iterator(mp, xfs_reclaim_inode, 0,
812 XFS_ICI_RECLAIM_TAG, 1, &nr_to_scan);
813 if (nr_to_scan <= 0)
814 break;
815 }
816 up_read(&xfs_mount_list_lock);
817 }
818
819 down_read(&xfs_mount_list_lock);
820 list_for_each_entry(mp, &xfs_mount_list, m_mplist) {
821 for (ag = 0; ag < mp->m_sb.sb_agcount; ag++) {
822
823 if (!mp->m_perag[ag].pag_ici_init)
824 continue;
825 reclaimable += mp->m_perag[ag].pag_ici_reclaimable;
826 }
827 }
828 up_read(&xfs_mount_list_lock);
829 return reclaimable;
830}
831
832static struct shrinker xfs_inode_shrinker = {
833 .shrink = xfs_reclaim_inode_shrink,
834 .seeks = DEFAULT_SEEKS,
835};
836
837void __init
838xfs_inode_shrinker_init(void)
839{
840 init_rwsem(&xfs_mount_list_lock);
841 register_shrinker(&xfs_inode_shrinker);
842}
843
844void
845xfs_inode_shrinker_destroy(void)
846{
847 ASSERT(list_empty(&xfs_mount_list));
848 unregister_shrinker(&xfs_inode_shrinker);
849}
850
851void
852xfs_inode_shrinker_register(
853 struct xfs_mount *mp)
854{
855 down_write(&xfs_mount_list_lock);
856 list_add_tail(&mp->m_mplist, &xfs_mount_list);
857 up_write(&xfs_mount_list_lock);
858}
859
860void
861xfs_inode_shrinker_unregister(
862 struct xfs_mount *mp)
863{
864 down_write(&xfs_mount_list_lock);
865 list_del(&mp->m_mplist);
866 up_write(&xfs_mount_list_lock);
774} 867}
diff --git a/fs/xfs/linux-2.6/xfs_sync.h b/fs/xfs/linux-2.6/xfs_sync.h
index ea932b43335d..0b28c13bdf94 100644
--- a/fs/xfs/linux-2.6/xfs_sync.h
+++ b/fs/xfs/linux-2.6/xfs_sync.h
@@ -54,6 +54,11 @@ void __xfs_inode_clear_reclaim_tag(struct xfs_mount *mp, struct xfs_perag *pag,
54int xfs_sync_inode_valid(struct xfs_inode *ip, struct xfs_perag *pag); 54int xfs_sync_inode_valid(struct xfs_inode *ip, struct xfs_perag *pag);
55int xfs_inode_ag_iterator(struct xfs_mount *mp, 55int xfs_inode_ag_iterator(struct xfs_mount *mp,
56 int (*execute)(struct xfs_inode *ip, struct xfs_perag *pag, int flags), 56 int (*execute)(struct xfs_inode *ip, struct xfs_perag *pag, int flags),
57 int flags, int tag, int write_lock); 57 int flags, int tag, int write_lock, int *nr_to_scan);
58
59void xfs_inode_shrinker_init(void);
60void xfs_inode_shrinker_destroy(void);
61void xfs_inode_shrinker_register(struct xfs_mount *mp);
62void xfs_inode_shrinker_unregister(struct xfs_mount *mp);
58 63
59#endif 64#endif
diff --git a/fs/xfs/quota/xfs_qm_syscalls.c b/fs/xfs/quota/xfs_qm_syscalls.c
index 873e07e29074..145f5963917d 100644
--- a/fs/xfs/quota/xfs_qm_syscalls.c
+++ b/fs/xfs/quota/xfs_qm_syscalls.c
@@ -891,7 +891,8 @@ xfs_qm_dqrele_all_inodes(
891 uint flags) 891 uint flags)
892{ 892{
893 ASSERT(mp->m_quotainfo); 893 ASSERT(mp->m_quotainfo);
894 xfs_inode_ag_iterator(mp, xfs_dqrele_inode, flags, XFS_ICI_NO_TAG, 0); 894 xfs_inode_ag_iterator(mp, xfs_dqrele_inode, flags,
895 XFS_ICI_NO_TAG, 0, NULL);
895} 896}
896 897
897/*------------------------------------------------------------------------*/ 898/*------------------------------------------------------------------------*/
diff --git a/fs/xfs/xfs_ag.h b/fs/xfs/xfs_ag.h
index 6702bd865811..1182604a16ea 100644
--- a/fs/xfs/xfs_ag.h
+++ b/fs/xfs/xfs_ag.h
@@ -229,6 +229,7 @@ typedef struct xfs_perag
229 int pag_ici_init; /* incore inode cache initialised */ 229 int pag_ici_init; /* incore inode cache initialised */
230 rwlock_t pag_ici_lock; /* incore inode lock */ 230 rwlock_t pag_ici_lock; /* incore inode lock */
231 struct radix_tree_root pag_ici_root; /* incore inode cache root */ 231 struct radix_tree_root pag_ici_root; /* incore inode cache root */
232 int pag_ici_reclaimable; /* reclaimable inodes */
232#endif 233#endif
233} xfs_perag_t; 234} xfs_perag_t;
234 235
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h
index 0088311d23e7..b20d59eab00a 100644
--- a/fs/xfs/xfs_mount.h
+++ b/fs/xfs/xfs_mount.h
@@ -257,6 +257,7 @@ typedef struct xfs_mount {
257 wait_queue_head_t m_wait_single_sync_task; 257 wait_queue_head_t m_wait_single_sync_task;
258 __int64_t m_update_flags; /* sb flags we need to update 258 __int64_t m_update_flags; /* sb flags we need to update
259 on the next remount,rw */ 259 on the next remount,rw */
260 struct list_head m_mplist; /* inode shrinker mount list */
260} xfs_mount_t; 261} xfs_mount_t;
261 262
262/* 263/*