+int ll_get_max_mdsize(struct ll_sb_info *sbi, int *lmmsize)
+{
+ int size, rc;
+
+ *lmmsize = obd_size_diskmd(sbi->ll_dt_exp, NULL);
+ size = sizeof(int);
+ rc = obd_get_info(sbi->ll_md_exp, strlen("max_easize"), "max_easize",
+ &size, lmmsize);
+ if (rc)
+ CERROR("Get max mdsize error rc %d \n", rc);
+
+ RETURN(rc);
+}
+
+void ll_dump_inode(struct inode *inode)
+{
+ struct list_head *tmp;
+ int dentry_count = 0;
+
+ LASSERT(inode != NULL);
+
+ list_for_each(tmp, &inode->i_dentry)
+ dentry_count++;
+
+ CERROR("inode %p dump: dev=%s ino=%lu mode=%o count=%u, %d dentries\n",
+ inode, ll_i2mdexp(inode)->exp_obd->obd_name, inode->i_ino,
+ inode->i_mode, atomic_read(&inode->i_count), dentry_count);
+}
+
+void lustre_dump_dentry(struct dentry *dentry, int recur)
+{
+ struct list_head *tmp;
+ int subdirs = 0;
+
+ LASSERT(dentry != NULL);
+
+ list_for_each(tmp, &dentry->d_subdirs)
+ subdirs++;
+
+ CERROR("dentry %p dump: name=%.*s parent=%.*s (%p), inode=%p, count=%u,"
+ " flags=0x%x, fsdata=%p, %d subdirs\n", dentry,
+ dentry->d_name.len, dentry->d_name.name,
+ dentry->d_parent->d_name.len, dentry->d_parent->d_name.name,
+ dentry->d_parent, dentry->d_inode, atomic_read(&dentry->d_count),
+ dentry->d_flags, dentry->d_fsdata, subdirs);
+ if (dentry->d_inode != NULL)
+ ll_dump_inode(dentry->d_inode);
+
+ if (recur == 0)
+ return;
+
+ list_for_each(tmp, &dentry->d_subdirs) {
+ struct dentry *d = list_entry(tmp, struct dentry, d_child);
+ lustre_dump_dentry(d, recur - 1);
+ }
+}
+
+#ifdef HAVE_EXPORT___IGET
+static void prune_dir_dentries(struct inode *inode)
+{
+ struct dentry *dentry, *prev = NULL;
+
+ /* due to lustre specific logic, a directory
+ * can have few dentries - a bug from VFS POV */
+restart:
+ spin_lock(&dcache_lock);
+ if (!list_empty(&inode->i_dentry)) {
+ dentry = list_entry(inode->i_dentry.prev,
+ struct dentry, d_alias);
+ /* in order to prevent infinite loops we
+ * break if previous dentry is busy */
+ if (dentry != prev) {
+ prev = dentry;
+ dget_locked(dentry);
+ spin_unlock(&dcache_lock);
+
+ /* try to kill all child dentries */
+ lock_dentry(dentry);
+ shrink_dcache_parent(dentry);
+ unlock_dentry(dentry);
+ dput(dentry);
+
+ /* now try to get rid of current dentry */
+ d_prune_aliases(inode);
+ goto restart;
+ }
+ }
+ spin_unlock(&dcache_lock);
+}
+
+static void prune_deathrow_one(struct ll_inode_info *lli)
+{
+ struct inode *inode = ll_info2i(lli);
+
+ /* first, try to drop any dentries - they hold a ref on the inode */
+ if (S_ISDIR(inode->i_mode))
+ prune_dir_dentries(inode);
+ else
+ d_prune_aliases(inode);
+
+
+ /* if somebody still uses it, leave it */
+ LASSERT(atomic_read(&inode->i_count) > 0);
+ if (atomic_read(&inode->i_count) > 1)
+ goto out;
+
+ CDEBUG(D_INODE, "inode %lu/%u(%d) looks a good candidate for prune\n",
+ inode->i_ino,inode->i_generation, atomic_read(&inode->i_count));
+
+ /* seems nobody uses it anymore */
+ inode->i_nlink = 0;
+
+out:
+ iput(inode);
+ return;
+}
+
+static void prune_deathrow(struct ll_sb_info *sbi, int try)
+{
+ struct ll_inode_info *lli;
+ int empty;
+
+ do {
+ if (need_resched() && try)
+ break;
+
+ if (try) {
+ if (!spin_trylock(&sbi->ll_deathrow_lock))
+ break;
+ } else {
+ spin_lock(&sbi->ll_deathrow_lock);
+ }
+
+ empty = 1;
+ lli = NULL;
+ if (!list_empty(&sbi->ll_deathrow)) {
+ lli = list_entry(sbi->ll_deathrow.next,
+ struct ll_inode_info,
+ lli_dead_list);
+ list_del_init(&lli->lli_dead_list);
+ if (!list_empty(&sbi->ll_deathrow))
+ empty = 0;
+ }
+ spin_unlock(&sbi->ll_deathrow_lock);
+
+ if (lli)
+ prune_deathrow_one(lli);
+
+ } while (empty == 0);
+}
+#else /* !HAVE_EXPORT___IGET */
+#define prune_deathrow(sbi, try) do {} while (0)
+#endif /* HAVE_EXPORT___IGET */
+
+void client_common_put_super(struct super_block *sb)