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

vfs: Create fs_context-aware mount_bdev() replacement

Create a function, get_tree_bdev(), that is fs_context-aware and a
->get_tree() counterpart of mount_bdev().

It caches the block device pointer in the fs_context struct so that this
information can be passed into sget_fc()'s test and set functions.

Signed-off-by: David Howells <dhowells@redhat.com>
cc: Jens Axboe <axboe@kernel.dk>
cc: linux-block@vger.kernel.org
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>

authored by

David Howells and committed by
Al Viro
fe62c3a4 533770cc

+99
+94
fs/super.c
··· 1222 1222 EXPORT_SYMBOL(get_tree_keyed); 1223 1223 1224 1224 #ifdef CONFIG_BLOCK 1225 + 1225 1226 static int set_bdev_super(struct super_block *s, void *data) 1226 1227 { 1227 1228 s->s_bdev = data; ··· 1231 1230 1232 1231 return 0; 1233 1232 } 1233 + 1234 + static int set_bdev_super_fc(struct super_block *s, struct fs_context *fc) 1235 + { 1236 + return set_bdev_super(s, fc->sget_key); 1237 + } 1238 + 1239 + static int test_bdev_super_fc(struct super_block *s, struct fs_context *fc) 1240 + { 1241 + return s->s_bdev == fc->sget_key; 1242 + } 1243 + 1244 + /** 1245 + * get_tree_bdev - Get a superblock based on a single block device 1246 + * @fc: The filesystem context holding the parameters 1247 + * @fill_super: Helper to initialise a new superblock 1248 + */ 1249 + int get_tree_bdev(struct fs_context *fc, 1250 + int (*fill_super)(struct super_block *, 1251 + struct fs_context *)) 1252 + { 1253 + struct block_device *bdev; 1254 + struct super_block *s; 1255 + fmode_t mode = FMODE_READ | FMODE_EXCL; 1256 + int error = 0; 1257 + 1258 + if (!(fc->sb_flags & SB_RDONLY)) 1259 + mode |= FMODE_WRITE; 1260 + 1261 + if (!fc->source) 1262 + return invalf(fc, "No source specified"); 1263 + 1264 + bdev = blkdev_get_by_path(fc->source, mode, fc->fs_type); 1265 + if (IS_ERR(bdev)) { 1266 + errorf(fc, "%s: Can't open blockdev", fc->source); 1267 + return PTR_ERR(bdev); 1268 + } 1269 + 1270 + /* Once the superblock is inserted into the list by sget_fc(), s_umount 1271 + * will protect the lockfs code from trying to start a snapshot while 1272 + * we are mounting 1273 + */ 1274 + mutex_lock(&bdev->bd_fsfreeze_mutex); 1275 + if (bdev->bd_fsfreeze_count > 0) { 1276 + mutex_unlock(&bdev->bd_fsfreeze_mutex); 1277 + warnf(fc, "%pg: Can't mount, blockdev is frozen", bdev); 1278 + return -EBUSY; 1279 + } 1280 + 1281 + fc->sb_flags |= SB_NOSEC; 1282 + fc->sget_key = bdev; 1283 + s = sget_fc(fc, test_bdev_super_fc, set_bdev_super_fc); 1284 + mutex_unlock(&bdev->bd_fsfreeze_mutex); 1285 + if (IS_ERR(s)) 1286 + return PTR_ERR(s); 1287 + 1288 + if (s->s_root) { 1289 + /* Don't summarily change the RO/RW state. */ 1290 + if ((fc->sb_flags ^ s->s_flags) & SB_RDONLY) { 1291 + warnf(fc, "%pg: Can't mount, would change RO state", bdev); 1292 + deactivate_locked_super(s); 1293 + blkdev_put(bdev, mode); 1294 + return -EBUSY; 1295 + } 1296 + 1297 + /* 1298 + * s_umount nests inside bd_mutex during 1299 + * __invalidate_device(). blkdev_put() acquires 1300 + * bd_mutex and can't be called under s_umount. Drop 1301 + * s_umount temporarily. This is safe as we're 1302 + * holding an active reference. 1303 + */ 1304 + up_write(&s->s_umount); 1305 + blkdev_put(bdev, mode); 1306 + down_write(&s->s_umount); 1307 + } else { 1308 + s->s_mode = mode; 1309 + snprintf(s->s_id, sizeof(s->s_id), "%pg", bdev); 1310 + sb_set_blocksize(s, block_size(bdev)); 1311 + error = fill_super(s, fc); 1312 + if (error) { 1313 + deactivate_locked_super(s); 1314 + return error; 1315 + } 1316 + 1317 + s->s_flags |= SB_ACTIVE; 1318 + bdev->bd_super = s; 1319 + } 1320 + 1321 + BUG_ON(fc->root); 1322 + fc->root = dget(s->s_root); 1323 + return 0; 1324 + } 1325 + EXPORT_SYMBOL(get_tree_bdev); 1234 1326 1235 1327 static int test_bdev_super(struct super_block *s, void *data) 1236 1328 {
+5
include/linux/fs_context.h
··· 88 88 struct mutex uapi_mutex; /* Userspace access mutex */ 89 89 struct file_system_type *fs_type; 90 90 void *fs_private; /* The filesystem's context */ 91 + void *sget_key; 91 92 struct dentry *root; /* The root and superblock */ 92 93 struct user_namespace *user_ns; /* The user namespace for this mount */ 93 94 struct net *net_ns; /* The network namespace for this mount */ ··· 159 158 int (*fill_super)(struct super_block *sb, 160 159 struct fs_context *fc), 161 160 void *key); 161 + 162 + extern int get_tree_bdev(struct fs_context *fc, 163 + int (*fill_super)(struct super_block *sb, 164 + struct fs_context *fc)); 162 165 163 166 extern const struct file_operations fscontext_fops; 164 167