diff options
-rw-r--r-- | fs/ocfs2/dlmglue.c | 46 | ||||
-rw-r--r-- | fs/ocfs2/dlmglue.h | 2 | ||||
-rw-r--r-- | fs/ocfs2/export.c | 84 | ||||
-rw-r--r-- | fs/ocfs2/inode.c | 28 | ||||
-rw-r--r-- | fs/ocfs2/inode.h | 1 | ||||
-rw-r--r-- | fs/ocfs2/ocfs2.h | 1 | ||||
-rw-r--r-- | fs/ocfs2/ocfs2_lockid.h | 4 | ||||
-rw-r--r-- | fs/ocfs2/suballoc.c | 159 | ||||
-rw-r--r-- | fs/ocfs2/suballoc.h | 2 |
9 files changed, 319 insertions, 8 deletions
diff --git a/fs/ocfs2/dlmglue.c b/fs/ocfs2/dlmglue.c index 7219a86d34cc..e15fc7d50827 100644 --- a/fs/ocfs2/dlmglue.c +++ b/fs/ocfs2/dlmglue.c | |||
@@ -244,6 +244,10 @@ static struct ocfs2_lock_res_ops ocfs2_rename_lops = { | |||
244 | .flags = 0, | 244 | .flags = 0, |
245 | }; | 245 | }; |
246 | 246 | ||
247 | static struct ocfs2_lock_res_ops ocfs2_nfs_sync_lops = { | ||
248 | .flags = 0, | ||
249 | }; | ||
250 | |||
247 | static struct ocfs2_lock_res_ops ocfs2_dentry_lops = { | 251 | static struct ocfs2_lock_res_ops ocfs2_dentry_lops = { |
248 | .get_osb = ocfs2_get_dentry_osb, | 252 | .get_osb = ocfs2_get_dentry_osb, |
249 | .post_unlock = ocfs2_dentry_post_unlock, | 253 | .post_unlock = ocfs2_dentry_post_unlock, |
@@ -622,6 +626,17 @@ static void ocfs2_rename_lock_res_init(struct ocfs2_lock_res *res, | |||
622 | &ocfs2_rename_lops, osb); | 626 | &ocfs2_rename_lops, osb); |
623 | } | 627 | } |
624 | 628 | ||
629 | static void ocfs2_nfs_sync_lock_res_init(struct ocfs2_lock_res *res, | ||
630 | struct ocfs2_super *osb) | ||
631 | { | ||
632 | /* nfs_sync lockres doesn't come from a slab so we call init | ||
633 | * once on it manually. */ | ||
634 | ocfs2_lock_res_init_once(res); | ||
635 | ocfs2_build_lock_name(OCFS2_LOCK_TYPE_NFS_SYNC, 0, 0, res->l_name); | ||
636 | ocfs2_lock_res_init_common(osb, res, OCFS2_LOCK_TYPE_NFS_SYNC, | ||
637 | &ocfs2_nfs_sync_lops, osb); | ||
638 | } | ||
639 | |||
625 | void ocfs2_file_lock_res_init(struct ocfs2_lock_res *lockres, | 640 | void ocfs2_file_lock_res_init(struct ocfs2_lock_res *lockres, |
626 | struct ocfs2_file_private *fp) | 641 | struct ocfs2_file_private *fp) |
627 | { | 642 | { |
@@ -2417,6 +2432,34 @@ void ocfs2_rename_unlock(struct ocfs2_super *osb) | |||
2417 | ocfs2_cluster_unlock(osb, lockres, DLM_LOCK_EX); | 2432 | ocfs2_cluster_unlock(osb, lockres, DLM_LOCK_EX); |
2418 | } | 2433 | } |
2419 | 2434 | ||
2435 | int ocfs2_nfs_sync_lock(struct ocfs2_super *osb, int ex) | ||
2436 | { | ||
2437 | int status; | ||
2438 | struct ocfs2_lock_res *lockres = &osb->osb_nfs_sync_lockres; | ||
2439 | |||
2440 | if (ocfs2_is_hard_readonly(osb)) | ||
2441 | return -EROFS; | ||
2442 | |||
2443 | if (ocfs2_mount_local(osb)) | ||
2444 | return 0; | ||
2445 | |||
2446 | status = ocfs2_cluster_lock(osb, lockres, ex ? LKM_EXMODE : LKM_PRMODE, | ||
2447 | 0, 0); | ||
2448 | if (status < 0) | ||
2449 | mlog(ML_ERROR, "lock on nfs sync lock failed %d\n", status); | ||
2450 | |||
2451 | return status; | ||
2452 | } | ||
2453 | |||
2454 | void ocfs2_nfs_sync_unlock(struct ocfs2_super *osb, int ex) | ||
2455 | { | ||
2456 | struct ocfs2_lock_res *lockres = &osb->osb_nfs_sync_lockres; | ||
2457 | |||
2458 | if (!ocfs2_mount_local(osb)) | ||
2459 | ocfs2_cluster_unlock(osb, lockres, | ||
2460 | ex ? LKM_EXMODE : LKM_PRMODE); | ||
2461 | } | ||
2462 | |||
2420 | int ocfs2_dentry_lock(struct dentry *dentry, int ex) | 2463 | int ocfs2_dentry_lock(struct dentry *dentry, int ex) |
2421 | { | 2464 | { |
2422 | int ret; | 2465 | int ret; |
@@ -2798,6 +2841,7 @@ int ocfs2_dlm_init(struct ocfs2_super *osb) | |||
2798 | local: | 2841 | local: |
2799 | ocfs2_super_lock_res_init(&osb->osb_super_lockres, osb); | 2842 | ocfs2_super_lock_res_init(&osb->osb_super_lockres, osb); |
2800 | ocfs2_rename_lock_res_init(&osb->osb_rename_lockres, osb); | 2843 | ocfs2_rename_lock_res_init(&osb->osb_rename_lockres, osb); |
2844 | ocfs2_nfs_sync_lock_res_init(&osb->osb_nfs_sync_lockres, osb); | ||
2801 | 2845 | ||
2802 | osb->cconn = conn; | 2846 | osb->cconn = conn; |
2803 | 2847 | ||
@@ -2833,6 +2877,7 @@ void ocfs2_dlm_shutdown(struct ocfs2_super *osb, | |||
2833 | 2877 | ||
2834 | ocfs2_lock_res_free(&osb->osb_super_lockres); | 2878 | ocfs2_lock_res_free(&osb->osb_super_lockres); |
2835 | ocfs2_lock_res_free(&osb->osb_rename_lockres); | 2879 | ocfs2_lock_res_free(&osb->osb_rename_lockres); |
2880 | ocfs2_lock_res_free(&osb->osb_nfs_sync_lockres); | ||
2836 | 2881 | ||
2837 | ocfs2_cluster_disconnect(osb->cconn, hangup_pending); | 2882 | ocfs2_cluster_disconnect(osb->cconn, hangup_pending); |
2838 | osb->cconn = NULL; | 2883 | osb->cconn = NULL; |
@@ -3015,6 +3060,7 @@ static void ocfs2_drop_osb_locks(struct ocfs2_super *osb) | |||
3015 | { | 3060 | { |
3016 | ocfs2_simple_drop_lockres(osb, &osb->osb_super_lockres); | 3061 | ocfs2_simple_drop_lockres(osb, &osb->osb_super_lockres); |
3017 | ocfs2_simple_drop_lockres(osb, &osb->osb_rename_lockres); | 3062 | ocfs2_simple_drop_lockres(osb, &osb->osb_rename_lockres); |
3063 | ocfs2_simple_drop_lockres(osb, &osb->osb_nfs_sync_lockres); | ||
3018 | } | 3064 | } |
3019 | 3065 | ||
3020 | int ocfs2_drop_inode_locks(struct inode *inode) | 3066 | int ocfs2_drop_inode_locks(struct inode *inode) |
diff --git a/fs/ocfs2/dlmglue.h b/fs/ocfs2/dlmglue.h index 3f8d9986b8e0..e1fd5721cd7f 100644 --- a/fs/ocfs2/dlmglue.h +++ b/fs/ocfs2/dlmglue.h | |||
@@ -115,6 +115,8 @@ void ocfs2_super_unlock(struct ocfs2_super *osb, | |||
115 | int ex); | 115 | int ex); |
116 | int ocfs2_rename_lock(struct ocfs2_super *osb); | 116 | int ocfs2_rename_lock(struct ocfs2_super *osb); |
117 | void ocfs2_rename_unlock(struct ocfs2_super *osb); | 117 | void ocfs2_rename_unlock(struct ocfs2_super *osb); |
118 | int ocfs2_nfs_sync_lock(struct ocfs2_super *osb, int ex); | ||
119 | void ocfs2_nfs_sync_unlock(struct ocfs2_super *osb, int ex); | ||
118 | int ocfs2_dentry_lock(struct dentry *dentry, int ex); | 120 | int ocfs2_dentry_lock(struct dentry *dentry, int ex); |
119 | void ocfs2_dentry_unlock(struct dentry *dentry, int ex); | 121 | void ocfs2_dentry_unlock(struct dentry *dentry, int ex); |
120 | int ocfs2_file_lock(struct file *file, int ex, int trylock); | 122 | int ocfs2_file_lock(struct file *file, int ex, int trylock); |
diff --git a/fs/ocfs2/export.c b/fs/ocfs2/export.c index 2f27b332d8b3..de3da8eb558c 100644 --- a/fs/ocfs2/export.c +++ b/fs/ocfs2/export.c | |||
@@ -31,6 +31,7 @@ | |||
31 | 31 | ||
32 | #include "ocfs2.h" | 32 | #include "ocfs2.h" |
33 | 33 | ||
34 | #include "alloc.h" | ||
34 | #include "dir.h" | 35 | #include "dir.h" |
35 | #include "dlmglue.h" | 36 | #include "dlmglue.h" |
36 | #include "dcache.h" | 37 | #include "dcache.h" |
@@ -38,6 +39,7 @@ | |||
38 | #include "inode.h" | 39 | #include "inode.h" |
39 | 40 | ||
40 | #include "buffer_head_io.h" | 41 | #include "buffer_head_io.h" |
42 | #include "suballoc.h" | ||
41 | 43 | ||
42 | struct ocfs2_inode_handle | 44 | struct ocfs2_inode_handle |
43 | { | 45 | { |
@@ -49,29 +51,97 @@ static struct dentry *ocfs2_get_dentry(struct super_block *sb, | |||
49 | struct ocfs2_inode_handle *handle) | 51 | struct ocfs2_inode_handle *handle) |
50 | { | 52 | { |
51 | struct inode *inode; | 53 | struct inode *inode; |
54 | struct ocfs2_super *osb = OCFS2_SB(sb); | ||
55 | u64 blkno = handle->ih_blkno; | ||
56 | int status, set; | ||
52 | struct dentry *result; | 57 | struct dentry *result; |
53 | 58 | ||
54 | mlog_entry("(0x%p, 0x%p)\n", sb, handle); | 59 | mlog_entry("(0x%p, 0x%p)\n", sb, handle); |
55 | 60 | ||
56 | if (handle->ih_blkno == 0) { | 61 | if (blkno == 0) { |
57 | mlog_errno(-ESTALE); | 62 | mlog(0, "nfs wants inode with blkno: 0\n"); |
58 | return ERR_PTR(-ESTALE); | 63 | result = ERR_PTR(-ESTALE); |
64 | goto bail; | ||
65 | } | ||
66 | |||
67 | inode = ocfs2_ilookup(sb, blkno); | ||
68 | /* | ||
69 | * If the inode exists in memory, we only need to check it's | ||
70 | * generation number | ||
71 | */ | ||
72 | if (inode) | ||
73 | goto check_gen; | ||
74 | |||
75 | /* | ||
76 | * This will synchronize us against ocfs2_delete_inode() on | ||
77 | * all nodes | ||
78 | */ | ||
79 | status = ocfs2_nfs_sync_lock(osb, 1); | ||
80 | if (status < 0) { | ||
81 | mlog(ML_ERROR, "getting nfs sync lock(EX) failed %d\n", status); | ||
82 | goto check_err; | ||
83 | } | ||
84 | |||
85 | status = ocfs2_test_inode_bit(osb, blkno, &set); | ||
86 | if (status < 0) { | ||
87 | if (status == -EINVAL) { | ||
88 | /* | ||
89 | * The blkno NFS gave us doesn't even show up | ||
90 | * as an inode, we return -ESTALE to be | ||
91 | * nice | ||
92 | */ | ||
93 | mlog(0, "test inode bit failed %d\n", status); | ||
94 | status = -ESTALE; | ||
95 | } else { | ||
96 | mlog(ML_ERROR, "test inode bit failed %d\n", status); | ||
97 | } | ||
98 | goto unlock_nfs_sync; | ||
99 | } | ||
100 | |||
101 | /* If the inode allocator bit is clear, this inode must be stale */ | ||
102 | if (!set) { | ||
103 | mlog(0, "inode %llu suballoc bit is clear\n", blkno); | ||
104 | status = -ESTALE; | ||
105 | goto unlock_nfs_sync; | ||
59 | } | 106 | } |
60 | 107 | ||
61 | inode = ocfs2_iget(OCFS2_SB(sb), handle->ih_blkno, 0, 0); | 108 | inode = ocfs2_iget(osb, blkno, 0, 0); |
62 | 109 | ||
63 | if (IS_ERR(inode)) | 110 | unlock_nfs_sync: |
64 | return (void *)inode; | 111 | ocfs2_nfs_sync_unlock(osb, 1); |
65 | 112 | ||
113 | check_err: | ||
114 | if (status < 0) { | ||
115 | if (status == -ESTALE) { | ||
116 | mlog(0, "stale inode ino: %llu generation: %u\n", | ||
117 | blkno, handle->ih_generation); | ||
118 | } | ||
119 | result = ERR_PTR(status); | ||
120 | goto bail; | ||
121 | } | ||
122 | |||
123 | if (IS_ERR(inode)) { | ||
124 | mlog_errno(PTR_ERR(inode)); | ||
125 | result = (void *)inode; | ||
126 | goto bail; | ||
127 | } | ||
128 | |||
129 | check_gen: | ||
66 | if (handle->ih_generation != inode->i_generation) { | 130 | if (handle->ih_generation != inode->i_generation) { |
67 | iput(inode); | 131 | iput(inode); |
68 | return ERR_PTR(-ESTALE); | 132 | mlog(0, "stale inode ino: %llu generation: %u\n", blkno, |
133 | handle->ih_generation); | ||
134 | result = ERR_PTR(-ESTALE); | ||
135 | goto bail; | ||
69 | } | 136 | } |
70 | 137 | ||
71 | result = d_obtain_alias(inode); | 138 | result = d_obtain_alias(inode); |
72 | if (!IS_ERR(result)) | 139 | if (!IS_ERR(result)) |
73 | result->d_op = &ocfs2_dentry_ops; | 140 | result->d_op = &ocfs2_dentry_ops; |
141 | else | ||
142 | mlog_errno(PTR_ERR(result)); | ||
74 | 143 | ||
144 | bail: | ||
75 | mlog_exit_ptr(result); | 145 | mlog_exit_ptr(result); |
76 | return result; | 146 | return result; |
77 | } | 147 | } |
diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c index 4a88bce35079..10e1fa87396a 100644 --- a/fs/ocfs2/inode.c +++ b/fs/ocfs2/inode.c | |||
@@ -113,6 +113,17 @@ void ocfs2_get_inode_flags(struct ocfs2_inode_info *oi) | |||
113 | oi->ip_attr |= OCFS2_DIRSYNC_FL; | 113 | oi->ip_attr |= OCFS2_DIRSYNC_FL; |
114 | } | 114 | } |
115 | 115 | ||
116 | struct inode *ocfs2_ilookup(struct super_block *sb, u64 blkno) | ||
117 | { | ||
118 | struct ocfs2_find_inode_args args; | ||
119 | |||
120 | args.fi_blkno = blkno; | ||
121 | args.fi_flags = 0; | ||
122 | args.fi_ino = ino_from_blkno(sb, blkno); | ||
123 | args.fi_sysfile_type = 0; | ||
124 | |||
125 | return ilookup5(sb, blkno, ocfs2_find_actor, &args); | ||
126 | } | ||
116 | struct inode *ocfs2_iget(struct ocfs2_super *osb, u64 blkno, unsigned flags, | 127 | struct inode *ocfs2_iget(struct ocfs2_super *osb, u64 blkno, unsigned flags, |
117 | int sysfile_type) | 128 | int sysfile_type) |
118 | { | 129 | { |
@@ -961,6 +972,17 @@ void ocfs2_delete_inode(struct inode *inode) | |||
961 | goto bail; | 972 | goto bail; |
962 | } | 973 | } |
963 | 974 | ||
975 | /* | ||
976 | * Synchronize us against ocfs2_get_dentry. We take this in | ||
977 | * shared mode so that all nodes can still concurrently | ||
978 | * process deletes. | ||
979 | */ | ||
980 | status = ocfs2_nfs_sync_lock(OCFS2_SB(inode->i_sb), 0); | ||
981 | if (status < 0) { | ||
982 | mlog(ML_ERROR, "getting nfs sync lock(PR) failed %d\n", status); | ||
983 | ocfs2_cleanup_delete_inode(inode, 0); | ||
984 | goto bail_unblock; | ||
985 | } | ||
964 | /* Lock down the inode. This gives us an up to date view of | 986 | /* Lock down the inode. This gives us an up to date view of |
965 | * it's metadata (for verification), and allows us to | 987 | * it's metadata (for verification), and allows us to |
966 | * serialize delete_inode on multiple nodes. | 988 | * serialize delete_inode on multiple nodes. |
@@ -974,7 +996,7 @@ void ocfs2_delete_inode(struct inode *inode) | |||
974 | if (status != -ENOENT) | 996 | if (status != -ENOENT) |
975 | mlog_errno(status); | 997 | mlog_errno(status); |
976 | ocfs2_cleanup_delete_inode(inode, 0); | 998 | ocfs2_cleanup_delete_inode(inode, 0); |
977 | goto bail_unblock; | 999 | goto bail_unlock_nfs_sync; |
978 | } | 1000 | } |
979 | 1001 | ||
980 | /* Query the cluster. This will be the final decision made | 1002 | /* Query the cluster. This will be the final decision made |
@@ -1017,6 +1039,10 @@ void ocfs2_delete_inode(struct inode *inode) | |||
1017 | bail_unlock_inode: | 1039 | bail_unlock_inode: |
1018 | ocfs2_inode_unlock(inode, 1); | 1040 | ocfs2_inode_unlock(inode, 1); |
1019 | brelse(di_bh); | 1041 | brelse(di_bh); |
1042 | |||
1043 | bail_unlock_nfs_sync: | ||
1044 | ocfs2_nfs_sync_unlock(OCFS2_SB(inode->i_sb), 0); | ||
1045 | |||
1020 | bail_unblock: | 1046 | bail_unblock: |
1021 | status = sigprocmask(SIG_SETMASK, &oldset, NULL); | 1047 | status = sigprocmask(SIG_SETMASK, &oldset, NULL); |
1022 | if (status < 0) | 1048 | if (status < 0) |
diff --git a/fs/ocfs2/inode.h b/fs/ocfs2/inode.h index e1978acbf65e..ea71525aad41 100644 --- a/fs/ocfs2/inode.h +++ b/fs/ocfs2/inode.h | |||
@@ -128,6 +128,7 @@ void ocfs2_drop_inode(struct inode *inode); | |||
128 | /* Flags for ocfs2_iget() */ | 128 | /* Flags for ocfs2_iget() */ |
129 | #define OCFS2_FI_FLAG_SYSFILE 0x1 | 129 | #define OCFS2_FI_FLAG_SYSFILE 0x1 |
130 | #define OCFS2_FI_FLAG_ORPHAN_RECOVERY 0x2 | 130 | #define OCFS2_FI_FLAG_ORPHAN_RECOVERY 0x2 |
131 | struct inode *ocfs2_ilookup(struct super_block *sb, u64 feoff); | ||
131 | struct inode *ocfs2_iget(struct ocfs2_super *osb, u64 feoff, unsigned flags, | 132 | struct inode *ocfs2_iget(struct ocfs2_super *osb, u64 feoff, unsigned flags, |
132 | int sysfile_type); | 133 | int sysfile_type); |
133 | int ocfs2_inode_init_private(struct inode *inode); | 134 | int ocfs2_inode_init_private(struct inode *inode); |
diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h index b65d19c9756d..558bd2709e01 100644 --- a/fs/ocfs2/ocfs2.h +++ b/fs/ocfs2/ocfs2.h | |||
@@ -300,6 +300,7 @@ struct ocfs2_super | |||
300 | struct ocfs2_cluster_connection *cconn; | 300 | struct ocfs2_cluster_connection *cconn; |
301 | struct ocfs2_lock_res osb_super_lockres; | 301 | struct ocfs2_lock_res osb_super_lockres; |
302 | struct ocfs2_lock_res osb_rename_lockres; | 302 | struct ocfs2_lock_res osb_rename_lockres; |
303 | struct ocfs2_lock_res osb_nfs_sync_lockres; | ||
303 | struct ocfs2_dlm_debug *osb_dlm_debug; | 304 | struct ocfs2_dlm_debug *osb_dlm_debug; |
304 | 305 | ||
305 | struct dentry *osb_debug_root; | 306 | struct dentry *osb_debug_root; |
diff --git a/fs/ocfs2/ocfs2_lockid.h b/fs/ocfs2/ocfs2_lockid.h index eb6f50c9ceca..a53ce87481bf 100644 --- a/fs/ocfs2/ocfs2_lockid.h +++ b/fs/ocfs2/ocfs2_lockid.h | |||
@@ -47,6 +47,7 @@ enum ocfs2_lock_type { | |||
47 | OCFS2_LOCK_TYPE_OPEN, | 47 | OCFS2_LOCK_TYPE_OPEN, |
48 | OCFS2_LOCK_TYPE_FLOCK, | 48 | OCFS2_LOCK_TYPE_FLOCK, |
49 | OCFS2_LOCK_TYPE_QINFO, | 49 | OCFS2_LOCK_TYPE_QINFO, |
50 | OCFS2_LOCK_TYPE_NFS_SYNC, | ||
50 | OCFS2_NUM_LOCK_TYPES | 51 | OCFS2_NUM_LOCK_TYPES |
51 | }; | 52 | }; |
52 | 53 | ||
@@ -81,6 +82,9 @@ static inline char ocfs2_lock_type_char(enum ocfs2_lock_type type) | |||
81 | case OCFS2_LOCK_TYPE_QINFO: | 82 | case OCFS2_LOCK_TYPE_QINFO: |
82 | c = 'Q'; | 83 | c = 'Q'; |
83 | break; | 84 | break; |
85 | case OCFS2_LOCK_TYPE_NFS_SYNC: | ||
86 | c = 'Y'; | ||
87 | break; | ||
84 | default: | 88 | default: |
85 | c = '\0'; | 89 | c = '\0'; |
86 | } | 90 | } |
diff --git a/fs/ocfs2/suballoc.c b/fs/ocfs2/suballoc.c index 4c1399cc03f3..b4ca5911caaf 100644 --- a/fs/ocfs2/suballoc.c +++ b/fs/ocfs2/suballoc.c | |||
@@ -2185,3 +2185,162 @@ out: | |||
2185 | 2185 | ||
2186 | return ret; | 2186 | return ret; |
2187 | } | 2187 | } |
2188 | |||
2189 | /* | ||
2190 | * Read the inode specified by blkno to get suballoc_slot and | ||
2191 | * suballoc_bit. | ||
2192 | */ | ||
2193 | static int ocfs2_get_suballoc_slot_bit(struct ocfs2_super *osb, u64 blkno, | ||
2194 | u16 *suballoc_slot, u16 *suballoc_bit) | ||
2195 | { | ||
2196 | int status; | ||
2197 | struct buffer_head *inode_bh = NULL; | ||
2198 | struct ocfs2_dinode *inode_fe; | ||
2199 | |||
2200 | mlog_entry("blkno: %llu\n", blkno); | ||
2201 | |||
2202 | /* dirty read disk */ | ||
2203 | status = ocfs2_read_blocks_sync(osb, blkno, 1, &inode_bh); | ||
2204 | if (status < 0) { | ||
2205 | mlog(ML_ERROR, "read block %llu failed %d\n", blkno, status); | ||
2206 | goto bail; | ||
2207 | } | ||
2208 | |||
2209 | inode_fe = (struct ocfs2_dinode *) inode_bh->b_data; | ||
2210 | if (!OCFS2_IS_VALID_DINODE(inode_fe)) { | ||
2211 | mlog(ML_ERROR, "invalid inode %llu requested\n", blkno); | ||
2212 | status = -EINVAL; | ||
2213 | goto bail; | ||
2214 | } | ||
2215 | |||
2216 | if (le16_to_cpu(inode_fe->i_suballoc_slot) != OCFS2_INVALID_SLOT && | ||
2217 | (u32)le16_to_cpu(inode_fe->i_suballoc_slot) > osb->max_slots - 1) { | ||
2218 | mlog(ML_ERROR, "inode %llu has invalid suballoc slot %u\n", | ||
2219 | blkno, (u32)le16_to_cpu(inode_fe->i_suballoc_slot)); | ||
2220 | status = -EINVAL; | ||
2221 | goto bail; | ||
2222 | } | ||
2223 | |||
2224 | if (suballoc_slot) | ||
2225 | *suballoc_slot = le16_to_cpu(inode_fe->i_suballoc_slot); | ||
2226 | if (suballoc_bit) | ||
2227 | *suballoc_bit = le16_to_cpu(inode_fe->i_suballoc_bit); | ||
2228 | |||
2229 | bail: | ||
2230 | brelse(inode_bh); | ||
2231 | |||
2232 | mlog_exit(status); | ||
2233 | return status; | ||
2234 | } | ||
2235 | |||
2236 | /* | ||
2237 | * test whether bit is SET in allocator bitmap or not. on success, 0 | ||
2238 | * is returned and *res is 1 for SET; 0 otherwise. when fails, errno | ||
2239 | * is returned and *res is meaningless. Call this after you have | ||
2240 | * cluster locked against suballoc, or you may get a result based on | ||
2241 | * non-up2date contents | ||
2242 | */ | ||
2243 | static int ocfs2_test_suballoc_bit(struct ocfs2_super *osb, | ||
2244 | struct inode *suballoc, | ||
2245 | struct buffer_head *alloc_bh, u64 blkno, | ||
2246 | u16 bit, int *res) | ||
2247 | { | ||
2248 | struct ocfs2_dinode *alloc_fe; | ||
2249 | struct ocfs2_group_desc *group; | ||
2250 | struct buffer_head *group_bh = NULL; | ||
2251 | u64 bg_blkno; | ||
2252 | int status; | ||
2253 | |||
2254 | mlog_entry("blkno: %llu bit: %u\n", blkno, (unsigned int)bit); | ||
2255 | |||
2256 | alloc_fe = (struct ocfs2_dinode *)alloc_bh->b_data; | ||
2257 | if ((bit + 1) > ocfs2_bits_per_group(&alloc_fe->id2.i_chain)) { | ||
2258 | mlog(ML_ERROR, "suballoc bit %u out of range of %u\n", | ||
2259 | (unsigned int)bit, | ||
2260 | ocfs2_bits_per_group(&alloc_fe->id2.i_chain)); | ||
2261 | status = -EINVAL; | ||
2262 | goto bail; | ||
2263 | } | ||
2264 | |||
2265 | bg_blkno = ocfs2_which_suballoc_group(blkno, bit); | ||
2266 | status = ocfs2_read_group_descriptor(suballoc, alloc_fe, bg_blkno, | ||
2267 | &group_bh); | ||
2268 | if (status < 0) { | ||
2269 | mlog(ML_ERROR, "read group %llu failed %d\n", bg_blkno, status); | ||
2270 | goto bail; | ||
2271 | } | ||
2272 | |||
2273 | group = (struct ocfs2_group_desc *) group_bh->b_data; | ||
2274 | *res = ocfs2_test_bit(bit, (unsigned long *)group->bg_bitmap); | ||
2275 | |||
2276 | bail: | ||
2277 | brelse(group_bh); | ||
2278 | |||
2279 | mlog_exit(status); | ||
2280 | return status; | ||
2281 | } | ||
2282 | |||
2283 | /* | ||
2284 | * Test if the bit representing this inode (blkno) is set in the | ||
2285 | * suballocator. | ||
2286 | * | ||
2287 | * On success, 0 is returned and *res is 1 for SET; 0 otherwise. | ||
2288 | * | ||
2289 | * In the event of failure, a negative value is returned and *res is | ||
2290 | * meaningless. | ||
2291 | * | ||
2292 | * Callers must make sure to hold nfs_sync_lock to prevent | ||
2293 | * ocfs2_delete_inode() on another node from accessing the same | ||
2294 | * suballocator concurrently. | ||
2295 | */ | ||
2296 | int ocfs2_test_inode_bit(struct ocfs2_super *osb, u64 blkno, int *res) | ||
2297 | { | ||
2298 | int status; | ||
2299 | u16 suballoc_bit = 0, suballoc_slot = 0; | ||
2300 | struct inode *inode_alloc_inode; | ||
2301 | struct buffer_head *alloc_bh = NULL; | ||
2302 | |||
2303 | mlog_entry("blkno: %llu", blkno); | ||
2304 | |||
2305 | status = ocfs2_get_suballoc_slot_bit(osb, blkno, &suballoc_slot, | ||
2306 | &suballoc_bit); | ||
2307 | if (status < 0) { | ||
2308 | mlog(ML_ERROR, "get alloc slot and bit failed %d\n", status); | ||
2309 | goto bail; | ||
2310 | } | ||
2311 | |||
2312 | inode_alloc_inode = | ||
2313 | ocfs2_get_system_file_inode(osb, INODE_ALLOC_SYSTEM_INODE, | ||
2314 | suballoc_slot); | ||
2315 | if (!inode_alloc_inode) { | ||
2316 | /* the error code could be inaccurate, but we are not able to | ||
2317 | * get the correct one. */ | ||
2318 | status = -EINVAL; | ||
2319 | mlog(ML_ERROR, "unable to get alloc inode in slot %u\n", | ||
2320 | (u32)suballoc_slot); | ||
2321 | goto bail; | ||
2322 | } | ||
2323 | |||
2324 | mutex_lock(&inode_alloc_inode->i_mutex); | ||
2325 | status = ocfs2_inode_lock(inode_alloc_inode, &alloc_bh, 0); | ||
2326 | if (status < 0) { | ||
2327 | mutex_unlock(&inode_alloc_inode->i_mutex); | ||
2328 | mlog(ML_ERROR, "lock on alloc inode on slot %u failed %d\n", | ||
2329 | (u32)suballoc_slot, status); | ||
2330 | goto bail; | ||
2331 | } | ||
2332 | |||
2333 | status = ocfs2_test_suballoc_bit(osb, inode_alloc_inode, alloc_bh, | ||
2334 | blkno, suballoc_bit, res); | ||
2335 | if (status < 0) | ||
2336 | mlog(ML_ERROR, "test suballoc bit failed %d\n", status); | ||
2337 | |||
2338 | ocfs2_inode_unlock(inode_alloc_inode, 0); | ||
2339 | mutex_unlock(&inode_alloc_inode->i_mutex); | ||
2340 | |||
2341 | iput(inode_alloc_inode); | ||
2342 | brelse(alloc_bh); | ||
2343 | bail: | ||
2344 | mlog_exit(status); | ||
2345 | return status; | ||
2346 | } | ||
diff --git a/fs/ocfs2/suballoc.h b/fs/ocfs2/suballoc.h index ea85a4c8b4b1..8c9a78a43164 100644 --- a/fs/ocfs2/suballoc.h +++ b/fs/ocfs2/suballoc.h | |||
@@ -188,4 +188,6 @@ int ocfs2_lock_allocators(struct inode *inode, struct ocfs2_extent_tree *et, | |||
188 | u32 clusters_to_add, u32 extents_to_split, | 188 | u32 clusters_to_add, u32 extents_to_split, |
189 | struct ocfs2_alloc_context **data_ac, | 189 | struct ocfs2_alloc_context **data_ac, |
190 | struct ocfs2_alloc_context **meta_ac); | 190 | struct ocfs2_alloc_context **meta_ac); |
191 | |||
192 | int ocfs2_test_inode_bit(struct ocfs2_super *osb, u64 blkno, int *res); | ||
191 | #endif /* _CHAINALLOC_H_ */ | 193 | #endif /* _CHAINALLOC_H_ */ |