diff -Nurp 2.4.23-pre5/arch/ia64/mm/hugetlbpage.c 2.4.23-pre5.ken/arch/ia64/mm/hugetlbpage.c
--- 2.4.23-pre5/arch/ia64/mm/hugetlbpage.c	Fri Sep 26 14:28:21 2003
+++ 2.4.23-pre5.ken/arch/ia64/mm/hugetlbpage.c	Fri Sep 26 14:29:05 2003
@@ -262,18 +262,19 @@ int hugetlb_prefault(struct address_spac
 			+ (vma->vm_pgoff >> (HPAGE_SHIFT - PAGE_SHIFT));
 		page = find_get_page(mapping, idx);
 		if (!page) {
-			loff_t i_size;
+			/* charge the fs quota first */
+			if (hugetlb_get_quota(mapping)) {
+				ret = -ENOMEM;
+				goto out;
+			}
 			page = alloc_hugetlb_page();
 			if (!page) {
+				hugetlb_put_quota(mapping);
 				ret = -ENOMEM;
 				goto out;
 			}
 			add_to_page_cache(page, mapping, idx);
 			unlock_page(page);
-			i_size = (loff_t)(idx + 1) * HPAGE_SIZE;
-			if (i_size > inode->i_size)
-				inode->i_size = i_size;
-
 		}
 		set_huge_pte(mm, vma, page, pte, vma->vm_flags & VM_WRITE);
 	}
diff -Nurp 2.4.23-pre5/fs/hugetlbfs/inode.c 2.4.23-pre5.ken/fs/hugetlbfs/inode.c
--- 2.4.23-pre5/fs/hugetlbfs/inode.c	Fri Sep 26 14:28:21 2003
+++ 2.4.23-pre5.ken/fs/hugetlbfs/inode.c	Fri Sep 26 14:29:05 2003
@@ -139,8 +139,7 @@ static int hugetlbfs_file_mmap(struct fi
 {
 	struct inode *inode = file->f_dentry->d_inode;
 	struct address_space *mapping = inode->i_mapping;
-	struct hugetlbfs_sb_info *sbinfo = HUGETLBFS_SB(inode->i_sb);
-	loff_t len;
+	loff_t len, vma_len;
 	int ret;
 
 	if (vma->vm_start & ~HPAGE_MASK)
@@ -155,17 +154,7 @@ static int hugetlbfs_file_mmap(struct fi
 	if (vma->vm_start < (REGION_HPAGE << REGION_SHIFT))
 		return -EINVAL;
 #endif
-	len = (loff_t)(vma->vm_end - vma->vm_start);
-	if (sbinfo->free_blocks >= 0) { /* Check if there is any size limit. */
-		spin_lock(&sbinfo->stat_lock);
-		if ((len >> HPAGE_SHIFT) <= sbinfo->free_blocks) {
-			sbinfo->free_blocks -= (len >> HPAGE_SHIFT);
-			spin_unlock(&sbinfo->stat_lock);
-		} else {
-			spin_unlock(&sbinfo->stat_lock);
-			return -ENOMEM;
-		}
-	}
+	vma_len = (loff_t)(vma->vm_end - vma->vm_start);
 
 	down(&inode->i_sem);
 
@@ -173,15 +162,11 @@ static int hugetlbfs_file_mmap(struct fi
 	vma->vm_flags |= VM_HUGETLB | VM_RESERVED;
 	vma->vm_ops = &hugetlb_vm_ops;
 	ret = hugetlb_prefault(mapping, vma);
+	len = vma_len + ((loff_t)vma->vm_pgoff << PAGE_SHIFT);
+	if (ret == 0 && inode->i_size < len)
+		inode->i_size = len;
 	up(&inode->i_sem);
 
-	/* If the huge page allocation has failed then increment the free_blocks. */
-	if ((ret != 0) && (sbinfo->free_blocks >= 0)) {
-		spin_lock(&sbinfo->stat_lock);
-		sbinfo->free_blocks += (len >> HPAGE_SHIFT);
-		spin_unlock(&sbinfo->stat_lock);
-	}
-
 	return ret;
 }
 
@@ -261,7 +246,6 @@ void truncate_huge_page(struct address_s
 
 void truncate_hugepages(struct inode *inode, struct address_space *mapping, loff_t lstart)
 {
-	struct hugetlbfs_sb_info *sbinfo = HUGETLBFS_SB(mapping->host->i_sb);
 	unsigned long  start = lstart >> HPAGE_SHIFT;
 	unsigned long next;
 	unsigned long max_idx;
@@ -277,13 +261,8 @@ void truncate_hugepages(struct inode *in
 		page_cache_release(page);
 		truncate_huge_page(mapping, page);
 		unlock_page(page);
-		if (sbinfo->free_blocks >= 0) {
-			spin_lock(&sbinfo->stat_lock);
-			sbinfo->free_blocks ++;
-			spin_unlock(&sbinfo->stat_lock);
-		}
+		hugetlb_put_quota(mapping);
 	}
-
 }
 
 static void hugetlbfs_delete_inode(struct inode *inode)
@@ -720,6 +699,36 @@ out_dentry:
 	return ERR_PTR(error);
 }
 
+int hugetlb_get_quota(struct address_space * mapping)
+{
+	int ret = 0;
+	struct hugetlbfs_sb_info *sbinfo =
+		HUGETLBFS_SB(mapping->host->i_sb);
+
+	if (sbinfo->free_blocks > -1) {
+		spin_lock(&sbinfo->stat_lock);
+		if (sbinfo->free_blocks > 0)
+			sbinfo->free_blocks--;
+		else
+			ret = -ENOMEM;
+		spin_unlock(&sbinfo->stat_lock);
+	}
+
+	return ret;
+}
+
+void hugetlb_put_quota(struct address_space *mapping)
+{
+	struct hugetlbfs_sb_info *sbinfo =
+		HUGETLBFS_SB(mapping->host->i_sb);
+
+	if (sbinfo->free_blocks > -1) {
+		spin_lock(&sbinfo->stat_lock);
+		sbinfo->free_blocks++;
+		spin_unlock(&sbinfo->stat_lock);
+	}
+}
+
 static int __init init_hugetlbfs_fs(void)
 {
 	int error;
diff -Nurp 2.4.23-pre5/include/linux/hugetlb.h 2.4.23-pre5.ken/include/linux/hugetlb.h
--- 2.4.23-pre5/include/linux/hugetlb.h	Fri Sep 26 14:28:21 2003
+++ 2.4.23-pre5.ken/include/linux/hugetlb.h	Fri Sep 26 14:29:05 2003
@@ -74,6 +74,8 @@ static inline struct hugetlbfs_sb_info *
 extern struct file_operations hugetlbfs_file_operations;
 extern struct vm_operations_struct hugetlb_vm_ops;
 struct file *hugetlb_zero_setup(size_t);
+int hugetlb_get_quota(struct address_space *mapping);
+void hugetlb_put_quota(struct address_space *mapping);
 
 static inline int is_file_hugepages(struct file *file)
 {
@@ -89,6 +91,8 @@ static inline void set_file_hugepages(st
 #define is_file_hugepages(file)		0
 #define set_file_hugepages(file)	BUG()
 #define hugetlb_zero_setup(size)	ERR_PTR(-ENOSYS)
+#define hugetlb_get_quota(mapping)	0
+#define hugetlb_put_quota(mapping)	0
 
 #endif /* !CONFIG_HUGETLBFS */
 
