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 7219a86d34c..e15fc7d5082 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 3f8d9986b8e..e1fd5721cd7 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 2f27b332d8b..de3da8eb558 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 4a88bce3507..10e1fa87396 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 e1978acbf65..ea71525aad4 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 b65d19c9756..558bd2709e0 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 eb6f50c9cec..a53ce87481b 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 4c1399cc03f..b4ca5911caa 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 ea85a4c8b4b..8c9a78a4316 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_ */ |
