Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

dm snapshot: test chunk size against both origin and snapshot

Validate chunk size against both origin and snapshot sector size

Don't allow chunk size smaller than either origin or snapshot logical
sector size. Reading or writing data not aligned to sector size is not
allowed and causes immediate errors.

This requires us to open the origin before initialising the
exception store and to export dm_snap_origin.

Cc: stable@kernel.org
Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Reviewed-by: Mike Snitzer <snitzer@redhat.com>
Signed-off-by: Alasdair G Kergon <agk@redhat.com>

authored by

Mikulas Patocka and committed by
Alasdair G Kergon
c2411045 1e5554c8

+26 -17
+3 -1
drivers/md/dm-exception-store.c
··· 173 173 174 174 /* Validate the chunk size against the device block size */ 175 175 if (chunk_size % 176 - (bdev_logical_block_size(dm_snap_cow(store->snap)->bdev) >> 9)) { 176 + (bdev_logical_block_size(dm_snap_cow(store->snap)->bdev) >> 9) || 177 + chunk_size % 178 + (bdev_logical_block_size(dm_snap_origin(store->snap)->bdev) >> 9)) { 177 179 *error = "Chunk size is not a multiple of device blocksize"; 178 180 return -EINVAL; 179 181 }
+2 -1
drivers/md/dm-exception-store.h
··· 126 126 }; 127 127 128 128 /* 129 - * Obtain the cow device used by a given snapshot. 129 + * Obtain the origin or cow device used by a given snapshot. 130 130 */ 131 + struct dm_dev *dm_snap_origin(struct dm_snapshot *snap); 131 132 struct dm_dev *dm_snap_cow(struct dm_snapshot *snap); 132 133 133 134 /*
+21 -15
drivers/md/dm-snap.c
··· 148 148 #define RUNNING_MERGE 0 149 149 #define SHUTDOWN_MERGE 1 150 150 151 + struct dm_dev *dm_snap_origin(struct dm_snapshot *s) 152 + { 153 + return s->origin; 154 + } 155 + EXPORT_SYMBOL(dm_snap_origin); 156 + 151 157 struct dm_dev *dm_snap_cow(struct dm_snapshot *s) 152 158 { 153 159 return s->cow; ··· 1071 1065 origin_mode = FMODE_WRITE; 1072 1066 } 1073 1067 1074 - origin_path = argv[0]; 1075 - argv++; 1076 - argc--; 1077 - 1078 1068 s = kmalloc(sizeof(*s), GFP_KERNEL); 1079 1069 if (!s) { 1080 1070 ti->error = "Cannot allocate snapshot context private " 1081 1071 "structure"; 1082 1072 r = -ENOMEM; 1083 1073 goto bad; 1074 + } 1075 + 1076 + origin_path = argv[0]; 1077 + argv++; 1078 + argc--; 1079 + 1080 + r = dm_get_device(ti, origin_path, origin_mode, &s->origin); 1081 + if (r) { 1082 + ti->error = "Cannot get origin device"; 1083 + goto bad_origin; 1084 1084 } 1085 1085 1086 1086 cow_path = argv[0]; ··· 1108 1096 1109 1097 argv += args_used; 1110 1098 argc -= args_used; 1111 - 1112 - r = dm_get_device(ti, origin_path, origin_mode, &s->origin); 1113 - if (r) { 1114 - ti->error = "Cannot get origin device"; 1115 - goto bad_origin; 1116 - } 1117 1099 1118 1100 s->ti = ti; 1119 1101 s->valid = 1; ··· 1218 1212 dm_exception_table_exit(&s->complete, exception_cache); 1219 1213 1220 1214 bad_hash_tables: 1221 - dm_put_device(ti, s->origin); 1222 - 1223 - bad_origin: 1224 1215 dm_exception_store_destroy(s->store); 1225 1216 1226 1217 bad_store: 1227 1218 dm_put_device(ti, s->cow); 1228 1219 1229 1220 bad_cow: 1221 + dm_put_device(ti, s->origin); 1222 + 1223 + bad_origin: 1230 1224 kfree(s); 1231 1225 1232 1226 bad: ··· 1320 1314 1321 1315 mempool_destroy(s->pending_pool); 1322 1316 1323 - dm_put_device(ti, s->origin); 1324 - 1325 1317 dm_exception_store_destroy(s->store); 1326 1318 1327 1319 dm_put_device(ti, s->cow); 1320 + 1321 + dm_put_device(ti, s->origin); 1328 1322 1329 1323 kfree(s); 1330 1324 }